[llvm] r212337 - GlobalDCE: Delete available_externally initializers if it allows removing the value the initializer is referring to.

Benjamin Kramer benny.kra at gmail.com
Mon Jul 7 14:31:29 PDT 2014


On 07.07.2014, at 23:24, Reid Kleckner <rnk at google.com> wrote:

> Does GlobalDCE run late?  Deleting vftables will make it impossible to devirtualize.
> 
> My original thought for PR20182 was to handle it some time late during CodeGen, so that we get smaller object files at -O0.
> 
> That said, Clang shouldn't be emitting available_externally vftables at -O0 anyway.  It's just a waste of memory and compile time.  If we can fix Clang to avoid this, GlobalDCE might be the right place for this.

GlobalDCE is one of the last passes that runs before we go into codegen, any devirtualization should've happened earlier. Emitting available_externally globals at -O0 is indeed a waste of memory, we don't do this for itanium-style vtables either.

- Ben

> 
> On Fri, Jul 4, 2014 at 5:36 AM, Benjamin Kramer <benny.kra at googlemail.com> wrote:
> Author: d0k
> Date: Fri Jul  4 07:36:05 2014
> New Revision: 212337
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=212337&view=rev
> Log:
> GlobalDCE: Delete available_externally initializers if it allows removing the value the initializer is referring to.
> 
> This is useful for functions that are not actually available externally but
> referenced by a vtable of some kind. Clang emits functions like this for the MS
> ABI.
> 
> PR20182.
> 
> Modified:
>     llvm/trunk/lib/Transforms/IPO/GlobalDCE.cpp
>     llvm/trunk/test/Transforms/GlobalDCE/externally_available.ll
> 
> Modified: llvm/trunk/lib/Transforms/IPO/GlobalDCE.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/GlobalDCE.cpp?rev=212337&r1=212336&r2=212337&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/GlobalDCE.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/GlobalDCE.cpp Fri Jul  4 07:36:05 2014
> @@ -44,14 +44,19 @@ namespace {
>      bool runOnModule(Module &M) override;
> 
>    private:
> -    SmallPtrSet<GlobalValue*, 32> AliveGlobals;
> +    SmallPtrSet<Constant *, 32> AliveGlobals;
>      SmallPtrSet<Constant *, 8> SeenConstants;
> +    SmallPtrSet<GlobalVariable *, 8> DiscardableGlobalInitializers;
> 
>      /// GlobalIsNeeded - mark the specific global value as needed, and
>      /// recursively mark anything that it uses as also needed.
>      void GlobalIsNeeded(GlobalValue *GV);
>      void MarkUsedGlobalsAsNeeded(Constant *C);
> 
> +    /// \brief Checks if C is alive or is a ConstantExpr that refers to an alive
> +    /// value.
> +    bool ContainsUsedGlobal(Constant *C);
> +
>      bool RemoveUnusedGlobalValue(GlobalValue &GV);
>    };
>  }
> @@ -162,6 +167,19 @@ bool GlobalDCE::runOnModule(Module &M) {
>        I->setAliasee(nullptr);
>      }
> 
> +  // Look for available externally constants that we can turn into normal
> +  // externals by deleting their initalizers. This allows us to remove other
> +  // globals that are referenced by the initializer.
> +  if (!DiscardableGlobalInitializers.empty()) {
> +    for (GlobalVariable *GV : DiscardableGlobalInitializers) {
> +      if (!ContainsUsedGlobal(GV->getInitializer())) {
> +        GV->setInitializer(nullptr);
> +        GV->setLinkage(GlobalValue::ExternalLinkage);
> +        Changed = true;
> +      }
> +    }
> +  }
> +
>    if (!DeadFunctions.empty()) {
>      // Now that all interferences have been dropped, delete the actual objects
>      // themselves.
> @@ -209,8 +227,12 @@ void GlobalDCE::GlobalIsNeeded(GlobalVal
>    if (GlobalVariable *GV = dyn_cast<GlobalVariable>(G)) {
>      // If this is a global variable, we must make sure to add any global values
>      // referenced by the initializer to the alive set.
> -    if (GV->hasInitializer())
> -      MarkUsedGlobalsAsNeeded(GV->getInitializer());
> +    if (GV->hasInitializer()) {
> +      if (GV->hasAvailableExternallyLinkage())
> +        DiscardableGlobalInitializers.insert(GV);
> +      else
> +        MarkUsedGlobalsAsNeeded(GV->getInitializer());
> +    }
>    } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(G)) {
>      // The target of a global alias is needed.
>      MarkUsedGlobalsAsNeeded(GA->getAliasee());
> @@ -248,6 +270,21 @@ void GlobalDCE::MarkUsedGlobalsAsNeeded(
>    }
>  }
> 
> +bool GlobalDCE::ContainsUsedGlobal(Constant *C) {
> +  // C contains a used global If C is alive or we visited it while marking
> +  // values alive.
> +  if (AliveGlobals.count(C) || SeenConstants.count(C))
> +    return true;
> +
> +  // Now check all operands of a ConstantExpr.
> +  for (User::op_iterator I = C->op_begin(), E = C->op_end(); I != E; ++I) {
> +    Constant *Op = dyn_cast<Constant>(*I);
> +    if (Op && ContainsUsedGlobal(Op))
> +      return true;
> +  }
> +  return false;
> +}
> +
>  // RemoveUnusedGlobalValue - Loop over all of the uses of the specified
>  // GlobalValue, looking for the constant pointer ref that may be pointing to it.
>  // If found, check to see if the constant pointer ref is safe to destroy, and if
> 
> Modified: llvm/trunk/test/Transforms/GlobalDCE/externally_available.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalDCE/externally_available.ll?rev=212337&r1=212336&r2=212337&view=diff
> ==============================================================================
> --- llvm/trunk/test/Transforms/GlobalDCE/externally_available.ll (original)
> +++ llvm/trunk/test/Transforms/GlobalDCE/externally_available.ll Fri Jul  4 07:36:05 2014
> @@ -1,10 +1,43 @@
> -; RUN: opt < %s -globaldce -S | not grep test_
> +; RUN: opt < %s -globaldce -S | FileCheck %s
> 
>  ; test_function should not be emitted to the .s file.
> +; CHECK-NOT: @test_function
>  define available_externally i32 @test_function() {
>    ret i32 4
>  }
> 
>  ; test_global should not be emitted to the .s file.
> +; CHECK-NOT: @test_global
>  @test_global = available_externally global i32 4
> 
> +; CHECK: @x = external constant void ()*
> + at x = available_externally constant void()* @f
> +; CHECK: @y = external constant i32
> + at y = available_externally constant i32 ptrtoint (void()* @g to i32)
> +; @h is still alive, so don't remove the initializer too eagerly.
> +; CHECK: @z = available_externally constant i8 ptrtoint (void (i8)* @h to i8)
> + at z = available_externally constant i8 ptrtoint (void(i8)* @h to i8)
> +
> +; CHECK-NOT: @f
> +define linkonce_odr void @f() {
> +  ret void
> +}
> +
> +; CHECK-NOT: @g
> +define linkonce_odr void @g() {
> +  ret void
> +}
> +
> +; CHECK: define linkonce_odr void @h
> +define linkonce_odr void @h(i8) {
> +  ret void
> +}
> +
> +define i32 @main() {
> +  %f = load void()** @x
> +  call void %f()
> +  %g = load i32* @y
> +  %h = load i8* @z
> +  call void @h(i8 %h)
> +  ret i32 %g
> +}
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> 





More information about the llvm-commits mailing list