182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray/*
26a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * Copyright (C) 2015 The Android Open Source Project
36a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain *
46a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * Licensed under the Apache License, Version 2.0 (the "License");
56a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * you may not use this file except in compliance with the License.
66a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * You may obtain a copy of the License at
76a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain *
86a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain *      http://www.apache.org/licenses/LICENSE-2.0
96a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain *
106a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * Unless required by applicable law or agreed to in writing, software
116a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * distributed under the License is distributed on an "AS IS" BASIS,
126a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * See the License for the specific language governing permissions and
146a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain * limitations under the License.
156a92a033c33e383541d77607fbe8cd982875d13dRoland Levillain */
1682091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
1782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffraypublic class Main {
1882091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
19a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.div() licm (before)
20a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: Div loop:{{B\d+}}
2182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
22a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.div() licm (after)
23a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-NOT: Div loop:{{B\d+}}
2482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
25a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.div() licm (after)
26a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: Div loop:none
2782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
2882091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  public static int div() {
2982091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    int result = 0;
3082091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    for (int i = 0; i < 10; ++i) {
3182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      result += staticField / 42;
3282091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    }
3382091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    return result;
3482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  }
3582091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
36a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.innerDiv() licm (before)
37a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: Div loop:{{B\d+}}
3882091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
39a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.innerDiv() licm (after)
40a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-NOT: Div loop:{{B\d+}}
4182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
42a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.innerDiv() licm (after)
43a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: Div loop:none
4482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
4582091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  public static int innerDiv() {
4682091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    int result = 0;
4782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    for (int i = 0; i < 10; ++i) {
4882091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      for (int j = 0; j < 10; ++j) {
4982091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray        result += staticField / 42;
5082091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      }
5182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    }
5282091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    return result;
5382091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  }
5482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
555d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.innerMul() licm (before)
56a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: Mul loop:B4
5782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
585d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.innerMul() licm (after)
59a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: Mul loop:B2
6082091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
615d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  public static int innerMul() {
6282091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    int result = 0;
6382091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    for (int i = 0; i < 10; ++i) {
6482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      for (int j = 0; j < 10; ++j) {
6582091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray        // The operation has been hoisted out of the inner loop.
6682091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray        // Note that we depend on the compiler's block numbering to
6782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray        // check if it has been moved.
6882091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray        result += staticField * i;
6982091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      }
7082091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    }
7182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    return result;
7282091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  }
7382091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
745d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.divByA(int, int) licm (before)
75a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: Div loop:{{B\d+}}
7682091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
775d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.divByA(int, int) licm (after)
78a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: Div loop:{{B\d+}}
7982091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
805d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  public static int divByA(int a, int b) {
8182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    int result = 0;
8282091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    while (b < 5) {
8382091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      // a might be null, so we can't hoist the operation.
8482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      result += staticField / a;
8582091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      b++;
8682091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    }
8782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    return result;
8882091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  }
8982091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
90a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.arrayLength(int[]) licm (before)
91a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:{{B\d+}}
92a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG:                    ArrayLength [<<NullCheck>>] loop:{{B\d+}}
9382091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
94a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.arrayLength(int[]) licm (after)
95a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-NOT:                    NullCheck loop:{{B\d+}}
96a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-NOT:                    ArrayLength loop:{{B\d+}}
9782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
98a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-START: int Main.arrayLength(int[]) licm (after)
99a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:none
100a06d66a4ee60926127b9498b7ff0b3e37a24fccfDavid Brazdil  /// CHECK-DAG:                    ArrayLength [<<NullCheck>>] loop:none
10182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
10282091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  public static int arrayLength(int[] array) {
10382091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    int result = 0;
10482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    for (int i = 0; i < array.length; ++i) {
10582091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      result += array[i];
10682091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    }
10782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    return result;
10882091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  }
10982091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
1105d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (before)
1115d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-DAG: Div loop:{{B\d+}}
1125d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1135d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (after)
1145d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-NOT: Div loop:{{B\d+}}
1155d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1165d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (after)
1175d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-DAG: Div loop:none
1185d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1195d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  public static int divAndIntrinsic(int[] array) {
1205d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    int result = 0;
1215d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    for (int i = 0; i < array.length; i++) {
1225d75afe333f57546786686d9bee16b52f1bbe971Aart Bik      // An intrinsic call, unlike a general method call, cannot modify the field value.
1235d75afe333f57546786686d9bee16b52f1bbe971Aart Bik      // As a result, the invariant division on the field can be moved out of the loop.
1245d75afe333f57546786686d9bee16b52f1bbe971Aart Bik      result += (staticField / 42) + Math.abs(array[i]);
1255d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    }
1265d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    return result;
1275d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  }
1285d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1295d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (before)
1305d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-DAG: InvokeStaticOrDirect loop:{{B\d+}}
1315d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1325d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (after)
1335d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-NOT: InvokeStaticOrDirect loop:{{B\d+}}
1345d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1355d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (after)
1365d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-DAG: InvokeStaticOrDirect loop:none
1375d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1385d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  public static int invariantBoundIntrinsic(int x) {
1395d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    int result = 0;
1405d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    // The intrinsic call to abs used as loop bound is invariant.
1415d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    // As a result, the call itself can be moved out of the loop header.
1425d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    for (int i = 0; i < Math.abs(x); i++) {
1435d75afe333f57546786686d9bee16b52f1bbe971Aart Bik      result += i;
1445d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    }
1455d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    return result;
1465d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  }
1475d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1485d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (before)
1495d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-DAG: InvokeStaticOrDirect loop:{{B\d+}}
1505d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1515d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after)
1525d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-NOT: InvokeStaticOrDirect loop:{{B\d+}}
1535d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1545d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after)
1555d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  /// CHECK-DAG: InvokeStaticOrDirect loop:none
1565d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
1575d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  public static int invariantBodyIntrinsic(int x, int y) {
1585d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    int result = 0;
1595d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    for (int i = 0; i < 10; i++) {
1605d75afe333f57546786686d9bee16b52f1bbe971Aart Bik      // The intrinsic call to max used inside the loop is invariant.
1615d75afe333f57546786686d9bee16b52f1bbe971Aart Bik      // As a result, the call itself can be moved out of the loop body.
1625d75afe333f57546786686d9bee16b52f1bbe971Aart Bik      result += Math.max(x, y);
1635d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    }
1645d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    return result;
1655d75afe333f57546786686d9bee16b52f1bbe971Aart Bik  }
1665d75afe333f57546786686d9bee16b52f1bbe971Aart Bik
16782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  public static int staticField = 42;
16882091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
16982091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  public static void assertEquals(int expected, int actual) {
17082091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    if (expected != actual) {
17182091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray      throw new Error("Expected " + expected + ", got " + actual);
17282091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    }
17382091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  }
17482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray
17582091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  public static void main(String[] args) {
17682091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    assertEquals(10, div());
17782091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    assertEquals(100, innerDiv());
1785d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    assertEquals(18900, innerMul());
1795d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    assertEquals(105, divByA(2, 0));
18082091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray    assertEquals(12, arrayLength(new int[] { 4, 8 }));
1815d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    assertEquals(21, divAndIntrinsic(new int[] { 4, -2, 8, -3 }));
1825d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    assertEquals(45, invariantBoundIntrinsic(-10));
1835d75afe333f57546786686d9bee16b52f1bbe971Aart Bik    assertEquals(30, invariantBodyIntrinsic(2, 3));
18482091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray  }
18582091dad38f3e5bfaf3b6984c9ab73069fb68310Nicolas Geoffray}
186