This is an archive of the discontinued LLVM Phabricator instance.

Remove dangling BlockAddresses in GlobalDCE
AbandonedPublic

Authored by bruno on Aug 15 2014, 10:56 AM.

Details

Reviewers
None
Summary

Whenever globaldce delete globals vars, it updates their initializers to nullptr and leave underlying constants to be cleaned up later by its uses. However, initializers containing dangling BlockAddresses are never removed because its uses (Functions and Basic Blocks) may still be alive. The presence of dead BlockAddress after globaldce is a bug - the target basic block reference count is never updated - and also prevents other optimizations; e.g. simplifycfg to merge blocks.

This patch fix this issue by removing dead BlockAddresses.

Diff Detail

Event Timeline

bruno updated this revision to Diff 12563.Aug 15 2014, 10:56 AM
bruno retitled this revision from to Remove dangling BlockAddresses in GlobalDCE.
bruno updated this object.
bruno edited the test plan for this revision. (Show Details)
bruno set the repository for this revision to rL LLVM.
bruno added subscribers: Unknown Object (MLST), bob.wilson.

+; RUN: opt -O2 -simplifycfg -inline -early-cse -S < %s | FileCheck %s

Why do you need all these passes? You should be able to use just "
-simplifycfg -inline", no?

bruno added a comment.Aug 20 2014, 1:26 PM

Not really. But anyway, this could be indeed improved, the minimum would be:
"opt -ipsccp -instcombine -jump-threading -globaldce -simplifycfg -inline"

why? The patch only changes GlobalDCE.cpp. Why do you need to run
passes before it?

bruno added a comment.Aug 20 2014, 2:07 PM

Without this patch, GlobalDCE won't properly clean up blockaddress references, leaving BBs ref counts without proper update. One way to test that such ref counts are updated is to expose the module to further optimizations that actually use this refcount; simplifycfg in this example.
Other passes need to be executed before GlobalDCE to trigger the removal of @foo.addrs.

bruno updated this revision to Diff 12759.Aug 21 2014, 5:16 AM

I was stuck with the original bug testcase, this is indeed much smaller and simple :-)
Attached a new patch version, thanks Rafael!

Ok to commit?

One sec, let me review the code itself now that I understand the test :-)

bruno updated this revision to Diff 12854.Aug 22 2014, 1:07 PM

Hi Rafael,

I've tried this path before and the problem I found is exactly what you fix with:

+ if (isa<ConstantInt>(C) || isa<ConstantFP>(C)) // why?
+ return false;
+

I->setInitializer(nullptr) will actually destroy the constant in ConstantInt and ConstantFP and later on there's nothing there for destroyConstant to destroy.

This is not the case for other underlying constant types - which you can safely keep track by saving the initializer and deleting it later. I prefer your approach, but I suggest we do not change isSafeToDestroyConstant, but check this condition before. See the attached patch.

bruno abandoned this revision.Jul 15 2015, 10:52 AM