/* * 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: <> 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: <> IntermediateAddress [<>,{{i\d+}}] loop:<> outer_loop:none /// CHECK: Add [<>,{{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: <> 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 original 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++; // Note: ClinitCheck(Main) is eliminated because Main initialization is trivial. b/62478025 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); } } // Check that instructions having cross iteration dependencies are not // reordered. // /// CHECK-START-{ARM,ARM64}: void Main.testCrossItersDependencies() scheduler (before) /// CHECK: <> Phi [{{i\d+}},<>] /// CHECK: <> Phi [{{i\d+}},<>] // /// CHECK: <> Sub [<>,<>] /// CHECK: <> Add [<>,{{i\d+}}] /// CHECK-START-{ARM,ARM64}: void Main.testCrossItersDependencies() scheduler (after) /// CHECK: <> Phi [{{i\d+}},<>] /// CHECK: <> Phi [{{i\d+}},<>] // /// CHECK: <> Sub [<>,<>] /// CHECK: <> Add [<>,{{i\d+}}] /// CHECK-START-ARM: void Main.testCrossItersDependencies() disassembly (after) /// CHECK: subs /// CHECK: add /// CHECK: adds /// CHECK: ldrh /// CHECK: cmp /// CHECK: beq /// CHECK-START-ARM64: void Main.testCrossItersDependencies() disassembly (after) /// CHECK: sub /// CHECK: add /// CHECK: add /// CHECK: ldrh /// CHECK: cbz private static void testCrossItersDependencies() { int[] data = {1, 2, 3, 0}; int sub = 0; int sum = data[0]; for (int i = 1; data[i] != 0; ++i) { sub -= sum; sum += data[i]; } expectEquals(sub, -4); expectEquals(sum, 6); } // Check instructions defining values for the next iteration don't become // self-dependent in a scheduling graph which prevents valid reordering. // /// CHECK-START-{ARM,ARM64}: void Main.testNoSelfDependantSchedNode(int) scheduler (before) /// CHECK: IntermediateAddress /// CHECK: ArrayGet /// CHECK: LessThanOrEqual /// CHECK: Select /// CHECK: IntermediateAddress /// CHECK: ArraySet /// CHECK: Add /// CHECK-START-{ARM,ARM64}: void Main.testNoSelfDependantSchedNode(int) scheduler (after) /// CHECK: IntermediateAddress /// CHECK: ArrayGet /// CHECK: IntermediateAddress /// CHECK: LessThanOrEqual /// CHECK: Select /// CHECK: ArraySet /// CHECK: Add // // Parameter n is to prevent unrolling of the main loop. private static void testNoSelfDependantSchedNode(int n) { final int MAX = 2; int[] a = {1, 2, 3}; int[] b = new int[a.length]; n = Math.min(n, a.length); for (int i = 0; i < n; ++i) { int j = a[i]; b[i] = (j > MAX ? MAX : 0); } expectEquals(b[0], 0); expectEquals(b[1], 0); expectEquals(b[2], 2); } // In case of cross iteration dependencies when a value for the next iteration is also used on // the current iteration a MOV instruction is generated anyway. In such cases setting dependency // between scheduling nodes will not eliminate MOV. // In the test 'i+1' is such an example. // The test checks that a dependency between scheduling nodes (first ArrayGet and Add) is not // setup and Add is scheduled before ArrayGet. // /// CHECK-START-{ARM,ARM64}: void Main.testNonPreventingSchedulingCrossItersDeps(int) scheduler (before) /// CHECK: IntermediateAddress /// CHECK-NEXT: ArrayGet /// CHECK-NEXT: Add /// CHECK-NEXT: ArrayGet /// CHECK-START-{ARM,ARM64}: void Main.testNonPreventingSchedulingCrossItersDeps(int) scheduler (after) /// CHECK: IntermediateAddress /// CHECK-NEXT: Add /// CHECK-NEXT: ArrayGet /// CHECK-NEXT: ArrayGet // // Parameter n is to prevent unrolling of the main loop. private static void testNonPreventingSchedulingCrossItersDeps(int n) { int[] a = {1, 2, 3}; n = Math.min(n, a.length); for (int i = 0; i < n - 1; ++i) { if (a[i] < a[i + 1]) { int tmp = a[i]; a[i] = a[i + 1]; a[i + 1] = tmp; } } expectEquals(a[0], 2); expectEquals(a[1], 3); expectEquals(a[2], 1); } public static void main(String[] args) { testVecSetScalars(); testVecReplicateScalar(); testCrossItersDependencies(); testNoSelfDependantSchedNode(3); testNonPreventingSchedulingCrossItersDeps(3); if ((arrayAccess() + intDiv(10)) != -35) { System.out.println("FAIL"); } } }