/* * 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. */ public class Main { public class ExampleObj { int n1; int n2; public ExampleObj(int n1, int n2) { this.n1 = n1; this.n2 = n2; } } static int static_variable = 0; public ExampleObj my_obj; public static int number1; public static int number2; public static volatile int number3; /// CHECK-START-ARM64: int Main.arrayAccess() scheduler (before) /// CHECK: <> IntConstant 1 /// CHECK: <> Phi /// CHECK: <> Phi /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: Add [<>,<>] /// CHECK-START-ARM64: int Main.arrayAccess() scheduler (after) /// CHECK: <> IntConstant 1 /// CHECK: <> Phi /// CHECK: <> Phi /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: Add [<>,<>] public static int arrayAccess() { int res = 0; int [] array = new int[10]; for (int i = 0; i < 9; i++) { res += array[i]; res += array[i + 1]; } return res; } /// CHECK-START-ARM: void Main.arrayAccessVariable(int) scheduler (before) /// CHECK: <> ParameterValue /// CHECK-DAG: <> IntConstant 1 /// CHECK-DAG: <> IntConstant 2 /// CHECK-DAG: <> IntConstant -1 /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK-START-ARM: void Main.arrayAccessVariable(int) scheduler (after) /// CHECK: <> ParameterValue /// CHECK-DAG: <> IntConstant 1 /// CHECK-DAG: <> IntConstant 2 /// CHECK-DAG: <> IntConstant -1 /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> IntermediateAddress /// CHECK: ArrayGet [<>,{{i\d+}}] /// CHECK: ArrayGet [<>,{{i\d+}}] /// CHECK: ArrayGet [<>,{{i\d+}}] /// CHECK: Add /// CHECK: Add /// CHECK: Add /// CHECK: ArraySet /// CHECK: ArraySet /// CHECK: ArraySet /// CHECK-START-ARM64: void Main.arrayAccessVariable(int) scheduler (before) /// CHECK: <> ParameterValue /// CHECK-DAG: <> IntConstant 1 /// CHECK-DAG: <> IntConstant 2 /// CHECK-DAG: <> IntConstant -1 /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK-START-ARM64: void Main.arrayAccessVariable(int) scheduler (after) /// CHECK: <> ParameterValue /// CHECK-DAG: <> IntConstant 1 /// CHECK-DAG: <> IntConstant 2 /// CHECK-DAG: <> IntConstant -1 /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> IntermediateAddress /// CHECK: ArrayGet [<>,{{i\d+}}] /// CHECK: ArrayGet [<>,{{i\d+}}] /// CHECK: ArrayGet [<>,{{i\d+}}] /// CHECK: Add /// CHECK: Add /// CHECK: Add /// CHECK: ArraySet /// CHECK: ArraySet /// CHECK: ArraySet public static void arrayAccessVariable(int i) { int [] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (int j = 0; j < 100; j++) { array[i + 1]++; array[i + 2]++; array[i - 1]++; } } /// CHECK-START-ARM: void Main.arrayAccessSub(int) scheduler (before) /// CHECK: <> ParameterValue /// CHECK-DAG: <> IntConstant -1 /// CHECK-DAG: <> IntConstant 9 /// CHECK-DAG: <> IntConstant 1 /// CHECK: <> Add [<>,<>] /// CHECK: <> Sub [<>,<>] /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK-START-ARM: void Main.arrayAccessSub(int) scheduler (after) /// CHECK: <> ParameterValue /// CHECK-DAG: <> IntConstant -1 /// CHECK-DAG: <> IntConstant 9 /// CHECK-DAG: <> IntConstant 1 /// CHECK: <> Add [<>,<>] /// CHECK: <> Sub [<>,<>] /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK-START-ARM64: void Main.arrayAccessSub(int) scheduler (before) /// CHECK: <> ParameterValue /// CHECK-DAG: <> IntConstant -1 /// CHECK-DAG: <> IntConstant 9 /// CHECK-DAG: <> IntConstant 1 /// CHECK: <> Add [<>,<>] /// CHECK: <> Sub [<>,<>] /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK-START-ARM64: void Main.arrayAccessSub(int) scheduler (after) /// CHECK: <> ParameterValue /// CHECK-DAG: <> IntConstant -1 /// CHECK-DAG: <> IntConstant 9 /// CHECK-DAG: <> IntConstant 1 /// CHECK: <> Add [<>,<>] /// CHECK: <> Sub [<>,<>] /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] /// CHECK: <> ArrayGet [<>,<>] /// CHECK: <> Add [<>,<>] /// CHECK: <> ArraySet [<>,<>,<>] public static void arrayAccessSub(int i) { int [] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (int j = 0; j < 100; j++) { // These two accesses MAY ALIAS array[i - 1]++; array[9 - i]++; } } /// CHECK-START-ARM: void Main.arrayAccessLoopVariable() scheduler (before) /// CHECK-DAG: <> IntConstant 0 /// CHECK-DAG: <> IntConstant 1 /// CHECK: <> Phi /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet /// CHECK: <> Add /// CHECK: <> ArraySet /// CHECK: <> Add /// CHECK: <> ArrayGet /// CHECK: <> Add /// CHECK: <> ArraySet /// CHECK-START-ARM: void Main.arrayAccessLoopVariable() scheduler (after) /// CHECK-DAG: <> IntConstant 0 /// CHECK-DAG: <> IntConstant 1 /// CHECK: <> Phi /// CHECK: <> IntermediateAddress /// CHECK: <> Add /// CHECK: <> ArrayGet /// CHECK: <> ArrayGet /// CHECK: <> Add /// CHECK: <> Add /// CHECK: <> ArraySet /// CHECK: <> ArraySet /// CHECK-START-ARM64: void Main.arrayAccessLoopVariable() scheduler (before) /// CHECK-DAG: <> IntConstant 0 /// CHECK-DAG: <> IntConstant 1 /// CHECK: <> Phi /// CHECK: <> IntermediateAddress /// CHECK: <> ArrayGet /// CHECK: <> Add /// CHECK: <> ArraySet /// CHECK: <> Add /// CHECK: <> ArrayGet /// CHECK: <> Add /// CHECK: <> ArraySet /// CHECK-START-ARM64: void Main.arrayAccessLoopVariable() scheduler (after) /// CHECK-DAG: <> IntConstant 0 /// CHECK-DAG: <> IntConstant 1 /// CHECK: <> Phi /// CHECK: <> IntermediateAddress /// CHECK: <> Add /// CHECK: <> ArrayGet /// CHECK: <> ArrayGet /// CHECK: <> Add /// CHECK: <> Add /// CHECK: <> ArraySet /// CHECK: <> ArraySet public static void arrayAccessLoopVariable() { int [] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (int j = 0; j < 9; j++) { array[j]++; array[j + 1]++; } } // This case tests a bug found in LSA where LSA doesn't understand IntermediateAddress, // and incorrectly reported no alias between ArraySet1 and ArrayGet2, // thus ArrayGet2 is scheduled above ArraySet1 incorrectly. /// CHECK-START-ARM64: void Main.CrossOverLoop(int[], int[]) scheduler (before) /// CHECK: <> ParameterValue loop:none /// CHECK: <> ParameterValue loop:none /// CHECK: <> NullCheck [<>] loop:none /// CHECK: <> NullCheck [<>] loop:none /// CHECK: Phi loop:<> outer_loop:none /// CHECK: <> ArrayGet [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK: <> IntermediateAddress [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: <> ArraySet [<>,{{i\d+}},{{i\d+}}] loop:<> outer_loop:none /// CHECK: <> ArrayGet [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK: <> IntermediateAddress [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: <> ArraySet [<>,{{i\d+}},{{i\d+}}] loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK-START-ARM64: void Main.CrossOverLoop(int[], int[]) scheduler (after) /// CHECK: <> ParameterValue loop:none /// CHECK: <> ParameterValue loop:none /// CHECK: <> NullCheck [<>] loop:none /// CHECK: <> NullCheck [<>] loop:none /// CHECK: Phi loop:<> outer_loop:none /// CHECK: <> ArrayGet [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK: <> IntermediateAddress [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: <> ArraySet [<>,{{i\d+}},{{i\d+}}] loop:<> outer_loop:none /// CHECK: <> ArrayGet [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK: <> IntermediateAddress [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: <> ArraySet [<>,{{i\d+}},{{i\d+}}] loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none private static void CrossOverLoop(int a[], int b[]) { b[20] = 99; for (int i = 0; i < a.length; i++) { a[i] = b[20] - 7; i++; a[i] = b[20] - 7; } } // This test case is similar to above cross over loop, // but has more complex chains of transforming the original references: // ParameterValue --> BoundType --> NullCheck --> ArrayGet. // ParameterValue --> BoundType --> NullCheck --> IntermediateAddress --> ArraySet. // After using LSA to analyze the orginal references, the scheduler should be able // to find out that 'a' and 'b' may alias, hence unable to schedule these ArraGet/Set. /// CHECK-START-ARM64: void Main.CrossOverLoop2(java.lang.Object, java.lang.Object) scheduler (before) /// CHECK: Phi loop:<> outer_loop:none /// CHECK: ArrayGet loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK: ArraySet loop:<> outer_loop:none /// CHECK: ArrayGet loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK: ArraySet loop:<> outer_loop:none /// CHECK-START-ARM64: void Main.CrossOverLoop2(java.lang.Object, java.lang.Object) scheduler (after) /// CHECK: Phi loop:<> outer_loop:none /// CHECK: ArrayGet loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK: ArraySet loop:<> outer_loop:none /// CHECK: ArrayGet loop:<> outer_loop:none /// CHECK: Add loop:<> outer_loop:none /// CHECK: ArraySet loop:<> outer_loop:none private static void CrossOverLoop2(Object a, Object b) { ((int[])b)[20] = 99; for (int i = 0; i < ((int[])a).length; i++) { ((int[])a)[i] = ((int[])b)[20] - 7; i++; ((int[])a)[i] = ((int[])b)[20] - 7; } } /// CHECK-START-ARM: void Main.accessFields() scheduler (before) /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: StaticFieldGet /// CHECK: Add /// CHECK: StaticFieldSet /// CHECK: StaticFieldGet /// CHECK: Add /// CHECK: StaticFieldSet /// CHECK-START-ARM: void Main.accessFields() scheduler (after) /// CHECK-DAG: InstanceFieldGet /// CHECK-DAG: InstanceFieldGet /// CHECK-DAG: StaticFieldGet /// CHECK-DAG: StaticFieldGet /// CHECK: Add /// CHECK: Add /// CHECK: Add /// CHECK: Add /// CHECK-DAG: InstanceFieldSet /// CHECK-DAG: InstanceFieldSet /// CHECK-DAG: StaticFieldSet /// CHECK-DAG: StaticFieldSet /// CHECK-START-ARM64: void Main.accessFields() scheduler (before) /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: StaticFieldGet /// CHECK: Add /// CHECK: StaticFieldSet /// CHECK: StaticFieldGet /// CHECK: Add /// CHECK: StaticFieldSet /// CHECK-START-ARM64: void Main.accessFields() scheduler (after) /// CHECK-DAG: InstanceFieldGet /// CHECK-DAG: InstanceFieldGet /// CHECK-DAG: StaticFieldGet /// CHECK-DAG: StaticFieldGet /// CHECK: Add /// CHECK: Add /// CHECK: Add /// CHECK: Add /// CHECK-DAG: InstanceFieldSet /// CHECK-DAG: InstanceFieldSet /// CHECK-DAG: StaticFieldSet /// CHECK-DAG: StaticFieldSet public void accessFields() { my_obj = new ExampleObj(1, 2); for (int i = 0; i < 10; i++) { my_obj.n1++; my_obj.n2++; number1++; number2++; } } /// CHECK-START-ARM: void Main.accessFieldsVolatile() scheduler (before) /// CHECK-START-ARM64: void Main.accessFieldsVolatile() scheduler (before) /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: StaticFieldGet /// CHECK: Add /// CHECK: StaticFieldSet /// CHECK: StaticFieldGet /// CHECK: Add /// CHECK: StaticFieldSet /// CHECK-START-ARM: void Main.accessFieldsVolatile() scheduler (after) /// CHECK-START-ARM64: void Main.accessFieldsVolatile() scheduler (after) /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: StaticFieldGet /// CHECK: Add /// CHECK: StaticFieldSet /// CHECK: StaticFieldGet /// CHECK: Add /// CHECK: StaticFieldSet public void accessFieldsVolatile() { my_obj = new ExampleObj(1, 2); for (int i = 0; i < 10; i++) { my_obj.n1++; my_obj.n2++; number1++; number3++; } } /// CHECK-START-ARM: void Main.accessFieldsUnresolved() scheduler (before) /// CHECK-START-ARM64: void Main.accessFieldsUnresolved() scheduler (before) /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: UnresolvedInstanceFieldGet /// CHECK: Add /// CHECK: UnresolvedInstanceFieldSet /// CHECK: UnresolvedStaticFieldGet /// CHECK: Add /// CHECK: UnresolvedStaticFieldSet /// CHECK-START-ARM: void Main.accessFieldsUnresolved() scheduler (after) /// CHECK-START-ARM64: void Main.accessFieldsUnresolved() scheduler (after) /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldGet /// CHECK: Add /// CHECK: InstanceFieldSet /// CHECK: UnresolvedInstanceFieldGet /// CHECK: Add /// CHECK: UnresolvedInstanceFieldSet /// CHECK: UnresolvedStaticFieldGet /// CHECK: Add /// CHECK: UnresolvedStaticFieldSet public void accessFieldsUnresolved() { my_obj = new ExampleObj(1, 2); UnresolvedClass unresolved_obj = new UnresolvedClass(); for (int i = 0; i < 10; i++) { my_obj.n1++; my_obj.n2++; unresolved_obj.instanceInt++; UnresolvedClass.staticInt++; } } /// CHECK-START-ARM64: int Main.intDiv(int) scheduler (before) /// CHECK: Sub /// CHECK: DivZeroCheck /// CHECK: Div /// CHECK: StaticFieldSet /// CHECK-START-ARM64: int Main.intDiv(int) scheduler (after) /// CHECK: Sub /// CHECK-NOT: StaticFieldSet /// CHECK: DivZeroCheck /// CHECK-NOT: Sub /// CHECK: Div public static int intDiv(int arg) { int res = 0; int tmp = arg; for (int i = 1; i < arg; i++) { tmp -= i; res = res / i; // div-zero check barrier. static_variable++; } res += tmp; return res; } private static void expectEquals(int expected, int result) { if (expected != result) { throw new Error("Expected: " + expected + ", found: " + result); } } private static final int ARRAY_SIZE = 32; // Check that VecReplicateScalar is not reordered. /// CHECK-START-ARM64: void Main.testVecReplicateScalar() scheduler (before) /// CHECK: Phi loop:<> outer_loop:none /// CHECK: NewArray loop:<> outer_loop:none /// CHECK: VecReplicateScalar loop:<> outer_loop:none /// CHECK-START-ARM64: void Main.testVecReplicateScalar() scheduler (after) /// CHECK: Phi loop:<> outer_loop:none /// CHECK: NewArray loop:<> outer_loop:none /// CHECK: VecReplicateScalar loop:<> outer_loop:none private static void testVecReplicateScalar() { for (int j = 0; j <= 8; j++) { int[] a = new int[ARRAY_SIZE]; for (int i = 0; i < a.length; i++) { a[i] += 1; } for (int i = 0; i < a.length; i++) { expectEquals(1, a[i]); } } } // Check that VecSetScalars, VecReduce, VecExtractScalar are not reordered. /// CHECK-START-ARM64: void Main.testVecSetScalars() scheduler (before) /// CHECK: Phi loop:<> outer_loop:none /// CHECK: NewArray loop:<> outer_loop:none /// CHECK: VecSetScalars loop:<> outer_loop:none // /// CHECK: VecReduce loop:<> outer_loop:none /// CHECK: VecExtractScalar loop:<> outer_loop:none /// CHECK: InvokeStaticOrDirect loop:<> outer_loop:none /// CHECK: InvokeStaticOrDirect loop:<> outer_loop:none /// CHECK-START-ARM64: void Main.testVecSetScalars() scheduler (after) /// CHECK: Phi loop:<> outer_loop:none /// CHECK: NewArray loop:<> outer_loop:none /// CHECK: VecSetScalars loop:<> outer_loop:none // /// CHECK: VecReduce loop:<> outer_loop:none /// CHECK: VecExtractScalar loop:<> outer_loop:none /// CHECK: InvokeStaticOrDirect loop:<> outer_loop:none /// CHECK: InvokeStaticOrDirect loop:<> outer_loop:none private static void testVecSetScalars() { for (int j = 0; j <= 8; j++) { int[] a = new int[ARRAY_SIZE]; int s = 5; for (int i = 0; i < ARRAY_SIZE; i++) { s+=a[i]; } expectEquals(a[0], 0); expectEquals(s, 5); } } public static void main(String[] args) { testVecSetScalars(); testVecReplicateScalar(); if ((arrayAccess() + intDiv(10)) != -35) { System.out.println("FAIL"); } } }