]> granicus.if.org Git - clang/commitdiff
When emitting a static local variable in C++, handle
authorJohn McCall <rjmccall@apple.com>
Fri, 30 Mar 2012 04:25:14 +0000 (04:25 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 30 Mar 2012 04:25:14 +0000 (04:25 +0000)
the case that the variable already exists.  Partly this is just
protection against people making crazy declarations with custom
asm labels or extern "C" names that intentionally collide with
the manglings of such variables, but the main reason is that we
can actually emit a static local variable twice with the
requirement that it match up.  There may be other cases with
(e.g.) the various nested functions, but the main exemplar is
with constructor variants, where we can be forced into
double-emitting the function body under certain circumstances
like (currently) the presence of virtual bases.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153723 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGDecl.cpp
lib/CodeGen/ItaniumCXXABI.cpp
test/CodeGenCXX/static-init.cpp

index 970f0b2389f210a6763ff04c37ae5e65d303b9e0..d6d66968948083c65cfac5764f40029b69d34fe7 100644 (file)
@@ -184,6 +184,24 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
     Name = GetStaticDeclName(*this, D, Separator);
 
   llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
+
+  // In C++, there are strange possibilities here involving the
+  // double-emission of constructors and destructors.
+  if (CGM.getLangOpts().CPlusPlus) {
+    llvm::GlobalValue *value = CGM.getModule().getNamedValue(Name);
+    if (value && isa<llvm::GlobalVariable>(value) &&
+        value->getType() ==
+          LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(Ty)))
+      return cast<llvm::GlobalVariable>(value);
+
+    if (value) {
+      CGM.Error(D.getLocation(),
+              "problem emitting static variable: already present as "
+              "different kind of symbol");
+      // Fall through and implicitly give it a uniqued name.
+    }
+  }
+    
   llvm::GlobalVariable *GV =
     new llvm::GlobalVariable(CGM.getModule(), LTy,
                              Ty.isConstant(getContext()), Linkage,
index 6fcf83d5ace19b8aba990b46eb3b7c58842ec179..8cce8c90a07186745cf203e9c76e24c18fa31dcb 100644 (file)
@@ -1051,7 +1051,7 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
 namespace {
   struct CallGuardAbort : EHScopeStack::Cleanup {
     llvm::GlobalVariable *Guard;
-    CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
+    CallGuardAbort(llvm::GlobalVariable *guard) : Guard(guard) {}
 
     void Emit(CodeGenFunction &CGF, Flags flags) {
       CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
@@ -1073,35 +1073,54 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
   bool threadsafe =
     (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl());
 
-  llvm::IntegerType *GuardTy;
+  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();
   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();
+  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());
+  SmallString<256> guardName;
+  {
+    llvm::raw_svector_ostream out(guardName);
+    getMangleContext().mangleItaniumGuardVariable(&D, out);
+    out.flush();
+  }
 
+  // There are strange possibilities here involving the
+  // double-emission of constructors and destructors.
+  llvm::GlobalVariable *guard = nullptr;
+  if (llvm::GlobalValue *existingGuard 
+        = CGM.getModule().getNamedValue(guardName.str())) {
+    if (isa<llvm::GlobalVariable>(existingGuard) &&
+        existingGuard->getType() == guardPtrTy) {
+      guard = cast<llvm::GlobalVariable>(existingGuard); // okay
+    } else {
+      CGM.Error(D.getLocation(),
+              "problem emitting guard for static variable: "
+              "already present as different kind of symbol");
+      // Fall through and implicitly give it a uniqued name.
+    }
+  }
+
+  if (!guard) {
+    // Just absorb linkage and visibility from the variable.
+    guard = new llvm::GlobalVariable(CGM.getModule(), guardTy,
+                                     false, GV->getLinkage(),
+                                     llvm::ConstantInt::get(guardTy, 0),
+                                     guardName.str());
+    guard->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 +1134,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,10 +1154,9 @@ 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));
-    LI->setAlignment(1);
+    llvm::LoadInst *load = 
+      Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy));
+    load->setAlignment(1);
 
     // Itanium ABI:
     //   An implementation supporting thread-safety on multiprocessor
@@ -1147,16 +1165,16 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
     //
     // In LLVM, we do this by marking the load Acquire.
     if (threadsafe)
-      LI->setAtomic(llvm::Acquire);
+      load->setAtomic(llvm::Acquire);
 
-    IsInitialized = Builder.CreateIsNull(LI, "guard.uninitialized");
+    isInitialized = Builder.CreateIsNull(load, "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 +1182,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,7 +1190,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
                          InitBlock, EndBlock);
   
     // Call __cxa_guard_abort along the exceptional edge.
-    CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, GuardVariable);
+    CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, guard);
     
     CGF.EmitBlock(InitBlock);
   }
@@ -1185,9 +1203,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
     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);
index a96cb7ac8e02a5664f33486b640a7dc4a014fb7a..ca47428fe2c6f2f389ee375ac91bfa718b634f0f 100644 (file)
@@ -79,3 +79,53 @@ 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)
+}