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
17public 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  public static int staticField = 42;
168
169  public static void assertEquals(int expected, int actual) {
170    if (expected != actual) {
171      throw new Error("Expected " + expected + ", got " + actual);
172    }
173  }
174
175  public static void main(String[] args) {
176    assertEquals(10, div());
177    assertEquals(100, innerDiv());
178    assertEquals(18900, innerMul());
179    assertEquals(105, divByA(2, 0));
180    assertEquals(12, arrayLength(new int[] { 4, 8 }));
181    assertEquals(21, divAndIntrinsic(new int[] { 4, -2, 8, -3 }));
182    assertEquals(45, invariantBoundIntrinsic(-10));
183    assertEquals(30, invariantBodyIntrinsic(2, 3));
184  }
185}
186