This is an archive of the discontinued LLVM Phabricator instance.

[GlobalOpt] Handle null check with global pointer variables
ClosedPublic

Authored by scui on May 18 2021, 12:16 PM.

Details

Summary

I'm working on extending the OptimizeGlobalAddressOfMalloc to handle some more general cases. One of the cases is the null check of global pointer variables. It is disabled with https://reviews.llvm.org/rGb7cd291c1542aee12c9e9fde6c411314a163a8ea. This PR is to reenable it while fixing the original problem reported. The fix is to set the store value correctly when creating store for the new created global init bool symbol.

Diff Detail

Event Timeline

scui created this revision.May 18 2021, 12:16 PM
scui requested review of this revision.May 18 2021, 12:16 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 18 2021, 12:16 PM
efriedma added inline comments.May 18 2021, 1:41 PM
llvm/lib/Transforms/IPO/GlobalOpt.cpp
684

Only loosely relevant to this patch, but are we really expecting anyone to call the result of malloc? Or am I misreading this?

703

Maybe explicitly note here that the rewriting code has special handling for this case.

Not sure this interacts correctly with AllUsesOfValueWillTrapIfNull recursion. It looks like the rewriting code can't handle an icmp of a bitcast/GEP/PHI of a load.

957

I think GV->hasInitializer() must be true here?

The equality comparison here makes me a little nervous, in case the way we analyze bitcasts changes in the future. SI->getValueOperand()->isNullValue() would probably be more clear anyway.

976

The code that was meant to support the icmp comparison case.

Sinking the load seems wrong; how do we know we aren't sinking it past a store?

scui updated this revision to Diff 347965.May 26 2021, 8:16 AM

This to address the review comments: (1) Refine the code to handle ICmpInst when checking if AllUsesOfValueWillTrapIfNull, (2) Consider the GlobalVariable is initialized when creating StoreInst for the global init bool symbol, (3) Remove the unsafe code sinking when transforming the ICmpInst.

scui added inline comments.May 26 2021, 8:23 AM
llvm/lib/Transforms/IPO/GlobalOpt.cpp
684

I think we can simply return false when passing to call argument, but I'll leave the code as it is for now. I'm going to extend the code for function call argument passing and function returns later in another patch,

703

Add restriction for operand 0 as the transformation only handles this kind of code pattern.

957

That's right, GV->hasInitializer() is true here. Modify the code as you suggested.

976

I agree, the sinking is not safe. Remove the comment, and the code sinking.

I'd like to see a little more test coverage, given all the different cases where the behavior of the transform changed.

llvm/lib/Transforms/IPO/GlobalOpt.cpp
957

Would !isa<Constant>(SI->getValueOperand())) work?

scui added a comment.Jun 7 2021, 8:34 PM

I'd like to see a little more test coverage, given all the different cases where the behavior of the transform changed.

Thanks for the suggestion. I'll come back to add some test cases when I get time later.

ormris removed a subscriber: ormris.Jun 11 2021, 2:45 PM
scui updated this revision to Diff 358713.Jul 14 2021, 1:16 PM

Add two test cases - one is to test the icmp condition with non-null value, the other is to test the disablement of the sinking of load to the icmp location.

scui added inline comments.Jul 14 2021, 1:18 PM
llvm/lib/Transforms/IPO/GlobalOpt.cpp
957

Would !isa<Constant>(SI->getValueOperand())) work?

This won't work, as the "GV = malloc()" instruction has been transformed to "GV = &NewGV", and "&NewGV" is a Constant.

New testcases look good.

llvm/lib/Transforms/IPO/GlobalOpt.cpp
980

Can we explicitly note here, for the signed compares, why it doesn't matter if the high bit of the global is set? The logic here isn't obvious.

990–991

UGE should fold to ConstantInt::getTrue(GV->getContext());

lkail added a subscriber: lkail.Jul 18 2021, 6:01 PM
scui added inline comments.Jul 19 2021, 12:49 PM
llvm/lib/Transforms/IPO/GlobalOpt.cpp
980

I'm not sure what comments I can add, as I actually don't know the logic here for the folding of the signed compares. The code has been like this from 2009 (the earliest I can found). Do you have any suggestions on how to handle all these signed compares?

990–991

Right.

efriedma added inline comments.Jul 19 2021, 1:13 PM
llvm/lib/Transforms/IPO/GlobalOpt.cpp
980

We could probably just reject icmps with a signed predicate; frontends won't normally generate signed pointer comparisons anyway.

Alternatively, you could use some tortured logic here: the program doesn't actually capture the pointer, and you can't do anything useful just knowing the sign of the pointer. So just pretend the sign bit isn't set.

scui added inline comments.Jul 20 2021, 7:47 AM
llvm/lib/Transforms/IPO/GlobalOpt.cpp
980

We could probably just reject icmps with a signed predicate; frontends won't normally generate signed pointer comparisons anyway.

Thank you very much for the suggestions. I'll take the safe approach - rejecting the signed comparisons. Hopefully it won't have much impact on real programs.

scui updated this revision to Diff 360159.Jul 20 2021, 8:51 AM

Exclude the signed null checks, and correct the handling of UGE.

This revision is now accepted and ready to land.Jul 20 2021, 8:53 AM
This revision was landed with ongoing or failed builds.Jul 20 2021, 9:28 AM
This revision was automatically updated to reflect the committed changes.