diff options
| author | Timur Iskhodzhanov <timurrrr@google.com> | 2013-10-08 19:15:38 +0000 |
|---|---|---|
| committer | Timur Iskhodzhanov <timurrrr@google.com> | 2013-10-08 19:15:38 +0000 |
| commit | 1ffb3916ce2ca71d1827db0cf39b7a0876e68ca7 (patch) | |
| tree | 181eaf94cdb1e23dbf5b7bab845ba1a97377d1b5 /clang/lib | |
| parent | 71cd285dc84426c786010c3bdbfcbfb1f7e23016 (diff) | |
| download | bcm5719-llvm-1ffb3916ce2ca71d1827db0cf39b7a0876e68ca7.tar.gz bcm5719-llvm-1ffb3916ce2ca71d1827db0cf39b7a0876e68ca7.zip | |
Abstract out parts of thunk emission code, add support for simple thunks when using -cxx-abi microsoft
Reviewed at http://llvm-reviews.chandlerc.com/D1787
llvm-svn: 192220
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/MicrosoftMangle.cpp | 86 | ||||
| -rw-r--r-- | clang/lib/AST/VTableBuilder.cpp | 72 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 6 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGVTables.cpp | 49 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGVTables.h | 15 | ||||
| -rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 12 |
7 files changed, 172 insertions, 75 deletions
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index ab0db1acbf6..2c37709bcf1 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -1405,7 +1406,8 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { // ::= Z # global far if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { switch (MD->getAccess()) { - default: + case AS_none: + llvm_unreachable("Unsupported access specifier"); case AS_private: if (MD->isStatic()) Out << 'C'; @@ -1858,36 +1860,70 @@ void MicrosoftMangleContextImpl::mangleName(const NamedDecl *D, return Mangler.mangle(D); } +static void mangleThunkThisAdjustment(const CXXMethodDecl *MD, + const ThisAdjustment &Adjustment, + MicrosoftCXXNameMangler &Mangler, + raw_ostream &Out) { + // FIXME: add support for vtordisp thunks. + if (Adjustment.NonVirtual != 0) { + switch (MD->getAccess()) { + case AS_none: + llvm_unreachable("Unsupported access specifier"); + case AS_private: + Out << 'G'; + break; + case AS_protected: + Out << 'O'; + break; + case AS_public: + Out << 'W'; + } + llvm::APSInt APSNumber(/*BitWidth=*/32, /*isUnsigned=*/true); + APSNumber = -Adjustment.NonVirtual; + Mangler.mangleNumber(APSNumber); + } else { + switch (MD->getAccess()) { + case AS_none: + llvm_unreachable("Unsupported access specifier"); + case AS_private: + Out << 'A'; + break; + case AS_protected: + Out << 'I'; + break; + case AS_public: + Out << 'Q'; + } + } +} + void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &Out) { - // FIXME: this is not yet a complete implementation, but merely a - // reasonably-working stub to avoid crashing when required to emit a thunk. MicrosoftCXXNameMangler Mangler(*this, Out); Out << "\01?"; Mangler.mangleName(MD); - if (Thunk.This.NonVirtual != 0) { - // FIXME: add support for protected/private or use mangleFunctionClass. - Out << "W"; - llvm::APSInt APSNumber(/*BitWidth=*/32 /*FIXME: check on x64*/, - /*isUnsigned=*/true); - APSNumber = -Thunk.This.NonVirtual; - Mangler.mangleNumber(APSNumber); - } else { - // FIXME: add support for protected/private or use mangleFunctionClass. - Out << "Q"; - } - // FIXME: mangle return adjustment? Most likely includes using an overridee FPT? - Mangler.mangleFunctionType(MD->getType()->castAs<FunctionProtoType>(), MD); -} - -void MicrosoftMangleContextImpl::mangleCXXDtorThunk(const CXXDestructorDecl *DD, - CXXDtorType Type, - const ThisAdjustment &, - raw_ostream &) { - unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle thunk for this destructor yet"); - getDiags().Report(DD->getLocation(), DiagID); + mangleThunkThisAdjustment(MD, Thunk.This, Mangler, Out); + if (!Thunk.Return.isEmpty()) + assert(Thunk.Method != 0 && "Thunk info should hold the overridee decl"); + + const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD; + Mangler.mangleFunctionType( + DeclForFPT->getType()->castAs<FunctionProtoType>(), MD); +} + +void MicrosoftMangleContextImpl::mangleCXXDtorThunk( + const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &Adjustment, raw_ostream &Out) { + // FIXME: Actually, the dtor thunk should be emitted for vector deleting + // dtors rather than scalar deleting dtors. Just use the vector deleting dtor + // mangling manually until we support both deleting dtor types. + assert(Type == Dtor_Deleting); + MicrosoftCXXNameMangler Mangler(*this, Out, DD, Type); + Out << "\01??_E"; + Mangler.mangleName(DD->getParent()); + mangleThunkThisAdjustment(DD, Adjustment, Mangler, Out); + Mangler.mangleFunctionType(DD->getType()->castAs<FunctionProtoType>(), DD); } void MicrosoftMangleContextImpl::mangleCXXVFTable( diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index 9aad711748c..fbc5e3dd93a 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -992,6 +992,7 @@ public: MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { + assert(!Context.getTargetInfo().getCXXABI().isMicrosoft()); LayoutVTable(); @@ -1904,6 +1905,21 @@ VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, } } +struct ItaniumThunkInfoComparator { + bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) { + assert(LHS.Method == 0); + assert(RHS.Method == 0); + + if (LHS.This != RHS.This) + return LHS.This < RHS.This; + + if (LHS.Return != RHS.Return) + return LHS.Return < RHS.Return; + + llvm_unreachable("Shouldn't observe two equal thunks"); + } +}; + /// dumpLayout - Dump the vtable layout. void VTableBuilder::dumpLayout(raw_ostream& Out) { // FIXME: write more tests that actually use the dumpLayout output to prevent @@ -2146,7 +2162,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { const CXXMethodDecl *MD = I->second; ThunkInfoVectorTy ThunksVector = Thunks[MD]; - std::sort(ThunksVector.begin(), ThunksVector.end()); + std::sort(ThunksVector.begin(), ThunksVector.end(), + ItaniumThunkInfoComparator()); Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; @@ -2233,7 +2250,15 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { Out << '\n'; } - + +struct VTableThunksComparator { + bool operator()(const VTableLayout::VTableThunkTy &LHS, + const VTableLayout::VTableThunkTy &RHS) { + assert(LHS.first != RHS.first && + "All thunks should have unique indices!"); + return LHS.first < RHS.first; + } +}; } VTableLayout::VTableLayout(uint64_t NumVTableComponents, @@ -2252,6 +2277,9 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents, this->VTableComponents.get()); std::copy(VTableThunks, VTableThunks+NumVTableThunks, this->VTableThunks.get()); + std::sort(this->VTableThunks.get(), + this->VTableThunks.get() + NumVTableThunks, + VTableThunksComparator()); } VTableLayout::~VTableLayout() { } @@ -2312,7 +2340,6 @@ VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) { SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); - std::sort(VTableThunks.begin(), VTableThunks.end()); return new VTableLayout(Builder.getNumVTableComponents(), Builder.vtable_component_begin(), @@ -2520,18 +2547,14 @@ private: /// AddMethod - Add a single virtual member function to the vftable /// components vector. - void AddMethod(const CXXMethodDecl *MD, ThisAdjustment ThisAdjustment, - ReturnAdjustment ReturnAdjustment) { + void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) { if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - assert(ReturnAdjustment.isEmpty() && + assert(TI.Return.isEmpty() && "Destructor can't have return adjustment!"); Components.push_back(VTableComponent::MakeDeletingDtor(DD)); } else { - // Add the return adjustment if necessary. - if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) { - VTableThunks[Components.size()].Return = ReturnAdjustment; - VTableThunks[Components.size()].This = ThisAdjustment; - } + if (!TI.isEmpty()) + VTableThunks[Components.size()] = TI; Components.push_back(VTableComponent::MakeFunction(MD)); } } @@ -2816,6 +2839,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, FinalOverriders::OverriderInfo Overrider = Overriders.getOverrider(MD, Base.getBaseOffset()); ThisAdjustment ThisAdjustmentOffset; + bool ForceThunk = false; // Check if this virtual member function overrides // a method in one of the visited bases. @@ -2840,8 +2864,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]); } - if (ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD) - .isEmpty()) { + if (MD->getResultType() == OverriddenMD->getResultType()) { // No return adjustment needed - just replace the overridden method info // with the current info. MethodInfo MI(OverriddenMethodInfo.VBTableIndex, @@ -2859,6 +2882,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // method was in the vftable. // For now, just mark the overriden method as shadowed by a new slot. OverriddenMethodInfo.Shadowed = true; + ForceThunk = true; // Also apply this adjustment to the shadowed slots. if (!ThisAdjustmentOffset.isEmpty()) { @@ -2907,6 +2931,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD); } if (!ReturnAdjustmentOffset.isEmpty()) { + ForceThunk = true; ReturnAdjustment.NonVirtual = ReturnAdjustmentOffset.NonVirtualOffset.getQuantity(); if (ReturnAdjustmentOffset.VirtualBase) { @@ -2918,7 +2943,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, } } - AddMethod(Overrider.Method, ThisAdjustmentOffset, ReturnAdjustment); + AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, + ForceThunk ? MD : 0)); } } @@ -2929,6 +2955,20 @@ void PrintBasePath(const VFPtrInfo::BasePath &Path, raw_ostream &Out) { } } +struct MicrosoftThunkInfoStableSortComparator { + bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) { + if (LHS.This != RHS.This) + return LHS.This < RHS.This; + + if (LHS.Return != RHS.Return) + return LHS.Return < RHS.Return; + + // Keep different thunks with the same adjustments in the order they + // were put into the vector. + return false; + } +}; + void VFTableBuilder::dumpLayout(raw_ostream &Out) { Out << "VFTable for "; PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out); @@ -3042,7 +3082,8 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) { const CXXMethodDecl *MD = I->second; ThunkInfoVectorTy ThunksVector = Thunks[MD]; - std::sort(ThunksVector.begin(), ThunksVector.end()); + std::stable_sort(ThunksVector.begin(), ThunksVector.end(), + MicrosoftThunkInfoStableSortComparator()); Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; @@ -3218,7 +3259,6 @@ void MicrosoftVFTableContext::computeVTableRelatedInformation( assert(VFTableLayouts.count(id) == 0); SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks( Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); - std::sort(VTableThunks.begin(), VTableThunks.end()); VFTableLayouts[id] = new VTableLayout( Builder.getNumVTableComponents(), Builder.vtable_component_begin(), VTableThunks.size(), VTableThunks.data(), EmptyAddressPointsMap, true); diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 3a1c8d198dc..eaeb971dc42 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -339,11 +339,17 @@ public: SourceLocation CallLoc, llvm::Value *This) = 0; + virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, + GlobalDecl GD, + CallArgList &CallArgs) {} + /// Emit any tables needed to implement virtual inheritance. For Itanium, /// this emits virtual table tables. For the MSVC++ ABI, this emits virtual /// base tables. virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0; + virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) = 0; + virtual void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResultType); diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index b987eb4d079..5ede5650b93 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -333,6 +333,9 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, // Add our adjusted 'this' pointer. CallArgs.add(RValue::get(AdjustedThisPtr), ThisType); + if (isa<CXXDestructorDecl>(MD)) + CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, GD, CallArgs); + // Add the rest of the parameters. for (FunctionDecl::param_const_iterator I = MD->param_begin(), E = MD->param_end(); I != E; ++I) { @@ -390,14 +393,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, setThunkVisibility(CGM, MD, Thunk, Fn); } -void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, - bool UseAvailableExternallyLinkage) -{ - if (CGM.getTarget().getCXXABI().isMicrosoft()) { - // Emission of thunks is not supported yet in Microsoft ABI. - return; - } - +void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, + bool ForVTable) { const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD); // FIXME: re-use FnInfo in this computation. @@ -435,9 +432,11 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, } llvm::Function *ThunkFn = cast<llvm::Function>(Entry); + bool ABIHasKeyFunctions = CGM.getTarget().getCXXABI().hasKeyFunctions(); + bool UseAvailableExternallyLinkage = ForVTable && ABIHasKeyFunctions; if (!ThunkFn->isDeclaration()) { - if (UseAvailableExternallyLinkage) { + if (!ABIHasKeyFunctions || UseAvailableExternallyLinkage) { // There is already a thunk emitted for this function, do nothing. return; } @@ -466,14 +465,17 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk); } - if (UseAvailableExternallyLinkage) - ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); + CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable); } -void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD, - const ThunkInfo &Thunk) { - // We only want to do this when building with optimizations. - if (!CGM.getCodeGenOpts().OptimizationLevel) +void CodeGenVTables::maybeEmitThunkForVTable(GlobalDecl GD, + const ThunkInfo &Thunk) { + // If the ABI has key functions, only the TU with the key function should emit + // the thunk. However, we can allow inlining of thunks if we emit them with + // available_externally linkage together with vtables when optimizations are + // enabled. + if (CGM.getTarget().getCXXABI().hasKeyFunctions() && + !CGM.getCodeGenOpts().OptimizationLevel) return; // We can't emit thunks for member functions with incomplete types. @@ -482,7 +484,7 @@ void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD, cast<FunctionType>(MD->getType().getTypePtr()))) return; - EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true); + emitThunk(GD, Thunk, /*ForVTable=*/true); } void CodeGenVTables::EmitThunks(GlobalDecl GD) @@ -494,21 +496,18 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD) if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) return; + const VTableContext::ThunkInfoVectorTy *ThunkInfoVector; if (VFTContext.isValid()) { - // FIXME: This is a temporary solution to force generation of vftables in - // Microsoft ABI. Remove when we thread VFTableContext through CodeGen. - VFTContext->getVFPtrOffsets(MD->getParent()); - return; + ThunkInfoVector = VFTContext->getThunkInfo(GD); + } else { + ThunkInfoVector = VTContext.getThunkInfo(GD); } - const VTableContext::ThunkInfoVectorTy *ThunkInfoVector = - VTContext.getThunkInfo(MD); if (!ThunkInfoVector) return; for (unsigned I = 0, E = ThunkInfoVector->size(); I != E; ++I) - EmitThunk(GD, (*ThunkInfoVector)[I], - /*UseAvailableExternallyLinkage=*/false); + emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false); } llvm::Constant * @@ -603,7 +602,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, VTableThunks[NextVTableThunkIndex].first == I) { const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second; - MaybeEmitThunkAvailableExternally(GD, Thunk); + maybeEmitThunkForVTable(GD, Thunk); Init = CGM.GetAddrOfThunk(GD, Thunk); NextVTableThunkIndex++; diff --git a/clang/lib/CodeGen/CGVTables.h b/clang/lib/CodeGen/CGVTables.h index 9b95952e5e8..e17ad89c5e7 100644 --- a/clang/lib/CodeGen/CGVTables.h +++ b/clang/lib/CodeGen/CGVTables.h @@ -52,15 +52,12 @@ class CodeGenVTables { /// indices. SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; - /// EmitThunk - Emit a single thunk. - void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, - bool UseAvailableExternallyLinkage); - - /// MaybeEmitThunkAvailableExternally - Try to emit the given thunk with - /// available_externally linkage to allow for inlining of thunks. - /// This will be done iff optimizations are enabled and the member function - /// doesn't contain any incomplete types. - void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk); + /// emitThunk - Emit a single thunk. + void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable); + + /// maybeEmitThunkForVTable - Emit the given thunk for the vtable if needed by + /// the ABI. + void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk); public: /// CreateVTableInitializer - Create a vtable initializer for the given record diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index ecf5d577981..1e34a16dd99 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -173,6 +173,13 @@ public: void emitVirtualInheritanceTables(const CXXRecordDecl *RD); + void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) { + // Allow inlining of thunks by emitting them with available_externally + // linkage together with vtables when needed. + if (ForVTable) + Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); + } + StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; } StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 1d73b213b7d..7452c860d0b 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -173,8 +173,20 @@ public: CXXDtorType DtorType, SourceLocation CallLoc, llvm::Value *This); + void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD, + CallArgList &CallArgs) { + assert(GD.getDtorType() == Dtor_Deleting && + "Only deleting destructor thunks are available in this ABI"); + CallArgs.add(RValue::get(getStructorImplicitParamValue(CGF)), + CGM.getContext().IntTy); + } + void emitVirtualInheritanceTables(const CXXRecordDecl *RD); + void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) { + Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage); + } + void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, llvm::GlobalVariable *DeclPtr, bool PerformInit); |

