forked from OSchip/llvm-project
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. llvm-svn: 153776
This commit is contained in:
parent
191a6a86ad
commit
b88a566cc1
|
@ -273,11 +273,23 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
|
||||||
llvm::Value *&DMEntry = LocalDeclMap[&D];
|
llvm::Value *&DMEntry = LocalDeclMap[&D];
|
||||||
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
|
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<llvm::GlobalVariable>(addr->stripPointerCasts());
|
||||||
|
} else {
|
||||||
|
addr = var = CreateStaticVarDecl(D, ".", Linkage);
|
||||||
|
}
|
||||||
|
|
||||||
// Store into LocalDeclMap before generating initializer to handle
|
// Store into LocalDeclMap before generating initializer to handle
|
||||||
// circular references.
|
// 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,
|
// 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.
|
// even though that doesn't really make any sense.
|
||||||
|
@ -285,42 +297,38 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
|
||||||
if (D.getType()->isVariablyModifiedType())
|
if (D.getType()->isVariablyModifiedType())
|
||||||
EmitVariablyModifiedType(D.getType());
|
EmitVariablyModifiedType(D.getType());
|
||||||
|
|
||||||
// Local static block variables must be treated as globals as they may be
|
// Save the type in case adding the initializer forces a type change.
|
||||||
// referenced in their RHS initializer block-literal expresion.
|
llvm::Type *expectedType = addr->getType();
|
||||||
CGM.setStaticLocalDeclAddress(&D, GV);
|
|
||||||
|
|
||||||
// If this value has an initializer, emit it.
|
// If this value has an initializer, emit it.
|
||||||
if (D.getInit())
|
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<AnnotateAttr>())
|
if (D.hasAttr<AnnotateAttr>())
|
||||||
CGM.AddGlobalAnnotations(&D, GV);
|
CGM.AddGlobalAnnotations(&D, var);
|
||||||
|
|
||||||
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
|
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
|
||||||
GV->setSection(SA->getName());
|
var->setSection(SA->getName());
|
||||||
|
|
||||||
if (D.hasAttr<UsedAttr>())
|
if (D.hasAttr<UsedAttr>())
|
||||||
CGM.AddUsedGlobal(GV);
|
CGM.AddUsedGlobal(var);
|
||||||
|
|
||||||
// We may have to cast the constant because of the initializer
|
// We may have to cast the constant because of the initializer
|
||||||
// mismatch above.
|
// mismatch above.
|
||||||
//
|
//
|
||||||
// FIXME: It is really dangerous to store this in the map; if anyone
|
// FIXME: It is really dangerous to store this in the map; if anyone
|
||||||
// RAUW's the GV uses of this constant will be invalid.
|
// RAUW's the GV uses of this constant will be invalid.
|
||||||
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType());
|
llvm::Constant *castedAddr = llvm::ConstantExpr::getBitCast(var, expectedType);
|
||||||
llvm::Type *LPtrTy =
|
DMEntry = castedAddr;
|
||||||
LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType()));
|
CGM.setStaticLocalDeclAddress(&D, castedAddr);
|
||||||
llvm::Constant *CastedVal = llvm::ConstantExpr::getBitCast(GV, LPtrTy);
|
|
||||||
DMEntry = CastedVal;
|
|
||||||
CGM.setStaticLocalDeclAddress(&D, CastedVal);
|
|
||||||
|
|
||||||
// Emit global variable debug descriptor for static vars.
|
// Emit global variable debug descriptor for static vars.
|
||||||
CGDebugInfo *DI = getDebugInfo();
|
CGDebugInfo *DI = getDebugInfo();
|
||||||
if (DI) {
|
if (DI) {
|
||||||
DI->setLocation(D.getLocation());
|
DI->setLocation(D.getLocation());
|
||||||
DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(GV), &D);
|
DI->EmitGlobalVariable(var, &D);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -280,6 +280,7 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||||
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
|
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
|
||||||
llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;
|
llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;
|
||||||
llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
|
llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
|
||||||
|
llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;
|
||||||
|
|
||||||
llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;
|
llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;
|
||||||
llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;
|
llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;
|
||||||
|
@ -405,6 +406,14 @@ public:
|
||||||
StaticLocalDeclMap[D] = C;
|
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) {
|
llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) {
|
||||||
return AtomicSetterHelperFnMap[Ty];
|
return AtomicSetterHelperFnMap[Ty];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1064,8 +1064,8 @@ namespace {
|
||||||
/// just special-case it at particular places.
|
/// just special-case it at particular places.
|
||||||
void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
const VarDecl &D,
|
const VarDecl &D,
|
||||||
llvm::GlobalVariable *GV,
|
llvm::GlobalVariable *var,
|
||||||
bool PerformInit) {
|
bool shouldPerformInit) {
|
||||||
CGBuilderTy &Builder = CGF.Builder;
|
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 variables;
|
||||||
|
@ -1073,35 +1073,44 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
bool threadsafe =
|
bool threadsafe =
|
||||||
(getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl());
|
(getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl());
|
||||||
|
|
||||||
llvm::IntegerType *GuardTy;
|
|
||||||
|
|
||||||
// If we have a global variable with internal linkage and thread-safe statics
|
// 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.
|
// 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) {
|
if (useInt8GuardVariable) {
|
||||||
GuardTy = CGF.Int8Ty;
|
guardTy = CGF.Int8Ty;
|
||||||
} else {
|
} else {
|
||||||
// Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
|
// 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.
|
// Create the guard variable if we don't already have it (as we
|
||||||
SmallString<256> GuardVName;
|
// might if we're double-emitting this function body).
|
||||||
llvm::raw_svector_ostream Out(GuardVName);
|
llvm::GlobalVariable *guard = CGM.getStaticLocalDeclGuardAddress(&D);
|
||||||
getMangleContext().mangleItaniumGuardVariable(&D, Out);
|
if (!guard) {
|
||||||
Out.flush();
|
// Mangle the name for the guard.
|
||||||
|
SmallString<256> guardName;
|
||||||
|
{
|
||||||
|
llvm::raw_svector_ostream out(guardName);
|
||||||
|
getMangleContext().mangleItaniumGuardVariable(&D, out);
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
// Just absorb linkage and visibility from the variable.
|
// Create the guard variable with a zero-initializer.
|
||||||
llvm::GlobalVariable *GuardVariable =
|
// Just absorb linkage and visibility from the guarded variable.
|
||||||
new llvm::GlobalVariable(CGM.getModule(), GuardTy,
|
guard = new llvm::GlobalVariable(CGM.getModule(), guardTy,
|
||||||
false, GV->getLinkage(),
|
false, var->getLinkage(),
|
||||||
llvm::ConstantInt::get(GuardTy, 0),
|
llvm::ConstantInt::get(guardTy, 0),
|
||||||
GuardVName.str());
|
guardName.str());
|
||||||
GuardVariable->setVisibility(GV->getVisibility());
|
guard->setVisibility(var->getVisibility());
|
||||||
|
|
||||||
|
CGM.setStaticLocalDeclGuardAddress(&D, guard);
|
||||||
|
}
|
||||||
|
|
||||||
// Test whether the variable has completed initialization.
|
// Test whether the variable has completed initialization.
|
||||||
llvm::Value *IsInitialized;
|
llvm::Value *isInitialized;
|
||||||
|
|
||||||
// ARM C++ ABI 3.2.3.1:
|
// ARM C++ ABI 3.2.3.1:
|
||||||
// To support the potential use of initialization guard variables
|
// To support the potential use of initialization guard variables
|
||||||
|
@ -1115,9 +1124,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
if (IsARM && !useInt8GuardVariable) {
|
if (IsARM && !useInt8GuardVariable) {
|
||||||
llvm::Value *V = Builder.CreateLoad(GuardVariable);
|
llvm::Value *V = Builder.CreateLoad(guard);
|
||||||
V = Builder.CreateAnd(V, Builder.getInt32(1));
|
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:
|
// Itanium C++ ABI 3.3.2:
|
||||||
// The following is pseudo-code showing how these functions can be used:
|
// The following is pseudo-code showing how these functions can be used:
|
||||||
|
@ -1135,9 +1144,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
// }
|
// }
|
||||||
} else {
|
} else {
|
||||||
// Load the first byte of the guard variable.
|
// Load the first byte of the guard variable.
|
||||||
llvm::Type *PtrTy = Builder.getInt8PtrTy();
|
|
||||||
llvm::LoadInst *LI =
|
llvm::LoadInst *LI =
|
||||||
Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy));
|
Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy));
|
||||||
LI->setAlignment(1);
|
LI->setAlignment(1);
|
||||||
|
|
||||||
// Itanium ABI:
|
// Itanium ABI:
|
||||||
|
@ -1149,14 +1157,14 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
if (threadsafe)
|
if (threadsafe)
|
||||||
LI->setAtomic(llvm::Acquire);
|
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 *InitCheckBlock = CGF.createBasicBlock("init.check");
|
||||||
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
|
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
|
||||||
|
|
||||||
// Check if the first byte of the guard variable is zero.
|
// Check if the first byte of the guard variable is zero.
|
||||||
Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock);
|
Builder.CreateCondBr(isInitialized, InitCheckBlock, EndBlock);
|
||||||
|
|
||||||
CGF.EmitBlock(InitCheckBlock);
|
CGF.EmitBlock(InitCheckBlock);
|
||||||
|
|
||||||
|
@ -1164,7 +1172,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
if (threadsafe) {
|
if (threadsafe) {
|
||||||
// Call __cxa_guard_acquire.
|
// Call __cxa_guard_acquire.
|
||||||
llvm::Value *V
|
llvm::Value *V
|
||||||
= Builder.CreateCall(getGuardAcquireFn(CGM, GuardPtrTy), GuardVariable);
|
= Builder.CreateCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
|
||||||
|
|
||||||
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
|
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
|
||||||
|
|
||||||
|
@ -1172,22 +1180,22 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
InitBlock, EndBlock);
|
InitBlock, EndBlock);
|
||||||
|
|
||||||
// Call __cxa_guard_abort along the exceptional edge.
|
// Call __cxa_guard_abort along the exceptional edge.
|
||||||
CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, GuardVariable);
|
CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, guard);
|
||||||
|
|
||||||
CGF.EmitBlock(InitBlock);
|
CGF.EmitBlock(InitBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the initializer and add a global destructor if appropriate.
|
// Emit the initializer and add a global destructor if appropriate.
|
||||||
CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
|
CGF.EmitCXXGlobalVarDeclInit(D, var, shouldPerformInit);
|
||||||
|
|
||||||
if (threadsafe) {
|
if (threadsafe) {
|
||||||
// Pop the guard-abort cleanup if we pushed one.
|
// Pop the guard-abort cleanup if we pushed one.
|
||||||
CGF.PopCleanupBlock();
|
CGF.PopCleanupBlock();
|
||||||
|
|
||||||
// Call __cxa_guard_release. This cannot throw.
|
// Call __cxa_guard_release. This cannot throw.
|
||||||
Builder.CreateCall(getGuardReleaseFn(CGM, GuardPtrTy), GuardVariable);
|
Builder.CreateCall(getGuardReleaseFn(CGM, guardPtrTy), guard);
|
||||||
} else {
|
} else {
|
||||||
Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable);
|
Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guard);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGF.EmitBlock(EndBlock);
|
CGF.EmitBlock(EndBlock);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// CHECK: @_ZZ1hvE1i = internal global i32 0, align 4
|
// CHECK: @_ZZ1hvE1i = internal global i32 0, align 4
|
||||||
// CHECK: @base_req = global [4 x i8] c"foo\00", align 1
|
// 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: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16
|
||||||
// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0
|
// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0
|
||||||
// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0
|
// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0
|
||||||
|
@ -79,3 +80,73 @@ namespace union_static_local {
|
||||||
c::main();
|
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(
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue