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