From e1811ed6b57a54dc8ebd327e4bd2c4422092a3a0 Mon Sep 17 00:00:00 2001 From: Artem Serov Date: Thu, 27 Apr 2017 16:50:47 +0100 Subject: ARM64: Share address computation across SIMD LDRs/STRs. For array accesses the element address has the following structure: Address = CONST_OFFSET + base_addr + index << ELEM_SHIFT Taking into account ARM64 LDR/STR addressing modes address part (CONST_OFFSET + index << ELEM_SHIFT) can be shared across array access with the same data type and index. For example, for the following loop 5 accesses can share address computation: void foo(int[] a, int[] b, int[] c) { for (i...) { a[i] = a[i] + 5; b[i] = b[i] + c[i]; } } Test: test-art-host, test-art-target Change-Id: I46af3b4e4a55004336672cdba3296b7622d815ca --- test/527-checker-array-access-simd/src/Main.java | 223 +++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 test/527-checker-array-access-simd/src/Main.java (limited to 'test/527-checker-array-access-simd/src/Main.java') diff --git a/test/527-checker-array-access-simd/src/Main.java b/test/527-checker-array-access-simd/src/Main.java new file mode 100644 index 0000000000..8af5465faf --- /dev/null +++ b/test/527-checker-array-access-simd/src/Main.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2017 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 static void assertIntEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + /// CHECK-START-ARM64: void Main.checkIntCase(int[]) instruction_simplifier_arm64 (before) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 5 + /// CHECK-DAG: <> VecReplicateScalar [<>] + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecAdd [<>,<>] + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkIntCase(int[]) instruction_simplifier_arm64 (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 5 + /// CHECK-DAG: <> IntConstant 12 + /// CHECK-DAG: <> IntConstant 2 + /// CHECK-DAG: <> VecReplicateScalar [<>] + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecAdd [<>,<>] + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkIntCase(int[]) GVN$after_arch (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 5 + /// CHECK-DAG: <> IntConstant 12 + /// CHECK-DAG: <> IntConstant 2 + /// CHECK-DAG: <> VecReplicateScalar [<>] + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecAdd [<>,<>] + /// CHECK-NOT: IntermediateAddress + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkIntCase(int[]) disassembly (after) + /// CHECK: IntermediateAddressIndex + /// CHECK-NEXT: add w{{[0-9]+}}, w{{[0-9]+}}, w{{[0-9]+}}, lsl #2 + public static void checkIntCase(int[] a) { + for (int i = 0; i < 128; i++) { + a[i] += 5; + } + } + + /// CHECK-START-ARM64: void Main.checkByteCase(byte[]) instruction_simplifier_arm64 (before) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 5 + /// CHECK-DAG: <> VecReplicateScalar [<>] + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecAdd [<>,<>] + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkByteCase(byte[]) instruction_simplifier_arm64 (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 5 + /// CHECK-DAG: <> IntConstant 12 + /// CHECK-DAG: <> VecReplicateScalar [<>] + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecAdd [<>,<>] + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkByteCase(byte[]) GVN$after_arch (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 5 + /// CHECK-DAG: <> IntConstant 12 + /// CHECK-DAG: <> VecReplicateScalar [<>] + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecAdd [<>,<>] + /// CHECK-NOT: IntermediateAddress + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkByteCase(byte[]) disassembly (after) + /// CHECK: IntermediateAddressIndex + /// CHECK-NEXT: add w{{[0-9]+}}, w{{[0-9]+}}, #0x{{[0-9a-fA-F]+}} + /// CHECK: VecLoad + /// CHECK-NEXT: ldr q{{[0-9]+}}, [x{{[0-9]+}}, x{{[0-9]+}}] + /// CHECK: VecStore + /// CHECK-NEXT: str q{{[0-9]+}}, [x{{[0-9]+}}, x{{[0-9]+}}] + public static void checkByteCase(byte[] a) { + for (int i = 0; i < 128; i++) { + a[i] += 5; + } + } + + /// CHECK-START-ARM64: void Main.checkSingleAccess(int[]) instruction_simplifier_arm64 (before) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 5 + /// CHECK-DAG: <> VecReplicateScalar [<>] + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkSingleAccess(int[]) instruction_simplifier_arm64 (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 5 + /// CHECK-DAG: <> VecReplicateScalar [<>] + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: VecStore [<>,<>,<>] + /// CHECK-NOT: IntermediateAddress + public static void checkSingleAccess(int[] a) { + for (int i = 0; i < 128; i++) { + a[i] = 5; + } + } + + /// CHECK-START-ARM64: void Main.checkInt2Float(int[], float[]) instruction_simplifier_arm64 (before) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> ParameterValue + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecCnv [<>] + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkInt2Float(int[], float[]) instruction_simplifier_arm64 (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 12 + /// CHECK-DAG: <> IntConstant 2 + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecCnv [<>] + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkInt2Float(int[], float[]) GVN$after_arch (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 12 + /// CHECK-DAG: <> IntConstant 2 + // -------------- Loop + /// CHECK-DAG: <> Phi + /// CHECK-DAG: If + /// CHECK-DAG: <> IntermediateAddressIndex [<>,<>,<>] + /// CHECK-DAG: <> VecLoad [<>,<>] + /// CHECK-DAG: <> VecCnv [<>] + /// CHECK-NOT: IntermediateAddress + /// CHECK-DAG: VecStore [<>,<>,<>] + + /// CHECK-START-ARM64: void Main.checkInt2Float(int[], float[]) disassembly (after) + /// CHECK: IntermediateAddressIndex + /// CHECK-NEXT: add w{{[0-9]+}}, w{{[0-9]+}}, w{{[0-9]+}}, lsl #2 + public static void checkInt2Float(int[] a, float[] b) { + for (int i = 0; i < 128; i++) { + b[i] = (float) a[i]; + } + } + + public static final int ARRAY_SIZE = 1024; + + public static int calcArraySum(int[] a, byte[] b, float[] c) { + int sum = 0; + for (int i = 0; i < 128; i++) { + sum += a[i] + b[i] + (int) c[i]; + } + return sum; + } + + public static void main(String[] args) { + byte[] ba = new byte[ARRAY_SIZE]; + int[] ia = new int[ARRAY_SIZE]; + float[] fa = new float[ARRAY_SIZE]; + + checkSingleAccess(ia); + checkIntCase(ia); + checkByteCase(ba); + checkInt2Float(ia, fa); + + assertIntEquals(3200, calcArraySum(ia, ba, fa)); + } +} -- cgit v1.2.3-59-g8ed1b