r225570 - Don't emit implicit template instantiations eagerly (PR21718)

Rafael EspĂ­ndola rafael.espindola at gmail.com
Mon Jan 12 11:40:28 PST 2015


This is awesome. A nice step towards fixing pr16187 :-)

On 9 January 2015 at 20:19, Hans Wennborg <hans at hanshq.net> wrote:
> Author: hans
> Date: Fri Jan  9 19:19:48 2015
> New Revision: 225570
>
> URL: http://llvm.org/viewvc/llvm-project?rev=225570&view=rev
> Log:
> Don't emit implicit template instantiations eagerly (PR21718)
>
> Their linkage can change if they are later explicitly instantiated. We would
> previously emit such functions eagerly (as opposed to lazily on first use) if
> they have a 'dllexport' or 'used' attribute, and fail an assert when hitting the
> explicit instantiation.
>
> This is achieved by replacing the old CodeGenModule::MayDeferGeneration() method
> with two new ones: MustBeEmitted() and MayBeEmittedEagerly().
>
> Differential Revision: http://reviews.llvm.org/D6674
>
> Modified:
>     cfe/trunk/lib/CodeGen/CodeGenModule.cpp
>     cfe/trunk/lib/CodeGen/CodeGenModule.h
>     cfe/trunk/test/CodeGenCXX/dllexport.cpp
>     cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=225570&r1=225569&r2=225570&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Jan  9 19:19:48 2015
> @@ -1102,14 +1102,18 @@ void CodeGenModule::EmitDeferred() {
>      llvm::GlobalValue *GV = G.GV;
>      DeferredDeclsToEmit.pop_back();
>
> -    assert(GV == GetGlobalValue(getMangledName(D)));
> +    assert(!GV || GV == GetGlobalValue(getMangledName(D)));
> +    if (!GV)
> +      GV = GetGlobalValue(getMangledName(D));
> +
> +
>      // Check to see if we've already emitted this.  This is necessary
>      // for a couple of reasons: first, decls can end up in the
>      // deferred-decls queue multiple times, and second, decls can end
>      // up with definitions in unusual ways (e.g. by an extern inline
>      // function acquiring a strong function redefinition).  Just
>      // ignore these cases.
> -    if(!GV->isDeclaration())
> +    if (GV && !GV->isDeclaration())
>        continue;
>
>      // Otherwise, emit the definition and move on to the next one.
> @@ -1234,12 +1238,22 @@ bool CodeGenModule::isInSanitizerBlackli
>    return false;
>  }
>
> -bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
> +bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
>    // Never defer when EmitAllDecls is specified.
>    if (LangOpts.EmitAllDecls)
> -    return false;
> +    return true;
> +
> +  return getContext().DeclMustBeEmitted(Global);
> +}
>
> -  return !getContext().DeclMustBeEmitted(Global);
> +bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
> +  if (const auto *FD = dyn_cast<FunctionDecl>(Global))
> +    if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
> +      // Implicit template instantiations may change linkage if they are later
> +      // explicitly instantiated, so they should not be emitted eagerly.
> +      return false;
> +
> +  return true;
>  }
>
>  llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor(
> @@ -1348,9 +1362,10 @@ void CodeGenModule::EmitGlobal(GlobalDec
>        return;
>    }
>
> -  // Defer code generation when possible if this is a static definition, inline
> -  // function etc.  These we only want to emit if they are used.
> -  if (!MayDeferGeneration(Global)) {
> +  // Defer code generation to first use when possible, e.g. if this is an inline
> +  // function. If the global must always be emitted, do it eagerly if possible
> +  // to benefit from cache locality.
> +  if (MustBeEmitted(Global) && MayBeEmittedEagerly(Global)) {
>      // Emit the definition if it can't be deferred.
>      EmitGlobalDefinition(GD);
>      return;
> @@ -1363,13 +1378,16 @@ void CodeGenModule::EmitGlobal(GlobalDec
>      DelayedCXXInitPosition[Global] = CXXGlobalInits.size();
>      CXXGlobalInits.push_back(nullptr);
>    }
> -
> -  // If the value has already been used, add it directly to the
> -  // DeferredDeclsToEmit list.
> +
>    StringRef MangledName = getMangledName(GD);
> -  if (llvm::GlobalValue *GV = GetGlobalValue(MangledName))
> +  if (llvm::GlobalValue *GV = GetGlobalValue(MangledName)) {
> +    // The value has already been used and should therefore be emitted.
>      addDeferredDeclToEmit(GV, GD);
> -  else {
> +  } else if (MustBeEmitted(Global)) {
> +    // The value must be emitted, but cannot be emitted eagerly.
> +    assert(!MayBeEmittedEagerly(Global));
> +    addDeferredDeclToEmit(/*GV=*/nullptr, GD);
> +  } else {
>      // Otherwise, remember that we saw a deferred decl with this name.  The
>      // first use of the mangled name will cause it to move into
>      // DeferredDeclsToEmit.
> @@ -1843,7 +1861,7 @@ CodeGenModule::CreateRuntimeVariable(llv
>  void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
>    assert(!D->getInit() && "Cannot emit definite definitions here!");
>
> -  if (MayDeferGeneration(D)) {
> +  if (!MustBeEmitted(D)) {
>      // If we have not seen a reference to this variable yet, place it
>      // into the deferred declarations table to be emitted if needed
>      // later.
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=225570&r1=225569&r2=225570&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Fri Jan  9 19:19:48 2015
> @@ -1200,9 +1200,15 @@ private:
>    /// Emits the initializer for a uuidof string.
>    llvm::Constant *EmitUuidofInitializer(StringRef uuidstr);
>
> -  /// Determine if the given decl can be emitted lazily; this is only relevant
> -  /// for definitions. The given decl must be either a function or var decl.
> -  bool MayDeferGeneration(const ValueDecl *D);
> +  /// Determine whether the definition must be emitted; if this returns \c
> +  /// false, the definition can be emitted lazily if it's used.
> +  bool MustBeEmitted(const ValueDecl *D);
> +
> +  /// Determine whether the definition can be emitted eagerly, or should be
> +  /// delayed until the end of the translation unit. This is relevant for
> +  /// definitions whose linkage can change, e.g. implicit function instantions
> +  /// which may later be explicitly instantiated.
> +  bool MayBeEmittedEagerly(const ValueDecl *D);
>
>    /// Check whether we can use a "simpler", more core exceptions personality
>    /// function.
>
> Modified: cfe/trunk/test/CodeGenCXX/dllexport.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllexport.cpp?rev=225570&r1=225569&r2=225570&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/dllexport.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/dllexport.cpp Fri Jan  9 19:19:48 2015
> @@ -615,6 +615,21 @@ NonExportedBaseClass::~NonExportedBaseCl
>  struct __declspec(dllexport) ExportedDerivedClass : NonExportedBaseClass {};
>  // M32-DAG: weak_odr dllexport x86_thiscallcc void @"\01??1ExportedDerivedClass@@UAE at XZ"
>
> +// Do not assert about generating code for constexpr functions twice during explicit instantiation (PR21718).
> +template <typename T> struct ExplicitInstConstexprMembers {
> +  // Copy assignment operator
> +  // M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable(1) %struct.ExplicitInstConstexprMembers* @"\01??4?$ExplicitInstConstexprMembers at X@@QAEAAU0 at ABU0@@Z"
> +
> +  constexpr ExplicitInstConstexprMembers() {}
> +  // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstConstexprMembers* @"\01??0?$ExplicitInstConstexprMembers at X@@QAE at XZ"
> +
> +  ExplicitInstConstexprMembers(const ExplicitInstConstexprMembers&) = default;
> +  // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstConstexprMembers* @"\01??0?$ExplicitInstConstexprMembers at X@@QAE at ABU0@@Z"
> +
> +  constexpr int f() const { return 42; }
> +  // M32-DAG: define weak_odr dllexport x86_thiscallcc i32 @"\01?f@?$ExplicitInstConstexprMembers at X@@QBEHXZ"
> +};
> +template struct __declspec(dllexport) ExplicitInstConstexprMembers<void>;
>
>  //===----------------------------------------------------------------------===//
>  // Classes with template base classes
>
> Modified: cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp?rev=225570&r1=225569&r2=225570&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp Fri Jan  9 19:19:48 2015
> @@ -90,6 +90,19 @@ namespace LateInstantiation {
>    // CHECK-OPT: define available_externally i32 @_ZN17LateInstantiation1fIiEEiv(
>  }
>
> +namespace PR21718 {
> +// The linkage of a used constexpr member function can change from linkonce_odr
> +// to weak_odr after explicit instantiation without errors about defining the
> +// same function twice.
> +template <typename T>
> +struct S {
> +// CHECK-LABEL: define weak_odr i32 @_ZN7PR217181SIiE1fEv
> +  __attribute__((used)) constexpr int f() { return 0; }
> +};
> +int g() { return S<int>().f(); }
> +template struct S<int>;
> +}
> +
>  // Check that we emit definitions from explicit instantiations even when they
>  // occur prior to the definition itself.
>  template <typename T> struct S {
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list