1 /*
2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8078262 8177095
27  * @summary Tests correct dominator information after loop peeling.
28  *
29  * @run main/othervm -Xcomp
30  *      -XX:CompileCommand=compileonly,compiler.loopopts.TestLoopPeeling::test*
31  *      compiler.loopopts.TestLoopPeeling
32  */
33 
34 package compiler.loopopts;
35 
36 public class TestLoopPeeling {
37 
38     public int[] array = new int[100];
39 
main(String args[])40     public static void main(String args[]) {
41         TestLoopPeeling test = new TestLoopPeeling();
42         try {
43             test.testArrayAccess1(0, 1);
44             test.testArrayAccess2(0);
45             test.testArrayAccess3(0, false);
46             test.testArrayAllocation(0, 1);
47         } catch (Exception e) {
48             // Ignore exceptions
49         }
50     }
51 
testArrayAccess1(int index, int inc)52     public void testArrayAccess1(int index, int inc) {
53         int storeIndex = -1;
54 
55         for (; index < 10; index += inc) {
56             // This loop invariant check triggers loop peeling because it can
57             // be moved out of the loop (see 'IdealLoopTree::policy_peeling').
58             if (inc == 42) return;
59 
60             // This loop variant usage of LShiftL( ConvI2L( Phi(storeIndex) ) )
61             // prevents the split if optimization that would otherwise clone the
62             // LShiftL and ConvI2L nodes and assign them to their corresponding array
63             // address computation (see 'PhaseIdealLoop::split_if_with_blocks_post').
64             if (storeIndex > 0 && array[storeIndex] == 42) return;
65 
66             if (index == 42) {
67                 // This store and the corresponding range check are moved out of the
68                 // loop and both used after main loop and the peeled iteration exit.
69                 // For the peeled iteration, storeIndex is always -1 and the ConvI2L
70                 // is replaced by TOP. However, the range check is not folded because
71                 // we don't do the split if optimization in PhaseIdealLoop2.
72                 // As a result, we have a (dead) control path from the peeled iteration
73                 // to the StoreI but the data path is removed.
74                 array[storeIndex] = 1;
75                 return;
76             }
77 
78             storeIndex++;
79         }
80     }
81 
testArrayAccess2(int index)82     public int testArrayAccess2(int index) {
83         // Load1 and the corresponding range check are moved out of the loop
84         // and both are used after the main loop and the peeled iteration exit.
85         // For the peeled iteration, storeIndex is always Integer.MIN_VALUE and
86         // for the main loop it is 0. Hence, the merging phi has type int:<=0.
87         // Load1 reads the array at index ConvI2L(CastII(AddI(storeIndex, -1)))
88         // where the CastII is range check dependent and has type int:>=0.
89         // The CastII gets pushed through the AddI and its type is changed to int:>=1
90         // which does not overlap with the input type of storeIndex (int:<=0).
91         // The CastII is replaced by TOP causing a cascade of other eliminations.
92         // Since the control path through the range check CmpU(AddI(storeIndex, -1))
93         // is not eliminated, the graph is in a corrupted state. We fail once we merge
94         // with the result of Load2 because we get data from a non-dominating region.
95         int storeIndex = Integer.MIN_VALUE;
96         for (; index < 10; ++index) {
97             if (index == 42) {
98                 return array[storeIndex-1]; // Load1
99             }
100             storeIndex = 0;
101         }
102         return array[42]; // Load2
103     }
104 
testArrayAccess3(int index, boolean b)105     public int testArrayAccess3(int index, boolean b) {
106         // Same as testArrayAccess2 but manifests as crash in register allocator.
107         int storeIndex = Integer.MIN_VALUE;
108         for (; index < 10; ++index) {
109             if (b) {
110                 return 0;
111             }
112             if (index == 42) {
113                 return array[storeIndex-1]; // Load1
114             }
115             storeIndex = 0;
116         }
117         return array[42]; // Load2
118     }
119 
testArrayAllocation(int index, int inc)120     public byte[] testArrayAllocation(int index, int inc) {
121         int allocationCount = -1;
122         byte[] result;
123 
124         for (; index < 10; index += inc) {
125             // This loop invariant check triggers loop peeling because it can
126             // be moved out of the loop (see 'IdealLoopTree::policy_peeling').
127             if (inc == 42) return null;
128 
129             if (index == 42) {
130                 // This allocation and the corresponding size check are moved out of the
131                 // loop and both used after main loop and the peeled iteration exit.
132                 // For the peeled iteration, allocationCount is always -1 and the ConvI2L
133                 // is replaced by TOP. However, the size check is not folded because
134                 // we don't do the split if optimization in PhaseIdealLoop2.
135                 // As a result, we have a (dead) control path from the peeled iteration
136                 // to the allocation but the data path is removed.
137                 result = new byte[allocationCount];
138                 return result;
139             }
140 
141             allocationCount++;
142         }
143         return null;
144     }
145 }
146 
147