/* * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * @test * @bug 8290850 * @summary Test cloning of pinned phi input nodes in create_new_if_for_predicate(). * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.loopopts.TestCreateNewIfForPredicateCloning::* * compiler.loopopts.TestCreateNewIfForPredicateCloning */ package compiler.loopopts; public class TestCreateNewIfForPredicateCloning { static int iFld, iFld2, iFld3, nonZero = 2, nonZero2 = 3; static boolean bFld = true, bFld2 = false; static int[] iArrFld = new int[100]; public static void main(String[] args) { try { testUnswitching(); testLoopPredicatation(); testLoopPredicatationComplex(); testUnswitchingWithPredicates(); testUnswitchingWithPredicatesDiv(); testFuzzer1(); testFuzzer2(); testFuzzer3(); } catch (Exception e) { // Expected } } // Test case for the already fixed problem in 8271954: Calling create_new_if_for_predicate in // clone_predicate_to_unswitched_loop(). This does not crash anymore. But still use it as sanity test here with the // new fix. static void testUnswitching() { int x = 3; // Block to delay precise type information to after CCP. int limit = 2; int constantAfterCCP = 2; for (; limit < 4; limit *= 2); for (int i = 2; i < limit; i++) { constantAfterCCP = 6; // Only known to be constant 6 after CCP. } for (int i = 51; i > 9; i -= 3) { if (bFld) { x *= 6; } // (1) after unswitching: // if (bFld) {...} // Since we have a back to back if now with the same condition, we can merge them together by using the // split if optimization. That will create phi nodes for the UCT regions. Whenever we then call // create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap // projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But // in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon // trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph: // the LCA of the old and new uncommon projection would be above the early control (control input of the // CastII nodes). // // 8271954 fixes this when calling create_new_if_for_predicate() in // clone_predicate_to_unswitched_loop(). x -= 5; for (int j = 1; j < 10; j++) { if (bFld) { // Unswitching on bFld such that this condition is moved to (1) continue; } x = 34; // Redefine x such that x is only used in UCT before this loop after split if. int y = 34; if (constantAfterCCP == 2) { // Known to be never taken after CCP, so y will always be 34. y = 35; } if (y == iFld) { // Folds to 34 == iFld after CCP and trigger another unswitching continue; } iFld3 = 34; // Just another statement sucht that the second round of unswitching is done } } // This loop is only needed to delay the second round of unswitching for the inner loop above. for (int i = 0; i < iArrFld.length; i++) { iArrFld[i] = 3; } } // Similar to testUnswitching() but we are calling create_new_if_for_predicate in Loop Predication for: // - Creating hoised range check predicate and skeleton predicate // - Creating invariant check predicate // which leads to a crash. static void testLoopPredicatation() { int x = 3; // Block to delay precise type information to after CCP. int limit = 2; int constantAfterCCP = 2; for (; limit < 4; limit *= 2); for (int i = 2; i < limit; i++) { constantAfterCCP = 6; // Only known to be constant 6 after CCP. } for (int i = 51; i > 9; i -= 3) { if (bFld) { x *= 6; } // (1) after unswitching: // if (bFld) {...} // Since we have a back to back if now with the same condition, we can merge them together by using the // split if optimization. That will create phi nodes for the UCT regions. Whenever we then call // create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap // projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But // in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon // trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph: // the LCA of the old and new uncommon projection would be above the early control (control input of the // CastII nodes). x -= 5; for (int j = 1; j < 10; j++) { if (bFld) { // Unswitching on bFld such that this condition is moved to (1) continue; } x = 34; // Redefine x such that x is only used in UCT before this loop after split if. int y = iArrFld[j]; // Range check and null check will be hoisted after Unswitching and split if. } } // This loop is only needed to delay the second round of unswitching for the inner loop above. for (int i = 0; i < iArrFld.length; i++) { iArrFld[i] = 3; } } // Similar to testLoopPredicatation() but we are adding some computations for x such that we sink more nodes which // need to be cloned when calling create_new_if_for_predicate(). static void testLoopPredicatationComplex() { int x = 3; // Block to delay precise type information to after CCP. int limit = 2; int constantAfterCCP = 2; for (; limit < 4; limit *= 2); for (int i = 2; i < limit; i++) { constantAfterCCP = 6; // Only known to be constant 6 after CCP. } for (int i = 51; i > 9; i -= 3) { if (bFld) { x *= 6; } // (1) after unswitching: // if (bFld) {...} // Since we have a back to back if now with the same condition, we can merge them together by using the // split if optimization. That will create phi nodes for the UCT regions. Whenever we then call // create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap // projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But // in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon // trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph: // the LCA of the old and new uncommon projection would be above the early control (control input of the // CastII nodes). x -= 5; // Add some more computations such that more nodes are sunk and therefore more nodes need to be cloned in // create_new_if_for_predicate(). double d1 = 5 + (double) x; x = (int)((d1 + iFld2) - (d1 + iFld)); d1 = 5 + (double) x; x = (int)((d1 + iFld2) - (d1 + iFld)); d1 = 5 + (double) x; x = (int)((d1 + iFld2) - (d1 + iFld)); d1 = 5 + (double) x; x = (int)((d1 + iFld2) - (d1 + iFld)); d1 = 5 + (double) x; x = (int)((d1 + iFld2) - (d1 + iFld)); d1 = 5 + (double) x; x = (int)((d1 + iFld2) - (d1 + iFld)); for (int j = 1; j < 10; j++) { if (bFld) { // Unswitching on bFld such that this condition is moved to (1) continue; } x = 34; // Redefine x such that x is only used in UCT before this loop after split if. int y = iArrFld[j]; // Range check and null check will be hoisted after Unswitching and split if. } } // This loop is only needed to delay the second round of unswitching for the inner loop above. for (int i = 0; i < iArrFld.length; i++) { iArrFld[i] = 3; } } // Combination of testUnswitching() and testLoopPredicatation(): After creating predicates in loop predication, // we perform another round of loop unswitching where we additionally call create_new_if_for_predicate in // clone_skeleton_predicate_for_unswitched_loops() which currently leads to a crash. static void testUnswitchingWithPredicates() { int x = 3; if (iArrFld == null) { // Makes sure to get rid of null check for iArrFld to only create range check predicate return; } // Block to delay precise type information to after CCP. int limit = 2; int constantAfterCCP = 2; for (; limit < 4; limit *= 2); for (int i = 2; i < limit; i++) { constantAfterCCP = 6; // Only known to be constant 6 after CCP. } for (int i = 51; i > 9; i -= 3) { if (bFld) { x *= 6; } // (1) after unswitching: // if (bFld) {...} // Since we have a back to back if now with the same condition, we can merge them together by using the // split if optimization. That will create phi nodes for the UCT regions. Whenever we then call // create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap // projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But // in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon // trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph: // the LCA of the old and new uncommon projection would be above the early control (control input of the // CastII nodes). x -= 5; for (int j = 1; j < 10; j++) { if (bFld) { // Unswitching on bFld such that this condition is moved to (1) continue; } x = 34; // Redefine x such that x is only used in UCT before this loop after split if. int z = iArrFld[j]; // Range check and null check will be hoisted after Unswitching and split if. int y = 34; if (constantAfterCCP == 2) { // Known to be never taken after CCP, so y will always be 34. y = 35; } if (y == iFld) { // Folds to 34 == iFld after CCP and trigger another unswitching continue; } iFld3 = 34; // Just another statement sucht that the second round of unswitching is done } } // This loop is only needed to delay the second round of unswitching for the inner loop above. for (int i = 0; i < iArrFld.length; i++) { iArrFld[i] = 3; } } // Same as testUnswitchingWithPredicates() but with a DivI node which has a control input which needs // to be rewired as well. static void testUnswitchingWithPredicatesDiv() { int x = 3; if (iArrFld == null) { // Makes sure to get rid of null check for iArrFld to only create range check predicate return; } // Block to delay precise type information to after CCP. int limit = 2; int constantAfterCCP = 2; for (; limit < 4; limit *= 2); for (int i = 2; i < limit; i++) { constantAfterCCP = 6; // Only known to be constant 6 after CCP. } for (int i = 51; i > 9; i -= 3) { if (bFld) { x *= 6; } // (1) after unswitching: // if (bFld) {...} // Since we have a back to back if now with the same condition, we can merge them together by using the // split if optimization. That will create phi nodes for the UCT regions. Whenever we then call // create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap // projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But // in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon // trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph: // the LCA of the old and new uncommon projection would be above the early control (control input of the // CastII nodes). x -= 5; double d = 5.5f + (double) x; int a = (int)d; x = (a / nonZero) - (a / nonZero2); for (int j = 1; j < 10; j++) { if (bFld) { // Unswitching on bFld such that this condition is moved to (1) continue; } x = 34; // Redefine x such that x is only used in UCT before this loop after split if. int z = iArrFld[j]; // Range check and null check will be hoisted after Unswitching and split if. int y = 34; if (constantAfterCCP == 2) { // Known to be never taken after CCP, so y will always be 34. y = 35; } if (y == iFld) { // Folds to 34 == iFld after CCP and trigger another unswitching continue; } iFld3 = 34; // Just another statement sucht that the second round of unswitching is done } } // This loop is only needed to delay the second round of unswitching for the inner loop above. for (int i = 0; i < iArrFld.length; i++) { iArrFld[i] = 3; } } static void testFuzzer1() { int x = 0; int[] iArr = new int[400]; boolean b = true; long[] lArr = new long[400]; for (long l1 : lArr) { for (int i = 63; i > 1; i -= 3) { for (int j = 1; j < 4; j++) { if (!b) { x -= 5; } } for (int j = 1; j < 4; j++) { if (!b) { x = iArr[j]; } if (i == 0) { l1 += 5; } } } } } static void testFuzzer2() { int i, i1, i17 = 6, i18; short s1; boolean b2 = true; float f3; long lArr[][] = new long[400][]; byte byArrFld[] = new byte[4]; i = 1; do { for (i1 = 14; 6 < i1; i1--) ; i17 -= i18 = 1; while (i18 < 4) { i18 <<= i17 = 2; switch (i1) { case 114: s1 = byArrFld[1]; break; case 116: lArr[1][i18] = iFld; if (b2) continue; case 118: f3 = iFld; } } i++; } while (i < 10000); } static void testFuzzer3() { int x = 8; int y = 4; for (int i : iArrFld) { x += 2; if (bFld) { x = 3; } else { y = 2; } for (int j = 0; j < 10; j++) { x = 0; y += 5; if (!bFld) { iArrFld[1] = 5; } } } } }