forked from OSchip/llvm-project
Revert r153723, and its follow-ups r153728 and r153733.
These patches cause us to miscompile and/or reject code with static function-local variables in an extern-C context. Previously, we were papering over this as long as the variables are within the same translation unit, and had not seen any failures in the wild. We still need a proper fix, which involves mangling static locals inside of an extern-C block (as GCC already does), but this patch causes pretty widespread regressions. Firefox, and many other applications no longer build. Lots of test cases have been posted to the list in response to this commit, so there should be no problem reproducing the issues. llvm-svn: 153768
This commit is contained in:
parent
daa04130ed
commit
8453795255
|
@ -172,7 +172,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
|
||||||
|
|
||||||
void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
const VarDecl &D,
|
const VarDecl &D,
|
||||||
llvm::Constant *GV,
|
llvm::GlobalVariable *GV,
|
||||||
bool PerformInit) {
|
bool PerformInit) {
|
||||||
ErrorUnsupportedABI(CGF, "static local variable initialization");
|
ErrorUnsupportedABI(CGF, "static local variable initialization");
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,9 +246,8 @@ public:
|
||||||
/// The variable may be:
|
/// The variable may be:
|
||||||
/// - a static local variable
|
/// - a static local variable
|
||||||
/// - a static data member of a class template instantiation
|
/// - a static data member of a class template instantiation
|
||||||
/// In either case, it will be a (possibly casted) llvm::GlobalVariable.
|
|
||||||
virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
|
virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
|
||||||
llvm::Constant *addr, bool PerformInit);
|
llvm::GlobalVariable *DeclPtr, bool PerformInit);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -169,24 +169,7 @@ static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
|
||||||
return ContextName + Separator + D.getNameAsString();
|
return ContextName + Separator + D.getNameAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We wanted to make a variable of one type, but the variable already
|
llvm::GlobalVariable *
|
||||||
/// exists with another. Is that type good enough?
|
|
||||||
///
|
|
||||||
/// The problem we're working around here is that giving a global
|
|
||||||
/// variable an initializer can require changing its type in some
|
|
||||||
/// convoluted circumstances.
|
|
||||||
static bool isExistingVarAdequate(CodeGenModule &CGM,
|
|
||||||
llvm::Type *existing, llvm::Type *desired) {
|
|
||||||
// Equality makes for a good fast path.
|
|
||||||
if (existing == desired) return true;
|
|
||||||
|
|
||||||
// Otherwise, just require them to have the same size.
|
|
||||||
return (CGM.getTargetData().getTypeStoreSize(existing)
|
|
||||||
== CGM.getTargetData().getTypeStoreSize(desired));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
llvm::Constant *
|
|
||||||
CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
|
CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
|
||||||
const char *Separator,
|
const char *Separator,
|
||||||
llvm::GlobalValue::LinkageTypes Linkage) {
|
llvm::GlobalValue::LinkageTypes Linkage) {
|
||||||
|
@ -201,37 +184,12 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
|
||||||
Name = GetStaticDeclName(*this, D, Separator);
|
Name = GetStaticDeclName(*this, D, Separator);
|
||||||
|
|
||||||
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
|
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
|
||||||
unsigned addrspace = CGM.getContext().getTargetAddressSpace(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)) {
|
|
||||||
// Check that the type is compatible with the type we want. The
|
|
||||||
// simple equality check isn't good enough because initializers
|
|
||||||
// can force the changing of a type (e.g. with unions).
|
|
||||||
if (value->getType()->getAddressSpace() == addrspace &&
|
|
||||||
isExistingVarAdequate(CGM, value->getType()->getElementType(), LTy))
|
|
||||||
return llvm::ConstantExpr::getBitCast(value,
|
|
||||||
LTy->getPointerTo(addrspace));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
CGM.Error(D.getLocation(),
|
|
||||||
"problem emitting static variable '" + Name +
|
|
||||||
"': already present as different kind of symbol");
|
|
||||||
|
|
||||||
// Fall through and implicitly give it a uniqued name.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::GlobalVariable *GV =
|
llvm::GlobalVariable *GV =
|
||||||
new llvm::GlobalVariable(CGM.getModule(), LTy,
|
new llvm::GlobalVariable(CGM.getModule(), LTy,
|
||||||
Ty.isConstant(getContext()), Linkage,
|
Ty.isConstant(getContext()), Linkage,
|
||||||
CGM.EmitNullConstant(D.getType()), Name, 0,
|
CGM.EmitNullConstant(D.getType()), Name, 0,
|
||||||
D.isThreadSpecified(),
|
D.isThreadSpecified(),
|
||||||
addrspace);
|
CGM.getContext().getTargetAddressSpace(Ty));
|
||||||
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
|
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
|
||||||
if (Linkage != llvm::GlobalValue::InternalLinkage)
|
if (Linkage != llvm::GlobalValue::InternalLinkage)
|
||||||
GV->setVisibility(CurFn->getVisibility());
|
GV->setVisibility(CurFn->getVisibility());
|
||||||
|
@ -246,85 +204,80 @@ static bool hasNontrivialDestruction(QualType T) {
|
||||||
return RD && !RD->hasTrivialDestructor();
|
return RD && !RD->hasTrivialDestructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to
|
/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
|
||||||
/// the global variable that has already been created for it. If
|
/// global variable that has already been created for it. If the initializer
|
||||||
/// the initializer has a different type than GV does, this may
|
/// has a different type than GV does, this may free GV and return a different
|
||||||
/// force the underlying variable to change. Otherwise it just
|
/// one. Otherwise it just returns GV.
|
||||||
/// returns it.
|
llvm::GlobalVariable *
|
||||||
///
|
|
||||||
/// The argument must be a (potentially casted) global variable,
|
|
||||||
/// and the result will be one, too.
|
|
||||||
llvm::Constant *
|
|
||||||
CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
|
CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
|
||||||
llvm::Constant *addr) {
|
llvm::GlobalVariable *GV) {
|
||||||
llvm::Constant *init = CGM.EmitConstantInit(D, this);
|
llvm::Constant *Init = CGM.EmitConstantInit(D, this);
|
||||||
|
|
||||||
llvm::GlobalVariable *var =
|
|
||||||
cast<llvm::GlobalVariable>(addr->stripPointerCasts());
|
|
||||||
|
|
||||||
// If constant emission failed, then this should be a C++ static
|
// If constant emission failed, then this should be a C++ static
|
||||||
// initializer.
|
// initializer.
|
||||||
if (!init) {
|
if (!Init) {
|
||||||
if (!getContext().getLangOpts().CPlusPlus)
|
if (!getContext().getLangOpts().CPlusPlus)
|
||||||
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
|
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
|
||||||
else if (Builder.GetInsertBlock()) {
|
else if (Builder.GetInsertBlock()) {
|
||||||
// Since we have a static initializer, this global variable can't
|
// Since we have a static initializer, this global variable can't
|
||||||
// be constant.
|
// be constant.
|
||||||
var->setConstant(false);
|
GV->setConstant(false);
|
||||||
|
|
||||||
EmitCXXGuardedInit(D, addr, /*PerformInit*/true);
|
EmitCXXGuardedInit(D, GV, /*PerformInit*/true);
|
||||||
}
|
}
|
||||||
return addr;
|
return GV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The initializer may differ in type from the global. Rewrite
|
// The initializer may differ in type from the global. Rewrite
|
||||||
// the global to match the initializer. (We have to do this
|
// the global to match the initializer. (We have to do this
|
||||||
// because some types, like unions, can't be completely represented
|
// because some types, like unions, can't be completely represented
|
||||||
// in the LLVM type system.)
|
// in the LLVM type system.)
|
||||||
if (var->getType()->getElementType() != init->getType()) {
|
if (GV->getType()->getElementType() != Init->getType()) {
|
||||||
llvm::GlobalVariable *newVar
|
llvm::GlobalVariable *OldGV = GV;
|
||||||
= new llvm::GlobalVariable(CGM.getModule(), init->getType(),
|
|
||||||
var->isConstant(),
|
GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
|
||||||
var->getLinkage(), init, "",
|
OldGV->isConstant(),
|
||||||
/*InsertBefore*/ var,
|
OldGV->getLinkage(), Init, "",
|
||||||
D.isThreadSpecified(),
|
/*InsertBefore*/ OldGV,
|
||||||
var->getType()->getAddressSpace());
|
D.isThreadSpecified(),
|
||||||
newVar->setVisibility(var->getVisibility());
|
CGM.getContext().getTargetAddressSpace(D.getType()));
|
||||||
|
GV->setVisibility(OldGV->getVisibility());
|
||||||
|
|
||||||
// Steal the name of the old global
|
// Steal the name of the old global
|
||||||
newVar->takeName(var);
|
GV->takeName(OldGV);
|
||||||
|
|
||||||
// Replace all uses of the old global with the new global
|
// Replace all uses of the old global with the new global
|
||||||
addr = llvm::ConstantExpr::getBitCast(newVar, addr->getType());
|
llvm::Constant *NewPtrForOldDecl =
|
||||||
var->replaceAllUsesWith(addr);
|
llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
|
||||||
|
OldGV->replaceAllUsesWith(NewPtrForOldDecl);
|
||||||
|
|
||||||
// Erase the old global, since it is no longer used.
|
// Erase the old global, since it is no longer used.
|
||||||
var->eraseFromParent();
|
OldGV->eraseFromParent();
|
||||||
var = newVar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var->setConstant(CGM.isTypeConstant(D.getType(), true));
|
GV->setConstant(CGM.isTypeConstant(D.getType(), true));
|
||||||
var->setInitializer(init);
|
GV->setInitializer(Init);
|
||||||
|
|
||||||
if (hasNontrivialDestruction(D.getType())) {
|
if (hasNontrivialDestruction(D.getType())) {
|
||||||
// We have a constant initializer, but a nontrivial destructor. We still
|
// We have a constant initializer, but a nontrivial destructor. We still
|
||||||
// need to perform a guarded "initialization" in order to register the
|
// need to perform a guarded "initialization" in order to register the
|
||||||
// destructor.
|
// destructor.
|
||||||
EmitCXXGuardedInit(D, addr, /*PerformInit*/false);
|
EmitCXXGuardedInit(D, GV, /*PerformInit*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr;
|
return GV;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
|
void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
|
||||||
llvm::GlobalValue::LinkageTypes Linkage) {
|
llvm::GlobalValue::LinkageTypes Linkage) {
|
||||||
|
llvm::Value *&DMEntry = LocalDeclMap[&D];
|
||||||
|
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
|
||||||
|
|
||||||
llvm::Constant *addr = CreateStaticVarDecl(D, ".", Linkage);
|
llvm::GlobalVariable *GV = CreateStaticVarDecl(D, ".", Linkage);
|
||||||
|
|
||||||
// Store into LocalDeclMap before generating initializer to handle
|
// Store into LocalDeclMap before generating initializer to handle
|
||||||
// circular references.
|
// circular references.
|
||||||
assert(!LocalDeclMap.count(&D) && "Decl already exists in localdeclmap!");
|
DMEntry = GV;
|
||||||
LocalDeclMap[&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.
|
||||||
|
@ -334,34 +287,40 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
|
||||||
|
|
||||||
// Local static block variables must be treated as globals as they may be
|
// Local static block variables must be treated as globals as they may be
|
||||||
// referenced in their RHS initializer block-literal expresion.
|
// referenced in their RHS initializer block-literal expresion.
|
||||||
CGM.setStaticLocalDeclAddress(&D, addr);
|
CGM.setStaticLocalDeclAddress(&D, GV);
|
||||||
|
|
||||||
// If this value has an initializer, emit it.
|
// If this value has an initializer, emit it.
|
||||||
// This can leave us with a casted pointer.
|
|
||||||
if (D.getInit())
|
if (D.getInit())
|
||||||
addr = AddInitializerToStaticVarDecl(D, addr);
|
GV = AddInitializerToStaticVarDecl(D, GV);
|
||||||
|
|
||||||
llvm::GlobalVariable *var =
|
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
|
||||||
cast<llvm::GlobalVariable>(addr->stripPointerCasts());
|
|
||||||
var->setAlignment(getContext().getDeclAlign(&D).getQuantity());
|
|
||||||
|
|
||||||
if (D.hasAttr<AnnotateAttr>())
|
if (D.hasAttr<AnnotateAttr>())
|
||||||
CGM.AddGlobalAnnotations(&D, var);
|
CGM.AddGlobalAnnotations(&D, GV);
|
||||||
|
|
||||||
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
|
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
|
||||||
var->setSection(SA->getName());
|
GV->setSection(SA->getName());
|
||||||
|
|
||||||
if (D.hasAttr<UsedAttr>())
|
if (D.hasAttr<UsedAttr>())
|
||||||
CGM.AddUsedGlobal(var);
|
CGM.AddUsedGlobal(GV);
|
||||||
|
|
||||||
LocalDeclMap[&D] = addr;
|
// We may have to cast the constant because of the initializer
|
||||||
CGM.setStaticLocalDeclAddress(&D, addr);
|
// 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);
|
||||||
|
|
||||||
// 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(var, &D);
|
DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(GV), &D);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
|
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
|
||||||
llvm::Constant *addr,
|
llvm::GlobalVariable *DeclPtr,
|
||||||
bool PerformInit) {
|
bool PerformInit) {
|
||||||
// If we've been asked to forbid guard variables, emit an error now.
|
// If we've been asked to forbid guard variables, emit an error now.
|
||||||
// This diagnostic is hard-coded for Darwin's use case; we can find
|
// This diagnostic is hard-coded for Darwin's use case; we can find
|
||||||
|
@ -189,7 +189,7 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
|
||||||
"this initialization requires a guard variable, which "
|
"this initialization requires a guard variable, which "
|
||||||
"the kernel does not support");
|
"the kernel does not support");
|
||||||
|
|
||||||
CGM.getCXXABI().EmitGuardedInit(*this, D, addr, PerformInit);
|
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::Function *
|
static llvm::Function *
|
||||||
|
|
|
@ -2392,17 +2392,17 @@ public:
|
||||||
|
|
||||||
/// CreateStaticVarDecl - Create a zero-initialized LLVM global for
|
/// CreateStaticVarDecl - Create a zero-initialized LLVM global for
|
||||||
/// a static local variable.
|
/// a static local variable.
|
||||||
llvm::Constant *CreateStaticVarDecl(const VarDecl &D,
|
llvm::GlobalVariable *CreateStaticVarDecl(const VarDecl &D,
|
||||||
const char *Separator,
|
const char *Separator,
|
||||||
llvm::GlobalValue::LinkageTypes Linkage);
|
llvm::GlobalValue::LinkageTypes Linkage);
|
||||||
|
|
||||||
/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to
|
/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
|
||||||
/// the global variable that has already been created for it. If
|
/// global variable that has already been created for it. If the initializer
|
||||||
/// the initializer has a different type than GV does, this may
|
/// has a different type than GV does, this may free GV and return a different
|
||||||
/// force the underlying variable to change. Otherwise it just
|
/// one. Otherwise it just returns GV.
|
||||||
/// returns it.
|
llvm::GlobalVariable *
|
||||||
llvm::Constant *
|
AddInitializerToStaticVarDecl(const VarDecl &D,
|
||||||
AddInitializerToStaticVarDecl(const VarDecl &D, llvm::Constant *GV);
|
llvm::GlobalVariable *GV);
|
||||||
|
|
||||||
|
|
||||||
/// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
|
/// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
|
||||||
|
@ -2420,7 +2420,7 @@ public:
|
||||||
/// possible to prove that an initialization will be done exactly
|
/// possible to prove that an initialization will be done exactly
|
||||||
/// once, e.g. with a static local variable or a static data member
|
/// once, e.g. with a static local variable or a static data member
|
||||||
/// of a class template.
|
/// of a class template.
|
||||||
void EmitCXXGuardedInit(const VarDecl &D, llvm::Constant *addr,
|
void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr,
|
||||||
bool PerformInit);
|
bool PerformInit);
|
||||||
|
|
||||||
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
|
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
|
||||||
|
|
|
@ -197,9 +197,8 @@ bool CodeGenModule::isTargetDarwin() const {
|
||||||
return getContext().getTargetInfo().getTriple().isOSDarwin();
|
return getContext().getTargetInfo().getTriple().isOSDarwin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenModule::Error(SourceLocation loc, const Twine &error) {
|
void CodeGenModule::Error(SourceLocation loc, StringRef error) {
|
||||||
unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
|
unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, error);
|
||||||
error.str());
|
|
||||||
getDiags().Report(Context.getFullLoc(loc), diagID);
|
getDiags().Report(Context.getFullLoc(loc), diagID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -733,7 +733,7 @@ public:
|
||||||
llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record);
|
llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record);
|
||||||
|
|
||||||
/// Error - Emit a general error that something can't be done.
|
/// Error - Emit a general error that something can't be done.
|
||||||
void Error(SourceLocation loc, const Twine &error);
|
void Error(SourceLocation loc, StringRef error);
|
||||||
|
|
||||||
/// ErrorUnsupported - Print out an error that codegen doesn't support the
|
/// ErrorUnsupported - Print out an error that codegen doesn't support the
|
||||||
/// specified stmt yet.
|
/// specified stmt yet.
|
||||||
|
|
|
@ -123,7 +123,7 @@ public:
|
||||||
llvm::Value *&AllocPtr, CharUnits &CookieSize);
|
llvm::Value *&AllocPtr, CharUnits &CookieSize);
|
||||||
|
|
||||||
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
|
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
|
||||||
llvm::Constant *addr, bool PerformInit);
|
llvm::GlobalVariable *DeclPtr, bool PerformInit);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ARMCXXABI : public ItaniumCXXABI {
|
class ARMCXXABI : public ItaniumCXXABI {
|
||||||
|
@ -1051,7 +1051,7 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
|
||||||
namespace {
|
namespace {
|
||||||
struct CallGuardAbort : EHScopeStack::Cleanup {
|
struct CallGuardAbort : EHScopeStack::Cleanup {
|
||||||
llvm::GlobalVariable *Guard;
|
llvm::GlobalVariable *Guard;
|
||||||
CallGuardAbort(llvm::GlobalVariable *guard) : Guard(guard) {}
|
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
|
||||||
|
|
||||||
void Emit(CodeGenFunction &CGF, Flags flags) {
|
void Emit(CodeGenFunction &CGF, Flags flags) {
|
||||||
CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
|
CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
|
||||||
|
@ -1064,7 +1064,7 @@ 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::Constant *varAddr,
|
llvm::GlobalVariable *GV,
|
||||||
bool PerformInit) {
|
bool PerformInit) {
|
||||||
CGBuilderTy &Builder = CGF.Builder;
|
CGBuilderTy &Builder = CGF.Builder;
|
||||||
|
|
||||||
|
@ -1073,60 +1073,35 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
bool threadsafe =
|
bool threadsafe =
|
||||||
(getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl());
|
(getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl());
|
||||||
|
|
||||||
llvm::IntegerType *guardTy;
|
llvm::IntegerType *GuardTy;
|
||||||
|
|
||||||
// Find the underlying global variable for linkage purposes.
|
|
||||||
// This may not have the right type for actual evaluation purposes.
|
|
||||||
llvm::GlobalVariable *var =
|
|
||||||
cast<llvm::GlobalVariable>(varAddr->stripPointerCasts());
|
|
||||||
|
|
||||||
// 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 && var->hasInternalLinkage();
|
bool useInt8GuardVariable = !threadsafe && GV->hasInternalLinkage();
|
||||||
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.
|
||||||
SmallString<256> guardName;
|
SmallString<256> GuardVName;
|
||||||
{
|
llvm::raw_svector_ostream Out(GuardVName);
|
||||||
llvm::raw_svector_ostream out(guardName);
|
getMangleContext().mangleItaniumGuardVariable(&D, Out);
|
||||||
getMangleContext().mangleItaniumGuardVariable(&D, out);
|
Out.flush();
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are strange possibilities here involving the
|
// Just absorb linkage and visibility from the variable.
|
||||||
// double-emission of constructors and destructors.
|
llvm::GlobalVariable *GuardVariable =
|
||||||
llvm::GlobalVariable *guard = 0;
|
new llvm::GlobalVariable(CGM.getModule(), GuardTy,
|
||||||
if (llvm::GlobalValue *existingGuard
|
false, GV->getLinkage(),
|
||||||
= CGM.getModule().getNamedValue(guardName.str())) {
|
llvm::ConstantInt::get(GuardTy, 0),
|
||||||
if (isa<llvm::GlobalVariable>(existingGuard) &&
|
GuardVName.str());
|
||||||
existingGuard->getType() == guardPtrTy) {
|
GuardVariable->setVisibility(GV->getVisibility());
|
||||||
guard = cast<llvm::GlobalVariable>(existingGuard); // okay
|
|
||||||
} else {
|
|
||||||
CGM.Error(D.getLocation(), "problem emitting static variable '"
|
|
||||||
+ guardName.str() +
|
|
||||||
"': 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, var->getLinkage(),
|
|
||||||
llvm::ConstantInt::get(guardTy, 0),
|
|
||||||
guardName.str());
|
|
||||||
guard->setVisibility(var->getVisibility());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -1140,9 +1115,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
if (IsARM && !useInt8GuardVariable) {
|
if (IsARM && !useInt8GuardVariable) {
|
||||||
llvm::Value *V = Builder.CreateLoad(guard);
|
llvm::Value *V = Builder.CreateLoad(GuardVariable);
|
||||||
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:
|
||||||
|
@ -1160,9 +1135,10 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
// }
|
// }
|
||||||
} else {
|
} else {
|
||||||
// Load the first byte of the guard variable.
|
// Load the first byte of the guard variable.
|
||||||
llvm::LoadInst *load =
|
llvm::Type *PtrTy = Builder.getInt8PtrTy();
|
||||||
Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy));
|
llvm::LoadInst *LI =
|
||||||
load->setAlignment(1);
|
Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy));
|
||||||
|
LI->setAlignment(1);
|
||||||
|
|
||||||
// Itanium ABI:
|
// Itanium ABI:
|
||||||
// An implementation supporting thread-safety on multiprocessor
|
// An implementation supporting thread-safety on multiprocessor
|
||||||
|
@ -1171,16 +1147,16 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
|
||||||
//
|
//
|
||||||
// In LLVM, we do this by marking the load Acquire.
|
// In LLVM, we do this by marking the load Acquire.
|
||||||
if (threadsafe)
|
if (threadsafe)
|
||||||
load->setAtomic(llvm::Acquire);
|
LI->setAtomic(llvm::Acquire);
|
||||||
|
|
||||||
isInitialized = Builder.CreateIsNull(load, "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);
|
||||||
|
|
||||||
|
@ -1188,7 +1164,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), guard);
|
= Builder.CreateCall(getGuardAcquireFn(CGM, GuardPtrTy), GuardVariable);
|
||||||
|
|
||||||
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
|
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
|
||||||
|
|
||||||
|
@ -1196,22 +1172,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, guard);
|
CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, GuardVariable);
|
||||||
|
|
||||||
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, varAddr, PerformInit);
|
CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
|
||||||
|
|
||||||
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), guard);
|
Builder.CreateCall(getGuardReleaseFn(CGM, GuardPtrTy), GuardVariable);
|
||||||
} else {
|
} else {
|
||||||
Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guard);
|
Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGF.EmitBlock(EndBlock);
|
CGF.EmitBlock(EndBlock);
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
// 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
|
||||||
|
@ -80,73 +79,3 @@ 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