Skip to content

Commit

Permalink
Use add(extended) to generate array index offset for AArch64.
Browse files Browse the repository at this point in the history
We want to find a better way to implement array offset calculation.
The old pattern for an int array member loading is:
       and      x4, x3, #0xffffffff
       lsl      x4, x4, #2
       add      x4, x4, #0x10
       ldr      x0, [x2, x4]

And the optimized pattern is:
       add      x1, x2, w3, uxtw #2
       ldr      x0, [x1, oracle#16]

Here is a jmh unit test for int array member loading:
    private final int func(int[] arr) {
        int ret = 0;
        for (int i=0; i < field0; i++) {
            ret += arr[i];
        }
        return ret;
    }
And the jmh performance results:
     without this patch   with this patch   units
         1173501.595        948290.420      us/op

Here are the additional issues fixed related to this patch:
1. Fix an issue in MatchProcessor, so that we can process platform specific node
as a matchable node.

2. Close this optimization for substratevm because the derived reference is not
supported yet in SVM.

mx bootstrap passes.
mx gate -o -t 'CTW:hosted' passes.

Change-Id: Ia34f2bf044ca6863be075cf000b29524ca44c42d
  • Loading branch information
Xiaohong Gong authored and Stefan Anzinger committed Jan 7, 2020
1 parent 4c4c075 commit 98b22c6
Show file tree
Hide file tree
Showing 10 changed files with 477 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.aarch64.test;

import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ExtendedAddShiftOp;
import org.junit.Test;

import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;

public class AArch64ArrayAddressTest extends AArch64MatchRuleTest {
private static final Predicate<LIRInstruction> predicate = op -> (op instanceof ExtendedAddShiftOp);

public static byte loadByte(byte[] arr, int n) {
return arr[n];
}

@Test
public void testLoadByte() {
byte[] arr = {3, 4, 5, 6, 7, 8};
test("loadByte", arr, 5);
checkLIR("loadByte", predicate, 1, 1);
}

public static char loadChar(char[] arr, int n) {
return arr[n];
}

@Test
public void testLoadChar() {
char[] arr = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
test("loadChar", arr, 5);
checkLIR("loadChar", predicate, 1, 1);
}

public static short loadShort(short[] arr, int n) {
return arr[n];
}

@Test
public void testLoadShort() {
short[] arr = {3, 4, 5, 6, 7, 8};
test("loadShort", arr, 5);
checkLIR("loadShort", predicate, 1, 1);
}

public static int loadInt(int[] arr, int n) {
return arr[n];
}

@Test
public void testLoadInt() {
int[] arr = {3, 4, 5, 6, 7, 8};
test("loadInt", arr, 5);
checkLIR("loadInt", predicate, 1, 1);
}

public static long loadLong(long[] arr, int n) {
return arr[n];
}

@Test
public void testLoadLong() {
long[] arr = {3L, 4L, 5L, 6L, 7L, 8L};
test("loadLong", arr, 5);
checkLIR("loadLong", predicate, 1, 1);
}

public static float loadFloat(float[] arr, int n) {
return arr[n];
}

@Test
public void testLoadFloat() {
float[] arr = {3.0F, 4.0F, 5.0F, 6.0F, 7.0F, 8.0F};
test("loadFloat", arr, 5);
checkLIR("loadFloat", predicate, 1, 1);
}

public static double loadDouble(double[] arr, int n) {
return arr[n];
}

@Test
public void testLoadDouble() {
double[] arr = {3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
test("loadDouble", arr, 5);
checkLIR("loadDouble", predicate, 1, 1);
}

public static String loadObject(String[] arr, int n) {
return arr[n];
}

@Test
public void testLoadObject() {
String[] arr = {"ac", "ad", "ew", "asf", "sdad", "aff"};
test("loadObject", arr, 5);
checkLIRforAll("loadObject", predicate, 1);
}

public static int storeInt(int[] arr, int n) {
arr[n] = n * n;
return arr[n];
}

@Test
public void testStoreInt() {
int[] arr = {3, 4, 5, 6, 7, 8};
test("storeInt", arr, 5);
checkLIRforAll("storeInt", predicate, 1);
}

public static Integer loadAndStoreObject(Integer[] arr, int i) {
if (arr[i] > 0) {
return 0;
}
arr[i] += 3;
return arr[i];
}

@Test
public void testLoadAndStoreObject() {
Integer[] arr = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
test("loadAndStoreObject", arr, 2);
checkLIRforAll("loadAndStoreObject", predicate, 2);
}

public static int useArrayInLoop(int[] arr) {
int ret = 0;
for (int i = 0; i < arr.length; i++) {
ret += arr[i];
}
return ret;
}

@Test
public void testUseArrayInLoop() {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8};
test("useArrayInLoop", arr);
checkLIRforAll("useArrayInLoop", predicate, 1);
}

public static int useArrayDeque(ArrayDeque<Integer> ad) {
ad.addFirst(4);
return ad.removeFirst();
}

@Test
public void testUseArrayDeque() {
ArrayDeque<Integer> ad = new ArrayDeque<>();
test("useArrayDeque", ad);
}

// Array load test when the index is narrowed firstly.
private static class Frame {
int index;

Frame(int index) {
this.index = index;
}
}

private static final Frame[] frameCache = new Frame[256];

private static Frame newFrame(byte data) {
return frameCache[data & 255];
}

public static int getFrameIndex(int n) {
return newFrame((byte) n).index;
}

@Test
public void testGetFrameIndex() {
for (int i = 0; i < 256; i++) {
frameCache[i] = new Frame(i * i);
}
test("getFrameIndex", 258);
checkLIRforAll("getFrameIndex", predicate, 1);
}

static Set<Long> allBarcodes = new HashSet<>();
static Set<Long> localBarcodes = new HashSet<>();

public static long useConstReferenceAsBase(long l) {
localBarcodes.add(l);
allBarcodes.add(l);
return l;
}

@Test
public void testUseConstReferenceAsBase() {
test("useConstReferenceAsBase", 2L);
int l = localBarcodes.size() + allBarcodes.size();
test("useConstReferenceAsBase", (long) l);
}
}
Loading

0 comments on commit 98b22c6

Please sign in to comment.