1 /*
   2  * Copyright (c) 2015, 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 /**
  26  * @test
  27  * @bug 8080289
  28  * @summary Move stores out of loops if possible
  29  *
  30  * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation
  31  *      -XX:CompileCommand=dontinline,compiler.loopopts.TestMoveStoresOutOfLoops::test*
  32  *      compiler.loopopts.TestMoveStoresOutOfLoops
  33  */
  34 
  35 package compiler.loopopts;
  36 
  37 import java.lang.reflect.Method;
  38 import java.lang.reflect.Modifier;
  39 import java.util.HashMap;
  40 import java.util.function.Function;
  41 
  42 public class TestMoveStoresOutOfLoops {
  43 
  44     private static long[] array = new long[10];
  45     private static long[] array2 = new long[10];
  46     private static boolean[] array3 = new boolean[1000];
  47     private static byte[] byte_array = new byte[10];
  48 
  49     // Array store should be moved out of the loop, value stored
  50     // should be 999, the loop should be eliminated
  51     static void test_after_1(int idx) {
  52         for (int i = 0; i < 1000; i++) {
  53             array[idx] = i;
  54         }
  55     }
  56 
  57     // Array store can't be moved out of loop because of following
  58     // non loop invariant array access
  59     static void test_after_2(int idx) {
  60         for (int i = 0; i < 1000; i++) {
  61             array[idx] = i;
  62             array2[i%10] = i;
  63         }
  64     }
  65 
  66     // Array store can't be moved out of loop because of following
  67     // use
  68     static void test_after_3(int idx) {
  69         for (int i = 0; i < 1000; i++) {
  70             array[idx] = i;
  71             if (array[0] == -1) {
  72                 break;
  73             }
  74         }
  75     }
  76 
  77     // Array store can't be moved out of loop because of preceding
  78     // use
  79     static void test_after_4(int idx) {
  80         for (int i = 0; i < 1000; i++) {
  81             if (array[0] == -2) {
  82                 break;
  83             }
  84             array[idx] = i;
  85         }
  86     }
  87 
  88     // All array stores should be moved out of the loop, one after
  89     // the other
  90     static void test_after_5(int idx) {
  91         for (int i = 0; i < 1000; i++) {
  92             array[idx] = i;
  93             array[idx+1] = i;
  94             array[idx+2] = i;
  95             array[idx+3] = i;
  96             array[idx+4] = i;
  97             array[idx+5] = i;
  98         }
  99     }
 100 
 101     // Array store can be moved after the loop but needs to be
 102     // cloned on both exit paths
 103     static void test_after_6(int idx) {
 104         for (int i = 0; i < 1000; i++) {
 105             array[idx] = i;
 106             if (array3[i]) {
 107                 return;
 108             }
 109         }
 110     }
 111 
 112     // Optimize out redundant stores
 113     static void test_stores_1(int ignored) {
 114         array[0] = 0;
 115         array[1] = 1;
 116         array[2] = 2;
 117         array[0] = 0;
 118         array[1] = 1;
 119         array[2] = 2;
 120     }
 121 
 122     static void test_stores_2(int idx) {
 123         array[idx+0] = 0;
 124         array[idx+1] = 1;
 125         array[idx+2] = 2;
 126         array[idx+0] = 0;
 127         array[idx+1] = 1;
 128         array[idx+2] = 2;
 129     }
 130 
 131     static void test_stores_3(int idx) {
 132         byte_array[idx+0] = 0;
 133         byte_array[idx+1] = 1;
 134         byte_array[idx+2] = 2;
 135         byte_array[idx+0] = 0;
 136         byte_array[idx+1] = 1;
 137         byte_array[idx+2] = 2;
 138     }
 139 
 140     // Array store can be moved out of the loop before the loop header
 141     static void test_before_1(int idx) {
 142         for (int i = 0; i < 1000; i++) {
 143             array[idx] = 999;
 144         }
 145     }
 146 
 147     // Array store can't be moved out of the loop before the loop
 148     // header because there's more than one store on this slice
 149     static void test_before_2(int idx) {
 150         for (int i = 0; i < 1000; i++) {
 151             array[idx] = 999;
 152             array[i%2] = 0;
 153         }
 154     }
 155 
 156     // Array store can't be moved out of the loop before the loop
 157     // header because of use before store
 158     static int test_before_3(int idx) {
 159         int res = 0;
 160         for (int i = 0; i < 1000; i++) {
 161             res += array[i%10];
 162             array[idx] = 999;
 163         }
 164         return res;
 165     }
 166 
 167     // Array store can't be moved out of the loop before the loop
 168     // header because of possible early exit
 169     static void test_before_4(int idx) {
 170         for (int i = 0; i < 1000; i++) {
 171             if (idx / (i+1) > 0) {
 172                 return;
 173             }
 174             array[idx] = 999;
 175         }
 176     }
 177 
 178     // Array store can't be moved out of the loop before the loop
 179     // header because it doesn't postdominate the loop head
 180     static void test_before_5(int idx) {
 181         for (int i = 0; i < 1000; i++) {
 182             if (i % 2 == 0) {
 183                 array[idx] = 999;
 184             }
 185         }
 186     }
 187 
 188     // Array store can be moved out of the loop before the loop header
 189     static int test_before_6(int idx) {
 190         int res = 0;
 191         for (int i = 0; i < 1000; i++) {
 192             if (i%2 == 1) {
 193                 res *= 2;
 194             } else {
 195                 res++;
 196             }
 197             array[idx] = 999;
 198         }
 199         return res;
 200     }
 201 
 202     final HashMap<String,Method> tests = new HashMap<>();
 203     {
 204         for (Method m : this.getClass().getDeclaredMethods()) {
 205             if (m.getName().matches("test_(before|after|stores)_[0-9]+")) {
 206                 assert(Modifier.isStatic(m.getModifiers())) : m;
 207                 tests.put(m.getName(), m);
 208             }
 209         }
 210     }
 211 
 212     boolean success = true;
 213     void doTest(String name, Runnable init, Function<String, Boolean> check) throws Exception {
 214         Method m = tests.get(name);
 215         for (int i = 0; i < 20000; i++) {
 216             init.run();
 217             m.invoke(null, 0);
 218             success = success && check.apply(name);
 219             if (!success) {
 220                 break;
 221             }
 222         }
 223     }
 224 
 225     static void array_init() {
 226         array[0] = -1;
 227     }
 228 
 229     static boolean array_check(String name) {
 230         boolean success = true;
 231         if (array[0] != 999) {
 232             success = false;
 233             System.out.println(name + " failed: array[0] = " + array[0]);
 234         }
 235         return success;
 236     }
 237 
 238     static void array_init2() {
 239         for (int i = 0; i < 6; i++) {
 240             array[i] = -1;
 241         }
 242     }
 243 
 244     static boolean array_check2(String name) {
 245         boolean success = true;
 246         for (int i = 0; i < 6; i++) {
 247             if (array[i] != 999) {
 248                 success = false;
 249                 System.out.println(name + " failed: array[" + i + "] = " + array[i]);
 250             }
 251         }
 252         return success;
 253     }
 254 
 255     static void array_init3() {
 256         for (int i = 0; i < 3; i++) {
 257             array[i] = -1;
 258         }
 259     }
 260 
 261     static boolean array_check3(String name) {
 262         boolean success = true;
 263         for (int i = 0; i < 3; i++) {
 264             if (array[i] != i) {
 265                 success = false;
 266                 System.out.println(name + " failed: array[" + i + "] = " + array[i]);
 267             }
 268         }
 269         return success;
 270     }
 271 
 272     static void array_init4() {
 273         for (int i = 0; i < 3; i++) {
 274             byte_array[i] = -1;
 275         }
 276     }
 277 
 278     static boolean array_check4(String name) {
 279         boolean success = true;
 280         for (int i = 0; i < 3; i++) {
 281             if (byte_array[i] != i) {
 282                 success = false;
 283                 System.out.println(name + " failed: byte_array[" + i + "] = " + byte_array[i]);
 284             }
 285         }
 286         return success;
 287     }
 288 
 289     static public void main(String[] args) throws Exception {
 290         TestMoveStoresOutOfLoops test = new TestMoveStoresOutOfLoops();
 291         test.doTest("test_after_1", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 292         test.doTest("test_after_2", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 293         test.doTest("test_after_3", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 294         test.doTest("test_after_4", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 295         test.doTest("test_after_5", TestMoveStoresOutOfLoops::array_init2, TestMoveStoresOutOfLoops::array_check2);
 296         test.doTest("test_after_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 297         array3[999] = true;
 298         test.doTest("test_after_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 299 
 300         test.doTest("test_stores_1", TestMoveStoresOutOfLoops::array_init3, TestMoveStoresOutOfLoops::array_check3);
 301         test.doTest("test_stores_2", TestMoveStoresOutOfLoops::array_init3, TestMoveStoresOutOfLoops::array_check3);
 302         test.doTest("test_stores_3", TestMoveStoresOutOfLoops::array_init4, TestMoveStoresOutOfLoops::array_check4);
 303 
 304         test.doTest("test_before_1", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 305         test.doTest("test_before_2", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 306         test.doTest("test_before_3", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 307         test.doTest("test_before_4", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 308         test.doTest("test_before_5", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 309         test.doTest("test_before_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
 310 
 311         if (!test.success) {
 312             throw new RuntimeException("Some tests failed");
 313         }
 314     }
 315 }