1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 public class Main { 18 19 /// CHECK-START: int Main.div() licm (before) 20 /// CHECK-DAG: Div loop:{{B\d+}} 21 22 /// CHECK-START: int Main.div() licm (after) 23 /// CHECK-NOT: Div loop:{{B\d+}} 24 25 /// CHECK-START: int Main.div() licm (after) 26 /// CHECK-DAG: Div loop:none 27 28 public static int div() { 29 int result = 0; 30 for (int i = 0; i < 10; ++i) { 31 result += staticField / 42; 32 } 33 return result; 34 } 35 36 /// CHECK-START: int Main.innerDiv() licm (before) 37 /// CHECK-DAG: Div loop:{{B\d+}} 38 39 /// CHECK-START: int Main.innerDiv() licm (after) 40 /// CHECK-NOT: Div loop:{{B\d+}} 41 42 /// CHECK-START: int Main.innerDiv() licm (after) 43 /// CHECK-DAG: Div loop:none 44 45 public static int innerDiv() { 46 int result = 0; 47 for (int i = 0; i < 10; ++i) { 48 for (int j = 0; j < 10; ++j) { 49 result += staticField / 42; 50 } 51 } 52 return result; 53 } 54 55 /// CHECK-START: int Main.innerMul() licm (before) 56 /// CHECK-DAG: Mul loop:B4 57 58 /// CHECK-START: int Main.innerMul() licm (after) 59 /// CHECK-DAG: Mul loop:B2 60 61 public static int innerMul() { 62 int result = 0; 63 for (int i = 0; i < 10; ++i) { 64 for (int j = 0; j < 10; ++j) { 65 // The operation has been hoisted out of the inner loop. 66 // Note that we depend on the compiler's block numbering to 67 // check if it has been moved. 68 result += staticField * i; 69 } 70 } 71 return result; 72 } 73 74 /// CHECK-START: int Main.divByA(int, int) licm (before) 75 /// CHECK-DAG: Div loop:{{B\d+}} 76 77 /// CHECK-START: int Main.divByA(int, int) licm (after) 78 /// CHECK-DAG: Div loop:{{B\d+}} 79 80 public static int divByA(int a, int b) { 81 int result = 0; 82 while (b < 5) { 83 // a might be null, so we can't hoist the operation. 84 result += staticField / a; 85 b++; 86 } 87 return result; 88 } 89 90 /// CHECK-START: int Main.arrayLength(int[]) licm (before) 91 /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:{{B\d+}} 92 /// CHECK-DAG: ArrayLength [<<NullCheck>>] loop:{{B\d+}} 93 94 /// CHECK-START: int Main.arrayLength(int[]) licm (after) 95 /// CHECK-NOT: NullCheck loop:{{B\d+}} 96 /// CHECK-NOT: ArrayLength loop:{{B\d+}} 97 98 /// CHECK-START: int Main.arrayLength(int[]) licm (after) 99 /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:none 100 /// CHECK-DAG: ArrayLength [<<NullCheck>>] loop:none 101 102 public static int arrayLength(int[] array) { 103 int result = 0; 104 for (int i = 0; i < array.length; ++i) { 105 result += array[i]; 106 } 107 return result; 108 } 109 110 /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (before) 111 /// CHECK-DAG: Div loop:{{B\d+}} 112 113 /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (after) 114 /// CHECK-NOT: Div loop:{{B\d+}} 115 116 /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (after) 117 /// CHECK-DAG: Div loop:none 118 119 public static int divAndIntrinsic(int[] array) { 120 int result = 0; 121 for (int i = 0; i < array.length; i++) { 122 // An intrinsic call, unlike a general method call, cannot modify the field value. 123 // As a result, the invariant division on the field can be moved out of the loop. 124 result += (staticField / 42) + Math.abs(array[i]); 125 } 126 return result; 127 } 128 129 /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (before) 130 /// CHECK-DAG: InvokeStaticOrDirect loop:{{B\d+}} 131 132 /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (after) 133 /// CHECK-NOT: InvokeStaticOrDirect loop:{{B\d+}} 134 135 /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (after) 136 /// CHECK-DAG: InvokeStaticOrDirect loop:none 137 138 public static int invariantBoundIntrinsic(int x) { 139 int result = 0; 140 // The intrinsic call to abs used as loop bound is invariant. 141 // As a result, the call itself can be moved out of the loop header. 142 for (int i = 0; i < Math.abs(x); i++) { 143 result += i; 144 } 145 return result; 146 } 147 148 /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (before) 149 /// CHECK-DAG: InvokeStaticOrDirect loop:{{B\d+}} 150 151 /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after) 152 /// CHECK-NOT: InvokeStaticOrDirect loop:{{B\d+}} 153 154 /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after) 155 /// CHECK-DAG: InvokeStaticOrDirect loop:none 156 157 public static int invariantBodyIntrinsic(int x, int y) { 158 int result = 0; 159 for (int i = 0; i < 10; i++) { 160 // The intrinsic call to max used inside the loop is invariant. 161 // As a result, the call itself can be moved out of the loop body. 162 result += Math.max(x, y); 163 } 164 return result; 165 } 166 167 // 168 // All operations up to the null check can be hoisted out of the 169 // loop. The null check itself sees the induction in its environment. 170 // 171 /// CHECK-START: int Main.doWhile(int) licm (before) 172 /// CHECK-DAG: <<Add:i\d+>> Add loop:<<Loop:B\d+>> outer_loop:none 173 /// CHECK-DAG: LoadClass loop:<<Loop>> outer_loop:none 174 /// CHECK-DAG: <<Get:l\d+>> StaticFieldGet loop:<<Loop>> outer_loop:none 175 /// CHECK-DAG: NullCheck [<<Get>>] env:[[<<Add>>,<<Get>>,{{i\d+}}]] loop:<<Loop>> outer_loop:none 176 /// CHECK-DAG: ArrayLength loop:<<Loop>> outer_loop:none 177 /// CHECK-DAG: BoundsCheck loop:<<Loop>> outer_loop:none 178 /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none 179 // 180 /// CHECK-START: int Main.doWhile(int) licm (after) 181 /// CHECK-NOT: LoadClass loop:{{B\d+}} 182 /// CHECK-NOT: StaticFieldGet loop:{{B\d+}} 183 // 184 /// CHECK-START: int Main.doWhile(int) licm (after) 185 /// CHECK-DAG: LoadClass loop:none 186 /// CHECK-DAG: <<Get:l\d+>> StaticFieldGet loop:none 187 /// CHECK-DAG: <<Add:i\d+>> Add loop:<<Loop:B\d+>> outer_loop:none 188 /// CHECK-DAG: NullCheck [<<Get>>] env:[[<<Add>>,<<Get>>,{{i\d+}}]] loop:<<Loop>> outer_loop:none 189 /// CHECK-DAG: ArrayLength loop:<<Loop>> outer_loop:none 190 /// CHECK-DAG: BoundsCheck loop:<<Loop>> outer_loop:none 191 /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none 192 public static int doWhile(int k) { 193 int i = k; 194 do { 195 i += 2; 196 } while (staticArray[i] == 0); 197 return i; 198 } 199 200 public static int staticField = 42; 201 202 public static int[] staticArray = null; 203 204 public static void assertEquals(int expected, int actual) { 205 if (expected != actual) { 206 throw new Error("Expected " + expected + ", got " + actual); 207 } 208 } 209 210 public static void main(String[] args) { 211 assertEquals(10, div()); 212 assertEquals(100, innerDiv()); 213 assertEquals(18900, innerMul()); 214 assertEquals(105, divByA(2, 0)); 215 assertEquals(12, arrayLength(new int[] { 4, 8 })); 216 assertEquals(21, divAndIntrinsic(new int[] { 4, -2, 8, -3 })); 217 assertEquals(45, invariantBoundIntrinsic(-10)); 218 assertEquals(30, invariantBodyIntrinsic(2, 3)); 219 220 staticArray = null; 221 try { 222 doWhile(0); 223 throw new Error("Expected NPE"); 224 } catch (NullPointerException e) { 225 } 226 staticArray = new int[5]; 227 staticArray[4] = 1; 228 assertEquals(4, doWhile(-2)); 229 assertEquals(4, doWhile(0)); 230 assertEquals(4, doWhile(2)); 231 try { 232 doWhile(1); 233 throw new Error("Expected IOOBE"); 234 } catch (IndexOutOfBoundsException e) { 235 } 236 237 System.out.println("passed"); 238 } 239 } 240