| /* |
| * 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; |
| } |
| } |
| } |
| } |
| } |
| |