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)
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
// ...
// }
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:
// }
} 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
//
// 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);
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");
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);
}
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);
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)
+}