Skip to content

Commit

Permalink
[GR-61410] Intrinsic for AArch64 Arrays.fill(array, constant)
Browse files Browse the repository at this point in the history
PullRequest: graal/19812
  • Loading branch information
gergo- committed Jan 29, 2025
2 parents 4664c29 + 60109a4 commit 9ad216f
Show file tree
Hide file tree
Showing 15 changed files with 1,116 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 jdk.graal.compiler.replacements.test;

import java.util.Arrays;

import org.junit.Assume;
import org.junit.Test;

import jdk.graal.compiler.nodes.Invoke;
import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import jdk.graal.compiler.replacements.ConstantBindingParameterPlugin;
import jdk.graal.compiler.replacements.nodes.ArrayFillNode;
import jdk.vm.ci.aarch64.AArch64;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.meta.ResolvedJavaMethod;

public class ArraysFillTest extends ArraysSubstitutionsTestBase {
private static final int[] LENGTHS = {0, 1, 2, 3, 4, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 31, 65, 127, 255, 1023, 1024, 1025};

private void testFills(Class<?> type, Object constant) {
Assume.assumeTrue((getTarget().arch instanceof AArch64));
for (int length : LENGTHS) {
testFillsSubstitution(new ArraysFillTestConfig(type, length, constant));
}
}

@Test
public void testFillBooleanFalse() {
testFills(boolean.class, false);
}

@Test
public void testFillBooleanTrue() {
testFills(boolean.class, true);
}

@Test
public void testFillCharA() {
testFills(char.class, 'A');
}

@Test
public void testFillChar0() {
testFills(char.class, '0');
}

@Test
public void testFillByteMin() {
testFills(byte.class, Byte.MIN_VALUE);
}

@Test
public void testFillByteMax() {
testFills(byte.class, Byte.MAX_VALUE);
}

@Test
public void testFillShortMin() {
testFills(short.class, Short.MIN_VALUE);
}

@Test
public void testFillShortMax() {
testFills(short.class, Short.MAX_VALUE);
}

@Test
public void testFillIntMin() {
testFills(int.class, Integer.MIN_VALUE);
}

@Test
public void testFillIntMax() {
testFills(int.class, Integer.MAX_VALUE);
}

@Test
public void testFillLongMin() {
testFills(long.class, Long.MIN_VALUE);
}

@Test
public void testFillLongMax() {
testFills(long.class, Long.MAX_VALUE);
}

@Test
public void testFillFloatMin() {
testFills(float.class, Float.MIN_VALUE);
}

@Test
public void testFillFloatMax() {
testFills(float.class, Float.MAX_VALUE);
}

@Test
public void testFillDoubleMin() {
testFills(double.class, Double.MIN_VALUE);
}

@Test
public void testFillDoubleMax() {
testFills(double.class, Double.MAX_VALUE);
}

private Object[] constantArgs;

@Override
protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
if (constantArgs != null) {
ConstantBindingParameterPlugin constantBinding = new ConstantBindingParameterPlugin(constantArgs, this.getMetaAccess(), this.getSnippetReflection());
conf.getPlugins().appendParameterPlugin(constantBinding);
}
return super.editGraphBuilderConfiguration(conf);
}

protected void testFillsSubstitution(ArraysFillTestConfig config) {
ResolvedJavaMethod realMethod = getResolvedJavaMethod(Arrays.class, "fill", config.parameterType());
ResolvedJavaMethod testMethod = getResolvedJavaMethod(config.testMethodName());
StructuredGraph graph = testGraph(config.testMethodName());

// Check to see if the resulting graph contains the expected node
StructuredGraph replacement = getReplacements().getInlineSubstitution(realMethod, 0, false, Invoke.InlineControl.Normal, false, null, graph.allowAssumptions(), graph.getOptions());
if (replacement == null) {
assertInGraph(graph, ArrayFillNode.class);
}

// Force compilation
InstalledCode code = getCode(testMethod, null, true);
assert code != null;

Object array1 = config.newArray();
Object array2 = config.newArray();
Object array3 = config.newArray();

invokeSafe(realMethod, null, array1, config.getConstant());
invokeSafe(testMethod, null, array2, config.getConstant());
executeVarargsSafe(code, array3, config.getConstant());

// Verify that the original method and the substitution produce the same value
assertDeepEquals(array1, array2);

// Verify that the generated code and the original produce the same value
assertDeepEquals(array2, array3);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 jdk.graal.compiler.replacements.test;

import jdk.graal.compiler.replacements.test.ArraysSubstitutionsTestBase.ArrayBuilder;

class ArraysFillTestConfig {
private Class<?> type = null;
private Object constant = null;
private int length = 0;

private Object[] parameterTypes = new Object[]{
new Class<?>[]{boolean[].class, boolean.class},
new Class<?>[]{byte[].class, byte.class},
new Class<?>[]{char[].class, char.class},
new Class<?>[]{short[].class, short.class},
new Class<?>[]{int[].class, int.class},
new Class<?>[]{long[].class, long.class},
new Class<?>[]{float[].class, float.class},
new Class<?>[]{double[].class, double.class}
};

private ArrayBuilder[] builders = new ArrayBuilder[]{
ArraysSubstitutionsTestBase::booleanArray,
ArraysSubstitutionsTestBase::byteArray,
ArraysSubstitutionsTestBase::charArray,
ArraysSubstitutionsTestBase::shortArray,
ArraysSubstitutionsTestBase::intArray,
ArraysSubstitutionsTestBase::longArray,
ArraysSubstitutionsTestBase::floatArray,
ArraysSubstitutionsTestBase::doubleArray,
};

private String[] testMethodNames = new String[]{
"arraysFillBoolean",
"arraysFillByte",
"arraysFillChar",
"arraysFillShort",
"arraysFillInt",
"arraysFillLong",
"arraysFillFloat",
"arraysFillDouble",
};

ArraysFillTestConfig(Class<?> type, int length, Object constant) {
this.type = type;
this.length = length;
this.constant = constant;
}

public String testMethodName() throws IllegalArgumentException {
return testMethodNames[index()];
}

public Object newArray() throws IllegalArgumentException {
ArrayBuilder builder = builders[index()];
return builder.newArray(this.length, 0, 0);
}

public Class<?>[] parameterType() throws IllegalArgumentException {
return (Class<?>[]) parameterTypes[index()];
}

public Object getConstant() {
return this.constant;
}

private int index() {
if (type == boolean.class) {
return 0;
} else if (type == byte.class) {
return 1;
} else if (type == char.class) {
return 2;
} else if (type == short.class) {
return 3;
} else if (type == int.class) {
return 4;
} else if (type == long.class) {
return 5;
} else if (type == float.class) {
return 6;
} else if (type == double.class) {
return 7;
} else {
throw new IllegalArgumentException("Unexpected type for 'type' field: " + type);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,38 @@ public static boolean arraysEqualsLong(long[] a, long[] b) {
return Arrays.equals(a, b);
}

public static void arraysFillBoolean(boolean[] a, boolean b) {
Arrays.fill(a, b);
}

public static void arraysFillByte(byte[] a, byte b) {
Arrays.fill(a, b);
}

public static void arraysFillChar(char[] a, char b) {
Arrays.fill(a, b);
}

public static void arraysFillShort(short[] a, short b) {
Arrays.fill(a, b);
}

public static void arraysFillInt(int[] a, int b) {
Arrays.fill(a, b);
}

public static void arraysFillLong(long[] a, long b) {
Arrays.fill(a, b);
}

public static void arraysFillFloat(float[] a, float b) {
Arrays.fill(a, b);
}

public static void arraysFillDouble(double[] a, double b) {
Arrays.fill(a, b);
}

interface ArrayBuilder {
Object newArray(int length, int firstValue, int lastValue);
}
Expand Down Expand Up @@ -150,4 +182,32 @@ static long[] longArray(int length, int firstValue, int lastValue) {
}
return arr;
}

static float[] floatArray(int length, float firstValue, float lastValue) {
float[] arr = new float[length];
for (int i = 0; i < length; i++) {
arr[i] = i;
}
if (length > 0) {
arr[0] = firstValue;
}
if (length > 1) {
arr[length - 1] = lastValue;
}
return arr;
}

static double[] doubleArray(int length, double firstValue, double lastValue) {
double[] arr = new double[length];
for (int i = 0; i < length; i++) {
arr[i] = i;
}
if (length > 0) {
arr[0] = firstValue;
}
if (length > 1) {
arr[length - 1] = lastValue;
}
return arr;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2449,6 +2449,21 @@ public void bfm(int size, Register dst, Register src, int r, int s) {
bitfieldInstruction(BFM, dst, src, r, s, generalFromSize(size));
}

/**
* C6.2.30 Bitfield insert.
*
* @param size register size. Has to be 32 or 64.
* @param dst general purpose register. May not be null, stackpointer or zero-register.
* @param src general purpose register. May not be null, stackpointer or zero-register.
* @param lsb start index of target register to override with bits from src register.
* @param width number of bits to copy from src register.
*/
public void bfi(int size, Register dst, Register src, int lsb, int width) {
assert verifySizeAndRegistersRR(size, dst, src);

bfm(size, dst, src, ((size - lsb) & (size - 1)), (width - 1));
}

/**
* C6.2.337 Unsigned bitfield move.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import jdk.graal.compiler.lir.aarch64.AArch64ArithmeticOp;
import jdk.graal.compiler.lir.aarch64.AArch64ArrayCompareToOp;
import jdk.graal.compiler.lir.aarch64.AArch64ArrayCopyWithConversionsOp;
import jdk.graal.compiler.lir.aarch64.AArch64ArrayFillOp;
import jdk.graal.compiler.lir.aarch64.AArch64ArrayEqualsOp;
import jdk.graal.compiler.lir.aarch64.AArch64ArrayIndexOfOp;
import jdk.graal.compiler.lir.aarch64.AArch64ArrayRegionCompareToOp;
Expand Down Expand Up @@ -623,6 +624,11 @@ public void emitArrayCopyWithConversion(EnumSet<?> runtimeCheckedCPUFeatures, Va
emitConvertNullToZero(arrayDst), asAllocatable(offsetDst), emitConvertNullToZero(arraySrc), asAllocatable(offsetSrc), asAllocatable(length), asAllocatable(dynamicStrides)));
}

@Override
public void emitArrayFill(JavaKind kind, EnumSet<?> runtimeCheckedCPUFeatures, Value array, Value arrayBaseOffset, Value length, Value value) {
append(new AArch64ArrayFillOp(kind, emitConvertNullToZero(array), asAllocatable(arrayBaseOffset), asAllocatable(length), asAllocatable(value)));
}

@Override
public Variable emitArrayEquals(JavaKind kind, EnumSet<?> runtimeCheckedCPUFeatures,
Value arrayA, Value offsetA, Value arrayB, Value offsetB, Value length) {
Expand Down
Loading

0 comments on commit 9ad216f

Please sign in to comment.