File: TestUnswitchCloneSkeletonPredicates.java

package info (click to toggle)
openjdk-11 11.0.24%2B8-2~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 780,008 kB
  • sloc: java: 5,197,087; xml: 1,192,267; cpp: 1,138,204; ansic: 462,088; javascript: 162,551; sh: 16,713; objc: 13,719; python: 4,757; asm: 3,570; makefile: 2,943; perl: 357; awk: 351; sed: 172; jsp: 24; csh: 3
file content (225 lines) | stat: -rw-r--r-- 9,319 bytes parent folder | download | duplicates (14)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*
 * Copyright (c) 2020, 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 8253644
 * @summary Test the complete cloning of skeleton predicates to unswitched loops as done when cloning them to the main loop.
 * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.loopopts.TestUnswitchCloneSkeletonPredicates::*
 *                   compiler.loopopts.TestUnswitchCloneSkeletonPredicates
 * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:-PartialPeelLoop -XX:CompileCommand=compileonly,compiler.loopopts.TestUnswitchCloneSkeletonPredicates::*
 *                   compiler.loopopts.TestUnswitchCloneSkeletonPredicates
 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-PartialPeelLoop compiler.loopopts.TestUnswitchCloneSkeletonPredicates
 */
package compiler.loopopts;

public class TestUnswitchCloneSkeletonPredicates {

    static int x = 0;
    static int y = 20;
    static int intArr[] = new int[21000];
    static int idx = 0;
    static boolean bFld = true;
    static int iFld = 20;
    static int iFld2 = 0 ;
    static int iArrFld[] = new int[50];
    static float fArrFld[] = new float[50];


    // Only triggers with -XX:-PartialPeelLoop
    /*
     * The inner loop is unswitched on (1) which creates a fast and a slow loop that both have (1) removed and instead
     * (1) is executed before the loop at (3). With the SplitIf optimization we find that (3) dominates (2) in both loops.
     *
     * As a result, we can remove (2) from both loops. This, however, has an influence on how the loop tree is built.
     * Before the SplitIf optimization, the loop tree looks like this:
     * Loop: N0/N0  has_sfpt
     *   Loop: N338/N314  limit_check profile_predicated predicated counted [0,100),+1 (2 iters)  has_sfpt
     *     Loop: N459/N458  profile_predicated predicated counted [0,10000),+1 (5271 iters)  has_sfpt (slow loop)
     *     Loop: N343/N267  profile_predicated predicated counted [0,10000),+1 (5271 iters)  has_sfpt (fast loop)
     *
     * Both unswitched loop have a copy of the skeleton predicate If node that share the same Opaque4 node with its inputs.
     * The inner loop is never exited normally due to always returning on (4). This means that the branch that exits the
     * loop on the loop limit check is never taken and has an uncommon trap. Nevertheless, the loop building algorithm still
     * identifies the fast and the slow loop as children of N338 because of the condition (2) over which the loop is left.
     * However, after the above mentioned SplitIf optimization the condition (2) is removed from both loops. As a result,
     * the slow loops (N459) is always exited immediately (x == 100 holds) because the break is executed on the first
     * iteration of the loop. The loop can be removed (but these nodes are still part of the parent loop N338). The fast loop
     * (N343), however, is now never exited normally and always returns on the 9800th iteration over (4). The normal loop exit
     * over the loop limit check is never taken (uncommon trap). Due to the last loop exit (2) being removed, N343 is no longer
     * recognized as a child loop of N338 due to not having a backedge to the parent loop. The loop tree looks like this:
     * Loop: N0/N0  has_sfpt
     *   Loop: N338/N314  limit_check profile_predicated predicated counted [0,100),+1 (2 iters)  has_sfpt
     *   Loop: N343/N267  profile_predicated predicated counted [0,10000),+1 (5274 iters)  has_sfpt
     *
     * As a next step, the original parent loop N338 is peeled. The fast and the slow loop still both share skeleton Opaque4 bool
     * nodes with all its inputs nodes up to and including the OpaqueLoopInit/Stride nodes. These skeleton predicates are still there
     * even though the slow loop N459 could have been removed (the Opaque4 nodes are only removed after loop opts). Let's look at one
     * of the skeleton If nodes for the fast loop that uses such a Opaque4 node. The skeleton 'If' is no longer part of the original
     * parent loop and is therefore not peeled. But now we need some phi nodes to select the correct nodes either from the peeled
     * iteration or from N338 for this skeleton If of the fast loop. This is done in PhaseIdealLoop::clone_iff() which creates
     * a new Opaque4 node together with new Bool and Cmp nodes and then inserts some phi nodes to do the selection.
     *
     * When afterwards creating pre/main/post loops for the fast loop (N343) that is no child anymore, we find these phi nodes on the
     * path to the OpaqueLoopInit/Stride nodes which lets the assertion PhaseIdealLoop::skeleton_predicate_has_opaque() fail. These
     * phi nodes on the path to the OpaqueLoopInit/Stride nodes are unexpected.
     *
     * The solution to this problem is to clone the skeleton predicates completely, including clones of all nodes up to and including
     * the OpaqueLoopInit/Stride nodes (similar to what is done when copying skeleton predicates to the main loop) instead of just
     * sharing Opaque4 nodes.
     */
    public static int test1() {
      int i = 0;
      while (i < 100) {
          int j = 0;
          // (3) <new unswitch condition>
          while (j < 10000)  {
              if (x == 100) { // (1) Loop is unswitched on this condition -> condition shared with (2)
                  y = 34;
              }

              intArr[idx] = 34;
              intArr[2*j + 35] = 45;

              if (x == 100) { // (2)
                  y = 35;
                  break;
              }
              if (j == 9800) { // (4)
                  return 2;
              }
              j++;
          }
          i++;
          intArr[i] = 45;
      }
      return y;
    }

    // Only triggers with -XX:-PartialPeelLoop
    public static int test2() {
      int i = 0;
      while (i < 100) {
          int j = 0;
          while (j < 10000)  {
              if (x == 100) {
                  y = 34;
              }

              intArr[2*j + 35] = 45;

              if (x == 100) {
                  y = 35;
                  break;
              }
              if (j == 9800) {
                  return 2;
              }
              j++;
          }
          i++;
          intArr[i] = 45;
      }
      return y;
    }

    // Only triggers with -XX:-PartialPeelLoop
    public static int test3() {
      int i = 0;
      while (i < 100) {
          int j = 0;
          while (j < 10000)  {
              if (x == 100) {
                  y = 34;
              }

              intArr[idx] = 34;
              intArr[2*j + 35] = 45;

              if (x == 100) {
                  y = 35;
                  break;
              }
              if (j == 9800) {
                  return 2;
              }
              j++;
          }
          i++;
      }
      return y;
}

    // Test that has two loop headers for a single loop (limitation of type flow, see JDK-8255663)
    // which also triggers the assertion failure of this bug.
    public static void test4() {
        int unused = 500; // Required, even though unused
        boolean b = true;
        int i = 1;
        while (++i < 35) {
            iArrFld[i] = 6;
            switch (iFld2) {
            case 40:
                if (b) {
                    continue;
                }
                b = false;
                break;
            }
        }
    }

    // Test that has two loop headers for a single loop (limitation of type flow, see JDK-8255663)
    // which also triggers the assertion failure of this bug. Only triggers with -XX:-PartialPeelLoop.
    public static void test5() {
        int j = 50;
        int i = 1;
        while (++i < 40) {
            j = 5;
            do {
                fArrFld[i] = 46;
                iFld = 5;
                if (bFld) break;
            } while (++j < 5);
            j = 2;
            do {
                try {
                    iFld = 56;
                } catch (ArithmeticException a_e) {}
                if (bFld) break;
            } while (++j < 2);
        }
    }

    public static void main(String[] strArr) {
        for (int i = 0; i < 5000; i++) {
            test1();
            test2();
            test3();
            x++;
            x = x % 106;
        }
        test4();
        test5();
    }
}