Author: rnk Date: Tue Sep 10 15:14:30 2013 New Revision: 190427 URL: http://llvm.org/viewvc/llvm-project?rev=190427&view=rev Log: [ms-cxxabi] Implement guard variables for static initialization
Static locals requiring initialization are not thread safe on Windows. Unfortunately, it's possible to create static locals that are actually externally visible with inline functions and templates. As a result, we have to implement an initialization guard scheme that is compatible with TUs built by MSVC, which makes thread safety prohibitively difficult. MSVC's scheme is that every function that requires a guard gets an i32 bitfield. Each static local is assigned a bit that indicates if it has been initialized, up to 32 bits, at which point a new bitfield is created. MSVC rejects inline functions with more than 32 static locals, and the externally visible mangling (?_B) only allows for one guard variable per function. On Eli's recommendation, I used MangleNumberingContext to track which bit each static corresponds to. Implements PR16888. Reviewers: rjmccall, eli.friedman Differential Revision: http://llvm-reviews.chandlerc.com/D1416 Modified: cfe/trunk/include/clang/AST/ASTContext.h cfe/trunk/include/clang/AST/Mangle.h cfe/trunk/include/clang/AST/MangleNumberingContext.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/CXXABI.h cfe/trunk/lib/AST/ItaniumCXXABI.cpp cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/AST/MangleNumberingContext.cpp cfe/trunk/lib/AST/MicrosoftCXXABI.cpp cfe/trunk/lib/AST/MicrosoftMangle.cpp cfe/trunk/lib/CodeGen/CGCXXABI.cpp cfe/trunk/lib/CodeGen/CGCXXABI.h cfe/trunk/lib/CodeGen/CGDeclCXX.cpp cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaLambda.cpp cfe/trunk/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp Modified: cfe/trunk/include/clang/AST/ASTContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h (original) +++ cfe/trunk/include/clang/AST/ASTContext.h Tue Sep 10 15:14:30 2013 @@ -19,7 +19,6 @@ #include "clang/AST/CanonicalType.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/AST/Decl.h" -#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/RawCommentList.h" @@ -59,6 +58,7 @@ namespace clang { class SelectorTable; class TargetInfo; class CXXABI; + class MangleNumberingContext; // Decls class MangleContext; class ObjCIvarDecl; @@ -353,7 +353,7 @@ private: /// \brief Mapping from each declaration context to its corresponding /// mangling numbering context (used for constructs like lambdas which /// need to be consistently numbered for the mangler). - llvm::DenseMap<const DeclContext *, MangleNumberingContext> + llvm::DenseMap<const DeclContext *, MangleNumberingContext *> MangleNumberingContexts; /// \brief Side-table of mangling numbers for declarations which rarely @@ -2119,6 +2119,8 @@ public: /// DeclContext. MangleNumberingContext &getManglingNumberContext(const DeclContext *DC); + MangleNumberingContext *createMangleNumberingContext() const; + /// \brief Used by ParmVarDecl to store on the side the /// index of the parameter when it exceeds the size of the normal bitfield. void setParameterIndex(const ParmVarDecl *D, unsigned index); Modified: cfe/trunk/include/clang/AST/Mangle.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Mangle.h (original) +++ cfe/trunk/include/clang/AST/Mangle.h Tue Sep 10 15:14:30 2013 @@ -139,11 +139,11 @@ public: void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &); - // This is pretty lame. - virtual void mangleItaniumGuardVariable(const VarDecl *D, - raw_ostream &) { - llvm_unreachable("Target does not support mangling guard variables"); - } + virtual void mangleStaticGuardVariable(const VarDecl *D, + raw_ostream &Out) = 0; + virtual void mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) = 0; + // FIXME: Revisit this once we know what we need to do for MSVC compatibility. virtual void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) { Modified: cfe/trunk/include/clang/AST/MangleNumberingContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/MangleNumberingContext.h?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/MangleNumberingContext.h (original) +++ cfe/trunk/include/clang/AST/MangleNumberingContext.h Tue Sep 10 15:14:30 2013 @@ -33,10 +33,11 @@ class VarDecl; class MangleNumberingContext : public RefCountedBase<MangleNumberingContext> { llvm::DenseMap<const Type *, unsigned> ManglingNumbers; - llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers; llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers; public: + virtual ~MangleNumberingContext() {} + /// \brief Retrieve the mangling number of a new lambda expression with the /// given call operator within this context. unsigned getManglingNumber(const CXXMethodDecl *CallOperator); @@ -47,7 +48,7 @@ public: /// \brief Retrieve the mangling number of a static local variable within /// this context. - unsigned getManglingNumber(const VarDecl *VD); + virtual unsigned getManglingNumber(const VarDecl *VD) = 0; /// \brief Retrieve the mangling number of a static local variable within /// this context. Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Sep 10 15:14:30 2013 @@ -703,12 +703,7 @@ public: /// \brief Retrieve the mangling numbering context, used to consistently /// number constructs like lambdas for mangling. - MangleNumberingContext &getMangleNumberingContext() { - assert(ManglingContextDecl && "Need to have a context declaration"); - if (!MangleNumbering) - MangleNumbering = new MangleNumberingContext; - return *MangleNumbering; - } + MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx); bool isUnevaluated() const { return Context == Unevaluated || Context == UnevaluatedAbstract; Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Tue Sep 10 15:14:30 2013 @@ -25,6 +25,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Mangle.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" @@ -766,6 +767,12 @@ ASTContext::~ASTContext() { AEnd = DeclAttrs.end(); A != AEnd; ++A) A->second->~AttrVec(); + + for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator + I = MangleNumberingContexts.begin(), + E = MangleNumberingContexts.end(); + I != E; ++I) + delete I->second; } void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { @@ -8037,7 +8044,15 @@ unsigned ASTContext::getManglingNumber(c MangleNumberingContext & ASTContext::getManglingNumberContext(const DeclContext *DC) { - return MangleNumberingContexts[DC]; + assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C. + MangleNumberingContext *&MCtx = MangleNumberingContexts[DC]; + if (!MCtx) + MCtx = createMangleNumberingContext(); + return *MCtx; +} + +MangleNumberingContext *ASTContext::createMangleNumberingContext() const { + return ABI->createMangleNumberingContext(); } void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { Modified: cfe/trunk/lib/AST/CXXABI.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CXXABI.h?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/AST/CXXABI.h (original) +++ cfe/trunk/lib/AST/CXXABI.h Tue Sep 10 15:14:30 2013 @@ -21,6 +21,7 @@ namespace clang { class ASTContext; class MemberPointerType; +class MangleNumberingContext; /// Implements C++ ABI-specific semantic analysis functions. class CXXABI { @@ -34,9 +35,12 @@ public: /// Returns the default calling convention for C++ methods. virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0; - // Returns whether the given class is nearly empty, with just virtual pointers - // and no data except possibly virtual bases. + /// Returns whether the given class is nearly empty, with just virtual + /// pointers and no data except possibly virtual bases. virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0; + + /// Returns a new mangling number context for this C++ ABI. + virtual MangleNumberingContext *createMangleNumberingContext() const = 0; }; /// Creates an instance of a C++ ABI class. Modified: cfe/trunk/lib/AST/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumCXXABI.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/AST/ItaniumCXXABI.cpp Tue Sep 10 15:14:30 2013 @@ -20,6 +20,7 @@ #include "CXXABI.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -27,6 +28,19 @@ using namespace clang; namespace { + +/// \brief Keeps track of the mangled names of lambda expressions and block +/// literals within a particular context. +class ItaniumNumberingContext : public MangleNumberingContext { + llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers; + +public: + /// Variable decls are numbered by identifier. + virtual unsigned getManglingNumber(const VarDecl *VD) { + return ++VarManglingNumbers[VD->getIdentifier()]; + } +}; + class ItaniumCXXABI : public CXXABI { protected: ASTContext &Context; @@ -61,6 +75,10 @@ public: Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); return Layout.getNonVirtualSize() == PointerSize; } + + virtual MangleNumberingContext *createMangleNumberingContext() const { + return new ItaniumNumberingContext(); + } }; class ARMCXXABI : public ItaniumCXXABI { Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue Sep 10 15:14:30 2013 @@ -152,7 +152,8 @@ public: void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &); - void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); + void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &); + void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out); void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &); void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &); @@ -3691,8 +3692,8 @@ ItaniumMangleContext::mangleCXXDtorThunk /// mangleGuardVariable - Returns the mangled name for a guard variable /// for the passed in VarDecl. -void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, - raw_ostream &Out) { +void ItaniumMangleContext::mangleStaticGuardVariable(const VarDecl *D, + raw_ostream &Out) { // <special-name> ::= GV <object name> # Guard variable for one-time // # initialization CXXNameMangler Mangler(*this, Out); @@ -3700,6 +3701,17 @@ void ItaniumMangleContext::mangleItanium Mangler.mangleName(D); } +void ItaniumMangleContext::mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) { + // Prefix the mangling of D with __dtor_. + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "__dtor_"; + if (shouldMangleDeclName(D)) + Mangler.mangle(D); + else + Mangler.getStream() << D->getName(); +} + void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &Out) { // <special-name> ::= TH <object name> Modified: cfe/trunk/lib/AST/MangleNumberingContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MangleNumberingContext.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/AST/MangleNumberingContext.cpp (original) +++ cfe/trunk/lib/AST/MangleNumberingContext.cpp Tue Sep 10 15:14:30 2013 @@ -38,11 +38,6 @@ MangleNumberingContext::getManglingNumbe } unsigned -MangleNumberingContext::getManglingNumber(const VarDecl *VD) { - return ++VarManglingNumbers[VD->getIdentifier()]; -} - -unsigned MangleNumberingContext::getManglingNumber(const TagDecl *TD) { return ++TagManglingNumbers[TD->getIdentifier()]; } Modified: cfe/trunk/lib/AST/MicrosoftCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftCXXABI.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/AST/MicrosoftCXXABI.cpp (original) +++ cfe/trunk/lib/AST/MicrosoftCXXABI.cpp Tue Sep 10 15:14:30 2013 @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -23,6 +24,22 @@ using namespace clang; namespace { + +/// \brief Numbers things which need to correspond across multiple TUs. +/// Typically these are things like static locals, lambdas, or blocks. +class MicrosoftNumberingContext : public MangleNumberingContext { + unsigned NumStaticLocals; + +public: + MicrosoftNumberingContext() : NumStaticLocals(0) { } + + /// Static locals are numbered by source order. + virtual unsigned getManglingNumber(const VarDecl *VD) { + assert(VD->isStaticLocal()); + return ++NumStaticLocals; + } +}; + class MicrosoftCXXABI : public CXXABI { ASTContext &Context; public: @@ -51,6 +68,10 @@ public: return Layout.getNonVirtualSize() == PointerSize || Layout.getNonVirtualSize() == PointerSize * 2; } + + MangleNumberingContext *createMangleNumberingContext() const { + return new MicrosoftNumberingContext(); + } }; } Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original) +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Tue Sep 10 15:14:30 2013 @@ -92,6 +92,7 @@ public: QualifierMangleMode QMM = QMM_Mangle); void mangleFunctionType(const FunctionType *T, const FunctionDecl *D, bool IsStructor, bool IsInstMethod); + void manglePostfix(const DeclContext *DC, bool NoFunction = false); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -100,7 +101,6 @@ private: } void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); void mangleSourceName(const IdentifierInfo *II); - void manglePostfix(const DeclContext *DC, bool NoFunction=false); void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); void mangleCXXDtorType(CXXDtorType T); void mangleQualifiers(Qualifiers Quals, bool IsMember); @@ -168,8 +168,10 @@ public: raw_ostream &); virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &); - virtual void mangleReferenceTemporary(const clang::VarDecl *, - raw_ostream &); + virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &); + virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out); + virtual void mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out); }; } @@ -1912,13 +1914,44 @@ void MicrosoftMangleContext::mangleCXXDt MicrosoftCXXNameMangler mangler(*this, Out, D, Type); mangler.mangle(D); } -void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD, +void MicrosoftMangleContext::mangleReferenceTemporary(const VarDecl *VD, raw_ostream &) { unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this reference temporary yet"); getDiags().Report(VD->getLocation(), DiagID); } +void MicrosoftMangleContext::mangleStaticGuardVariable(const VarDecl *VD, + raw_ostream &Out) { + // <guard-name> ::= ?_B <postfix> @51 + // ::= ?$S <guard-num> @ <postfix> @4IA + + // The first mangling is what MSVC uses to guard static locals in inline + // functions. It uses a different mangling in external functions to support + // guarding more than 32 variables. MSVC rejects inline functions with more + // than 32 static locals. We don't fully implement the second mangling + // because those guards are not externally visible, and instead use LLVM's + // default renaming when creating a new guard variable. + MicrosoftCXXNameMangler Mangler(*this, Out); + + bool Visible = VD->isExternallyVisible(); + // <operator-name> ::= ?_B # local static guard + Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@"); + Mangler.manglePostfix(VD->getDeclContext()); + Mangler.getStream() << (Visible ? "@51" : "@4IA"); +} + +void MicrosoftMangleContext::mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) { + // <destructor-name> ::= ?__F <postfix> YAXXZ + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "\01??__F"; + Mangler.mangleName(D); + // This is the mangling of the function type of the stub, which is a global, + // non-variadic, cdecl function that returns void and takes no args. + Mangler.getStream() << "YAXXZ"; +} + MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, DiagnosticsEngine &Diags) { return new MicrosoftMangleContext(Context, Diags); Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Tue Sep 10 15:14:30 2013 @@ -212,13 +212,6 @@ llvm::Value *CGCXXABI::readArrayCookieIm return llvm::ConstantInt::get(CGF.SizeTy, 0); } -void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, - const VarDecl &D, - llvm::GlobalVariable *GV, - bool PerformInit) { - ErrorUnsupportedABI(CGF, "static local variable initialization"); -} - void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, llvm::Constant *dtor, Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original) +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Tue Sep 10 15:14:30 2013 @@ -413,7 +413,8 @@ public: /// - a static local variable /// - a static data member of a class template instantiation virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *DeclPtr, bool PerformInit); + llvm::GlobalVariable *DeclPtr, + bool PerformInit) = 0; /// Emit code to force the execution of a destructor during global /// teardown. The default implementation of this uses atexit. Modified: cfe/trunk/lib/CodeGen/CGDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDeclCXX.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp Tue Sep 10 15:14:30 2013 @@ -166,9 +166,13 @@ static llvm::Constant *createAtExitStub( llvm::Constant *addr) { // Get the destructor function type, void(*)(void). llvm::FunctionType *ty = llvm::FunctionType::get(CGM.VoidTy, false); + SmallString<256> FnName; + { + llvm::raw_svector_ostream Out(FnName); + CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&VD, Out); + } llvm::Function *fn = - CreateGlobalInitOrDestructFunction(CGM, ty, - Twine("__dtor_", addr->getName())); + CreateGlobalInitOrDestructFunction(CGM, ty, FnName.str()); CodeGenFunction CGF(CGM); Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Sep 10 15:14:30 2013 @@ -1142,7 +1142,7 @@ void ItaniumCXXABI::EmitGuardedInit(Code SmallString<256> guardName; { llvm::raw_svector_ostream out(guardName); - getMangleContext().mangleItaniumGuardVariable(&D, out); + getMangleContext().mangleStaticGuardVariable(&D, out); out.flush(); } Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Sep 10 15:14:30 2013 @@ -305,6 +305,18 @@ public: private: /// VBTables - All the vbtables which have been referenced. llvm::DenseMap<const CXXRecordDecl *, VBTableVector> VBTablesMap; + + /// Info on the global variable used to guard initialization of static locals. + /// The BitIndex field is only used for externally invisible declarations. + struct GuardInfo { + GuardInfo() : Guard(0), BitIndex(0) {} + llvm::GlobalVariable *Guard; + unsigned BitIndex; + }; + + /// Map from DeclContext to the current guard variable. We assume that the + /// AST is visited in source code order. + llvm::DenseMap<const DeclContext *, GuardInfo> GuardVariableMap; }; } @@ -727,17 +739,86 @@ llvm::Value* MicrosoftCXXABI::Initialize } void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *DeclPtr, + llvm::GlobalVariable *GV, bool PerformInit) { - // FIXME: this code was only tested for global initialization. - // Not sure whether we want thread-safe static local variables as VS - // doesn't make them thread-safe. + // MSVC always uses an i32 bitfield to guard initialization, which is *not* + // threadsafe. Since the user may be linking in inline functions compiled by + // cl.exe, there's no reason to provide a false sense of security by using + // critical sections here. if (D.getTLSKind()) CGM.ErrorUnsupported(&D, "dynamic TLS initialization"); - // Emit the initializer and add a global destructor if appropriate. - CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit); + CGBuilderTy &Builder = CGF.Builder; + llvm::IntegerType *GuardTy = CGF.Int32Ty; + llvm::ConstantInt *Zero = llvm::ConstantInt::get(GuardTy, 0); + + // Get the guard variable for this function if we have one already. + GuardInfo &GI = GuardVariableMap[D.getDeclContext()]; + + unsigned BitIndex; + if (D.isExternallyVisible()) { + // Externally visible variables have to be numbered in Sema to properly + // handle unreachable VarDecls. + BitIndex = getContext().getManglingNumber(&D); + assert(BitIndex > 0); + BitIndex--; + } else { + // Non-externally visible variables are numbered here in CodeGen. + BitIndex = GI.BitIndex++; + } + + if (BitIndex >= 32) { + if (D.isExternallyVisible()) + ErrorUnsupportedABI(CGF, "more than 32 guarded initializations"); + BitIndex %= 32; + GI.Guard = 0; + } + + // Lazily create the i32 bitfield for this function. + if (!GI.Guard) { + // Mangle the name for the guard. + SmallString<256> GuardName; + { + llvm::raw_svector_ostream Out(GuardName); + getMangleContext().mangleStaticGuardVariable(&D, Out); + Out.flush(); + } + + // Create the guard variable with a zero-initializer. Just absorb linkage + // and visibility from the guarded variable. + GI.Guard = new llvm::GlobalVariable(CGM.getModule(), GuardTy, false, + GV->getLinkage(), Zero, GuardName.str()); + GI.Guard->setVisibility(GV->getVisibility()); + } else { + assert(GI.Guard->getLinkage() == GV->getLinkage() && + "static local from the same function had different linkage"); + } + + // Pseudo code for the test: + // if (!(GuardVar & MyGuardBit)) { + // GuardVar |= MyGuardBit; + // ... initialize the object ...; + // } + + // Test our bit from the guard variable. + llvm::ConstantInt *Bit = llvm::ConstantInt::get(GuardTy, 1U << BitIndex); + llvm::LoadInst *LI = Builder.CreateLoad(GI.Guard); + llvm::Value *IsInitialized = + Builder.CreateICmpNE(Builder.CreateAnd(LI, Bit), Zero); + llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init"); + llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); + Builder.CreateCondBr(IsInitialized, EndBlock, InitBlock); + + // Set our bit in the guard variable and emit the initializer and add a global + // destructor if appropriate. + CGF.EmitBlock(InitBlock); + Builder.CreateStore(Builder.CreateOr(LI, Bit), GI.Guard); + CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit); + Builder.CreateBr(EndBlock); + + // Continue. + CGF.EmitBlock(EndBlock); } // Member pointer helpers. Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Sep 10 15:14:30 2013 @@ -3083,6 +3083,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(S } static void HandleTagNumbering(Sema &S, const TagDecl *Tag) { + if (!S.Context.getLangOpts().CPlusPlus) + return; + if (isa<CXXRecordDecl>(Tag->getParent())) { // If this tag is the direct child of a class, number it if // it is anonymous. @@ -5356,7 +5359,7 @@ Sema::ActOnVariableDeclarator(Scope *S, isIncompleteDeclExternC(*this, NewVD)) RegisterLocallyScopedExternCDecl(NewVD, S); - if (NewVD->isStaticLocal()) { + if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { Decl *ManglingContextDecl; if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(NewVD->getDeclContext(), Modified: cfe/trunk/lib/Sema/SemaLambda.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLambda.cpp (original) +++ cfe/trunk/lib/Sema/SemaLambda.cpp Tue Sep 10 15:14:30 2013 @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/DeclSpec.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -114,12 +115,21 @@ Sema::getCurrentMangleNumberContext(cons // -- the in-class initializers of class members case DefaultArgument: // -- default arguments appearing in class definitions - return &ExprEvalContexts.back().getMangleNumberingContext(); + return &ExprEvalContexts.back().getMangleNumberingContext(Context); } llvm_unreachable("unexpected context"); } +MangleNumberingContext & +Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext( + ASTContext &Ctx) { + assert(ManglingContextDecl && "Need to have a context declaration"); + if (!MangleNumbering) + MangleNumbering = Ctx.createMangleNumberingContext(); + return *MangleNumbering; +} + CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, Modified: cfe/trunk/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp (original) +++ cfe/trunk/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp Tue Sep 10 15:14:30 2013 @@ -20,7 +20,7 @@ void foo() { // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 12] [local] [def] [__dtor_glob] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__cxx_global_var_init1] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__cxx_global_array_dtor] -// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__dtor_] +// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__dtor_array] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 16] [local] [def] [__dtor__ZZ3foovE4stat] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def]{{$}} Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp?rev=190427&r1=190426&r2=190427&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp (original) +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp Tue Sep 10 15:14:30 2013 @@ -5,19 +5,81 @@ // CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] struct S { - S() {} - ~S() {} -} s; + S(); + ~S(); +}; + +S s; // CHECK: define internal void [[INIT_s:@.*global_var.*]] [[NUW:#[0-9]+]] // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ" -// CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A") +// CHECK: call i32 @atexit(void ()* @"\01??__Fs@@YAXXZ") // CHECK: ret void -// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() [[NUW]] { +// CHECK: define internal void @"\01??__Fs@@YAXXZ"() [[NUW]] { // CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ" // CHECK: ret void +void StaticLocal() { + static S TheS; +} +// CHECK-LABEL: define void @"\01?StaticLocal@@YAXXZ"() +// CHECK: load i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: ret + +void MultipleStatics() { + static S S1; + static S S2; + static S S3; + static S S4; + static S S5; + static S S6; + static S S7; + static S S8; + static S S9; + static S S10; + static S S11; + static S S12; + static S S13; + static S S14; + static S S15; + static S S16; + static S S17; + static S S18; + static S S19; + static S S20; + static S S21; + static S S22; + static S S23; + static S S24; + static S S25; + static S S26; + static S S27; + static S S28; + static S S29; + static S S30; + static S S31; + static S S32; + static S S33; + static S S34; + static S S35; +} +// CHECK-LABEL: define void @"\01?MultipleStatics@@YAXXZ"() +// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA" +// CHECK: and i32 {{.*}}, 1 +// CHECK: and i32 {{.*}}, 2 +// CHECK: and i32 {{.*}}, 4 +// CHECK: and i32 {{.*}}, 8 +// CHECK: and i32 {{.*}}, 16 +// ... +// CHECK: and i32 {{.*}}, -2147483648 +// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA1" +// CHECK: and i32 {{.*}}, 1 +// CHECK: and i32 {{.*}}, 2 +// CHECK: and i32 {{.*}}, 4 +// CHECK: ret + // Force WeakODRLinkage by using templates class A { public: @@ -33,20 +95,55 @@ class B { template<typename T> A B<T>::foo; +inline S &UnreachableStatic() { + if (0) { + static S s; // bit 1 + return s; + } + static S s; // bit 2 + return s; +} + +// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?UnreachableStatic@@YAAAUS@@XZ"() +// CHECK: and i32 {{.*}}, 2 +// CHECK: or i32 {{.*}}, 2 +// CHECK: ret + +inline S &getS() { + static S TheS; + return TheS; +} + +// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?getS@@YAAAUS@@XZ" +// CHECK: load i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51" +// CHECK: and i32 {{.*}}, 1 +// CHECK: icmp ne i32 {{.*}}, 0 +// CHECK: br i1 +// init: +// CHECK: or i32 {{.*}}, 1 +// CHECK: store i32 {{.*}}, i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51" +// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"(%struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A") +// CHECK: call i32 @atexit(void ()* @"\01??__FTheS@?1??getS@@YAAAUS@@XZ@YAXXZ") +// CHECK: br label +// init.end: +// CHECK: ret %struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A" + void force_usage() { + UnreachableStatic(); + getS(); (void)B<int>::foo; // (void) - force usage } // CHECK: define internal void [[INIT_foo]]() [[NUW]] // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" -// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]]) +// CHECK: call i32 @atexit(void ()* @"\01??__Ffoo@?$B@H@@YAXXZ") // CHECK: ret void // CHECK: define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" // CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ" -// CHECK: define internal void [[FOO_DTOR]] +// CHECK: define internal void @"\01??__Ffoo@?$B@H@@YAXXZ" // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo // CHECK: ret void _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
