RFR: 8278228: C2: Improve identical back-to-back if elimination

Roland Westrelin roland at openjdk.java.net
Fri Dec 17 15:55:12 UTC 2021


On Fri, 17 Dec 2021 13:52:56 GMT, Roland Westrelin <roland at openjdk.org> wrote:

> C2 has had the ability to optimize:
> 
> (1)
> 
> if (some_condition) {
>   // body 1
> } else {
>   // body 2
> }
> if (some_condition) {
>   // body 3
> } else {
>   // body 4
> }
> 
> into:
> 
> (4)
> 
> if (some_condition) {
>   // body 1
>   // body 3
> } else {
>   // body 2
>   // body 4
> }
> 
> for a while.
> 
> This is achieved by the intermediate step:
> 
> (2)
> 
> if (some_condition) {
>   // body 1
>   some_condition2 = true;
> } else {
>   // body 2
>   some_condition2 = false;
> }
> if (some_condition2) {
>   // body 3
> } else {
>   // body 4
> }
> 
> which then allows the use of the exiting split if optimization. As a
> result, the graph is transformed to:
> 
> (3)
> 
> if (some_condition) {
>   // body 1
>   some_condition2 = true;
>   if (some_condition2) {
>     body3: // a Region here
>     // body3
>   } else {
>     goto body4;
>   }
> } else {
>   // body 2
>   some_condition2 = false;
>   if (some_condition2) {
>     goto body3;
>   } else {
>     body4:  // another Region here
>     // body4;
>   }
> }
> 
> and finally to (4) above.
> 
> Recently, 8275610 has shown that this can break if some_condition is a
> null check. If, say, body 3 has a control dependent CastPP, then when
> body 1 and body 3 are merged, the CastPP of body 3 doesn't become
> control dependent on the dominating if (because in step (2), the
> CastPP hides behind a Region). As a result, the CastPP loses its
> dependency on the null check.
> 
> After discussing this with Christian, it seemed this was caused by the
> way this transformation relies on split if: having custom code that
> wouldn't create Regions at body3 and body4 that are then optimized out
> would solve the problem. Anyway, after looking at the split if code,
> trying to figure out how to tease it apart in smaller steps and
> reusing some of them to build a new transformation, it seemed too
> complicated. So instead, I propose reusing split if in a slightly
> different way:
> 
> skip step (2) but perform split if anyway to obtain:
> 
> if (some_condition) {
>   // body 1
>   if (some_condition) {
>     body3: // Region1
>     // CastPP is here, control dependent on Region1
>     // body3
>   } else {
>     goto body4;
>   }
> } else {
>   // body 2
>  if (some_condition) {
>     goto body3;
>   } else {
>     body4:  // Region2
>     // body4;
>   }
> }
> 
> - A CastPP node would still be behind a Region. So next step, is to push
> control dependent nodes through Region1 and Region2:
> 
> if (some_condition) {
>   // body 1
>   if (some_condition) {
>     // A CastPP here
>     body3: // Region1
>     // body3
>   } else {
>     goto body4;
>   }
> } else {
>   // body 2
>  if (some_condition) {
>     // A CastPP here
>     goto body3;
>   } else {
>     body4:  // Region2
>     // body4;
>   }
> }
> 
> - And then call dominated_by() to optimize the dominated:
> 
> if (some_condition) {
> 
> in both branches of the dominating if (some_condition) {. That also
> causes the CastPP to become dependent on the dominating if.

I pushed a tweak to PhaseIdealLoop::push_pinned_nodes_thru_region() so it's applied only to nodes that will actually be rewired by dominated_by() and not all pinned nodes.

-------------

PR: https://git.openjdk.java.net/jdk/pull/6882


More information about the hotspot-compiler-dev mailing list