/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Regression tests for loop optimizations. */ public class Main { /// CHECK-START: int Main.earlyExitFirst(int) loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.earlyExitFirst(int) loop_optimization (after) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none static int earlyExitFirst(int m) { int k = 0; for (int i = 0; i < 10; i++) { if (i == m) { return k; } k++; } return k; } /// CHECK-START: int Main.earlyExitLast(int) loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.earlyExitLast(int) loop_optimization (after) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none static int earlyExitLast(int m) { int k = 0; for (int i = 0; i < 10; i++) { k++; if (i == m) { return k; } } return k; } /// CHECK-START: int Main.earlyExitNested() loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:<> /// CHECK-DAG: Phi loop:<> outer_loop:<> // /// CHECK-START: int Main.earlyExitNested() loop_optimization (after) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.earlyExitNested() loop_optimization (after) /// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:{{B\d+}} static int earlyExitNested() { int offset = 0; for (int i = 0; i < 2; i++) { int start = offset; // This loop can be removed. for (int j = 0; j < 2; j++) { offset++; } if (i == 1) { return start; } } return 0; } // Regression test for b/33774618: transfer operations involving // narrowing linear induction should be done correctly. // /// CHECK-START: int Main.transferNarrowWrap() loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.transferNarrowWrap() loop_optimization (after) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none static int transferNarrowWrap() { short x = 0; int w = 10; int v = 3; for (int i = 0; i < 10; i++) { v = w + 1; // transfer on wrap-around w = x; // wrap-around x += 2; // narrowing linear } return v; } // Regression test for b/33774618: transfer operations involving // narrowing linear induction should be done correctly // (currently rejected, could be improved). // /// CHECK-START: int Main.polynomialShort() loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.polynomialShort() loop_optimization (after) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none static int polynomialShort() { int x = 0; for (short i = 0; i < 10; i++) { x = x - i; // polynomial on narrowing linear } return x; } // Regression test for b/33774618: transfer operations involving // narrowing linear induction should be done correctly // (currently rejected, could be improved). // /// CHECK-START: int Main.polynomialIntFromLong() loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.polynomialIntFromLong() loop_optimization (after) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none static int polynomialIntFromLong() { int x = 0; for (long i = 0; i < 10; i++) { x = x - (int) i; // polynomial on narrowing linear } return x; } /// CHECK-START: int Main.polynomialInt() loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.polynomialInt() loop_optimization (after) /// CHECK-NOT: Phi // /// CHECK-START: int Main.polynomialInt() instruction_simplifier$after_bce (after) /// CHECK-DAG: <> IntConstant -45 loop:none /// CHECK-DAG: Return [<>] loop:none static int polynomialInt() { int x = 0; for (int i = 0; i < 10; i++) { x = x - i; } return x; } // Regression test for b/34779592 (found with fuzz testing): overflow for last value // of division truncates to zero, for multiplication it simply truncates. // /// CHECK-START: int Main.geoIntDivLastValue(int) loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.geoIntDivLastValue(int) loop_optimization (after) /// CHECK-NOT: Phi // /// CHECK-START: int Main.geoIntDivLastValue(int) instruction_simplifier$after_bce (after) /// CHECK-DAG: <> IntConstant 0 loop:none /// CHECK-DAG: Return [<>] loop:none static int geoIntDivLastValue(int x) { for (int i = 0; i < 2; i++) { x /= 1081788608; } return x; } /// CHECK-START: int Main.geoIntMulLastValue(int) loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: int Main.geoIntMulLastValue(int) loop_optimization (after) /// CHECK-NOT: Phi // /// CHECK-START: int Main.geoIntMulLastValue(int) instruction_simplifier$after_bce (after) /// CHECK-DAG: <> ParameterValue loop:none /// CHECK-DAG: <> IntConstant -194211840 loop:none /// CHECK-DAG: <> Mul [<>,<>] loop:none /// CHECK-DAG: Return [<>] loop:none static int geoIntMulLastValue(int x) { for (int i = 0; i < 2; i++) { x *= 1081788608; } return x; } /// CHECK-START: long Main.geoLongDivLastValue(long) loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: long Main.geoLongDivLastValue(long) loop_optimization (after) /// CHECK-NOT: Phi // /// CHECK-START: long Main.geoLongDivLastValue(long) instruction_simplifier$after_bce (after) /// CHECK-DAG: <> LongConstant 0 loop:none /// CHECK-DAG: Return [<>] loop:none // // Tests overflow in the divisor (while updating intermediate result). static long geoLongDivLastValue(long x) { for (int i = 0; i < 10; i++) { x /= 1081788608; } return x; } /// CHECK-START: long Main.geoLongDivLastValue() loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: long Main.geoLongDivLastValue() loop_optimization (after) /// CHECK-NOT: Phi // /// CHECK-START: long Main.geoLongDivLastValue() instruction_simplifier$after_bce (after) /// CHECK-DAG: <> LongConstant 0 loop:none /// CHECK-DAG: Return [<>] loop:none // // Tests overflow in the divisor (while updating base). static long geoLongDivLastValue() { long x = -1; for (int i2 = 0; i2 < 2; i2++) { x /= (Long.MAX_VALUE); } return x; } /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (before) /// CHECK-DAG: Phi loop:<> outer_loop:none /// CHECK-DAG: Phi loop:<> outer_loop:none // /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (after) /// CHECK-NOT: Phi // /// CHECK-START: long Main.geoLongMulLastValue(long) instruction_simplifier$after_bce (after) /// CHECK-DAG: <> ParameterValue loop:none /// CHECK-DAG: <> LongConstant -8070450532247928832 loop:none /// CHECK-DAG: <> Mul [<>,<>] loop:none /// CHECK-DAG: Return [<>] loop:none static long geoLongMulLastValue(long x) { for (int i = 0; i < 10; i++) { x *= 1081788608; } return x; } // If vectorized, the narrowing subscript should not cause // type inconsistencies in the synthesized code. static void narrowingSubscript(float[] a) { float val = 2.0f; for (long i = 0; i < a.length; i++) { a[(int) i] += val; } } public static void main(String[] args) { expectEquals(10, earlyExitFirst(-1)); for (int i = 0; i <= 10; i++) { expectEquals(i, earlyExitFirst(i)); } expectEquals(10, earlyExitFirst(11)); expectEquals(10, earlyExitLast(-1)); for (int i = 0; i < 10; i++) { expectEquals(i + 1, earlyExitLast(i)); } expectEquals(10, earlyExitLast(10)); expectEquals(10, earlyExitLast(11)); expectEquals(2, earlyExitNested()); expectEquals(17, transferNarrowWrap()); expectEquals(-45, polynomialShort()); expectEquals(-45, polynomialIntFromLong()); expectEquals(-45, polynomialInt()); expectEquals(0, geoIntDivLastValue(0)); expectEquals(0, geoIntDivLastValue(1)); expectEquals(0, geoIntDivLastValue(2)); expectEquals(0, geoIntDivLastValue(1081788608)); expectEquals(0, geoIntDivLastValue(-1081788608)); expectEquals(0, geoIntDivLastValue(2147483647)); expectEquals(0, geoIntDivLastValue(-2147483648)); expectEquals( 0, geoIntMulLastValue(0)); expectEquals( -194211840, geoIntMulLastValue(1)); expectEquals( -388423680, geoIntMulLastValue(2)); expectEquals(-1041498112, geoIntMulLastValue(1081788608)); expectEquals( 1041498112, geoIntMulLastValue(-1081788608)); expectEquals( 194211840, geoIntMulLastValue(2147483647)); expectEquals( 0, geoIntMulLastValue(-2147483648)); expectEquals(0L, geoLongDivLastValue(0L)); expectEquals(0L, geoLongDivLastValue(1L)); expectEquals(0L, geoLongDivLastValue(2L)); expectEquals(0L, geoLongDivLastValue(1081788608L)); expectEquals(0L, geoLongDivLastValue(-1081788608L)); expectEquals(0L, geoLongDivLastValue(2147483647L)); expectEquals(0L, geoLongDivLastValue(-2147483648L)); expectEquals(0L, geoLongDivLastValue(9223372036854775807L)); expectEquals(0L, geoLongDivLastValue(-9223372036854775808L)); expectEquals(0L, geoLongDivLastValue()); expectEquals( 0L, geoLongMulLastValue(0L)); expectEquals(-8070450532247928832L, geoLongMulLastValue(1L)); expectEquals( 2305843009213693952L, geoLongMulLastValue(2L)); expectEquals( 0L, geoLongMulLastValue(1081788608L)); expectEquals( 0L, geoLongMulLastValue(-1081788608L)); expectEquals( 8070450532247928832L, geoLongMulLastValue(2147483647L)); expectEquals( 0L, geoLongMulLastValue(-2147483648L)); expectEquals( 8070450532247928832L, geoLongMulLastValue(9223372036854775807L)); expectEquals( 0L, geoLongMulLastValue(-9223372036854775808L)); float[] a = new float[16]; narrowingSubscript(a); for (int i = 0; i < 16; i++) { expectEquals(2.0f, a[i]); } System.out.println("passed"); } private static void expectEquals(int expected, int result) { if (expected != result) { throw new Error("Expected: " + expected + ", found: " + result); } } private static void expectEquals(long expected, long result) { if (expected != result) { throw new Error("Expected: " + expected + ", found: " + result); } } private static void expectEquals(float expected, float result) { if (expected != result) { throw new Error("Expected: " + expected + ", found: " + result); } } }