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