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 
  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 
  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 
  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 
 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 
 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