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

Reid Kleckner rnk at google.com
Mon Jul 7 14:24:47 PDT 2014


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.


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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140707/bddffd77/attachment.html>


More information about the llvm-commits mailing list