jdk/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java
Leo Korinth 55e7af0560 8260555: Change the default TIMEOUT_FACTOR from 4 to 1
Reviewed-by: alanb, sspitsyn, lmesnik, ihse
2025-09-02 07:27:12 +00:00

1008 lines
45 KiB
Java

/*
* Copyright (c) 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.
*
* 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 compiler.loopopts.superword;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Utils;
import jdk.internal.misc.Unsafe;
import java.lang.reflect.Array;
import java.util.Map;
import java.util.HashMap;
import java.util.Random;
import java.lang.foreign.*;
/*
* @test
* @bug 8343685 8331659
* @summary Test vectorization with various invariants that are equivalent, but not trivially so,
* i.e. where the invariants have the same summands, but in a different order.
* @modules java.base/jdk.internal.misc
* @library /test/lib /
* @run driver/timeout=4800 compiler.loopopts.superword.TestEquivalentInvariants
*/
public class TestEquivalentInvariants {
static int RANGE = 1024*64;
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final Random RANDOM = Utils.getRandomInstance();
// Inputs
byte[] aB;
byte[] bB;
int[] aI;
int[] bI;
long[] aL;
long[] bL;
// List of tests
Map<String,TestFunction> tests = new HashMap<String,TestFunction>();
// List of gold, the results from the first run before compilation
Map<String,Object[]> golds = new HashMap<String,Object[]>();
interface TestFunction {
Object[] run();
}
public static void main(String[] args) {
TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
"-XX:-AlignVector");
TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
"-XX:+AlignVector");
}
public TestEquivalentInvariants() {
// Generate input once
aB = generateB();
bB = generateB();
aI = generateI();
bI = generateI();
aL = generateL();
bL = generateL();
// Add all tests to list
tests.put("testArrayBB", () -> {
return testArrayBB(aB.clone(), bB.clone());
});
tests.put("testArrayBBInvar3", () -> {
return testArrayBBInvar3(aB.clone(), bB.clone(), 0, 0, 0);
});
tests.put("testMemorySegmentB", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentB(data);
});
tests.put("testMemorySegmentBInvarI", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarI(data, 101, RANGE-200);
});
tests.put("testMemorySegmentBInvarL", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarL(data, 101, RANGE-200);
});
tests.put("testMemorySegmentBInvarIAdr", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarIAdr(data, 101, RANGE-200);
});
tests.put("testMemorySegmentBInvarLAdr", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarLAdr(data, 101, RANGE-200);
});
tests.put("testMemorySegmentBInvarI3a", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarI3a(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentBInvarI3b", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarI3b(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentBInvarI3c", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarI3c(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentBInvarI3d", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarI3d(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentBInvarI3e", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarI3e(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentBInvarI3f", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarI3f(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentBInvarL3g", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarL3g(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentBInvarL3h", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarL3h(data, -1, -2, -3, RANGE-200);
});
tests.put("testMemorySegmentBInvarL3k", () -> {
MemorySegment data = MemorySegment.ofArray(aB.clone());
return testMemorySegmentBInvarL3k(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3a", () -> {
MemorySegment data = MemorySegment.ofArray(aI.clone());
return testMemorySegmentIInvarL3a(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3b", () -> {
MemorySegment data = MemorySegment.ofArray(aI.clone());
return testMemorySegmentIInvarL3b(data, -1, -2, -3, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3c", () -> {
MemorySegment data = MemorySegment.ofArray(aI.clone());
return testMemorySegmentIInvarL3c(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3d", () -> {
MemorySegment data = MemorySegment.ofArray(aI.clone());
return testMemorySegmentIInvarL3d(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3d2", () -> {
MemorySegment data = MemorySegment.ofArray(aI.clone());
return testMemorySegmentIInvarL3d2(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3d3", () -> {
MemorySegment data = MemorySegment.ofArray(aI.clone());
return testMemorySegmentIInvarL3d3(data, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3e", () -> {
MemorySegment data = MemorySegment.ofArray(aI.clone());
return testMemorySegmentIInvarL3e(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3f", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentIInvarL3f(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentIInvarL3g", () -> {
MemorySegment data = MemorySegment.ofArray(aI.clone());
return testMemorySegmentIInvarL3g(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentLInvarL3a", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentLInvarL3a(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentLInvarL3b", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentLInvarL3b(data, -1, -2, -3, RANGE-200);
});
tests.put("testMemorySegmentLInvarL3c", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentLInvarL3c(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentLInvarL3d", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentLInvarL3d(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentLInvarL3d2", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentLInvarL3d2(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentLInvarL3d3", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentLInvarL3d3(data, RANGE-200);
});
tests.put("testMemorySegmentLInvarL3e", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentLInvarL3e(data, 1, 2, 3, RANGE-200);
});
tests.put("testMemorySegmentLInvarL3f", () -> {
MemorySegment data = MemorySegment.ofArray(aL.clone());
return testMemorySegmentLInvarL3f(data, 1, 2, 3, RANGE-200);
});
tests.put("testLargeInvariantSum", () -> {
return testLargeInvariantSum(aB.clone(), 0, 0, 0, RANGE-200);
});
// Compute gold value for all test methods before compilation
for (Map.Entry<String,TestFunction> entry : tests.entrySet()) {
String name = entry.getKey();
TestFunction test = entry.getValue();
Object[] gold = test.run();
golds.put(name, gold);
}
}
@Warmup(100)
@Run(test = {"testArrayBB",
"testArrayBBInvar3",
"testMemorySegmentB",
"testMemorySegmentBInvarI",
"testMemorySegmentBInvarL",
"testMemorySegmentBInvarIAdr",
"testMemorySegmentBInvarLAdr",
"testMemorySegmentBInvarI3a",
"testMemorySegmentBInvarI3b",
"testMemorySegmentBInvarI3c",
"testMemorySegmentBInvarI3d",
"testMemorySegmentBInvarI3e",
"testMemorySegmentBInvarI3f",
"testMemorySegmentBInvarL3g",
"testMemorySegmentBInvarL3h",
"testMemorySegmentBInvarL3k",
"testMemorySegmentIInvarL3a",
"testMemorySegmentIInvarL3b",
"testMemorySegmentIInvarL3c",
"testMemorySegmentIInvarL3d",
"testMemorySegmentIInvarL3d2",
"testMemorySegmentIInvarL3d3",
"testMemorySegmentIInvarL3e",
"testMemorySegmentIInvarL3f",
"testMemorySegmentIInvarL3g",
"testMemorySegmentLInvarL3a",
"testMemorySegmentLInvarL3b",
"testMemorySegmentLInvarL3c",
"testMemorySegmentLInvarL3d",
"testMemorySegmentLInvarL3d2",
"testMemorySegmentLInvarL3d3",
"testMemorySegmentLInvarL3e",
"testMemorySegmentLInvarL3f",
"testLargeInvariantSum"})
public void runTests() {
for (Map.Entry<String,TestFunction> entry : tests.entrySet()) {
String name = entry.getKey();
TestFunction test = entry.getValue();
// Recall gold value from before compilation
Object[] gold = golds.get(name);
// Compute new result
Object[] result = test.run();
// Compare gold and new result
verify(name, gold, result);
}
}
static byte[] generateB() {
byte[] a = new byte[RANGE];
for (int i = 0; i < a.length; i++) {
a[i] = (byte)RANDOM.nextInt();
}
return a;
}
static short[] generateS() {
short[] a = new short[RANGE];
for (int i = 0; i < a.length; i++) {
a[i] = (short)RANDOM.nextInt();
}
return a;
}
static int[] generateI() {
int[] a = new int[RANGE];
for (int i = 0; i < a.length; i++) {
a[i] = RANDOM.nextInt();
}
return a;
}
static long[] generateL() {
long[] a = new long[RANGE];
for (int i = 0; i < a.length; i++) {
a[i] = RANDOM.nextLong();
}
return a;
}
static void verify(String name, Object[] gold, Object[] result) {
if (gold.length != result.length) {
throw new RuntimeException("verify " + name + ": not the same number of outputs: gold.length = " +
gold.length + ", result.length = " + result.length);
}
for (int i = 0; i < gold.length; i++) {
Object g = gold[i];
Object r = result[i];
if (g == r) {
throw new RuntimeException("verify " + name + ": should be two separate objects (with identical content):" +
" gold[" + i + "] == result[" + i + "]");
}
// Wrap everything in MemorySegments, this allows simple value verification of Array as well as MemorySegment.
MemorySegment mg = null;
MemorySegment mr = null;
if (g.getClass().isArray()) {
if (g.getClass() != r.getClass() || !g.getClass().isArray() || !r.getClass().isArray()) {
throw new RuntimeException("verify " + name + ": must both be array of same type:" +
" gold[" + i + "].getClass() = " + g.getClass().getSimpleName() +
" result[" + i + "].getClass() = " + r.getClass().getSimpleName());
}
if (Array.getLength(g) != Array.getLength(r)) {
throw new RuntimeException("verify " + name + ": arrays must have same length:" +
" gold[" + i + "].length = " + Array.getLength(g) +
" result[" + i + "].length = " + Array.getLength(r));
}
Class c = g.getClass().getComponentType();
if (c == byte.class) {
mg = MemorySegment.ofArray((byte[])g);
mr = MemorySegment.ofArray((byte[])r);
} else if (c == int.class) {
mg = MemorySegment.ofArray((int[])g);
mr = MemorySegment.ofArray((int[])r);
} else if (c == long.class) {
mg = MemorySegment.ofArray((long[])g);
mr = MemorySegment.ofArray((long[])r);
} else {
throw new RuntimeException("verify " + name + ": array type not supported for verify:" +
" gold[" + i + "].getClass() = " + g.getClass().getSimpleName() +
" result[" + i + "].getClass() = " + r.getClass().getSimpleName());
}
} else if (g instanceof MemorySegment) {
mg = (MemorySegment)g;
if (!(r instanceof MemorySegment)) {
throw new RuntimeException("verify " + name + ": was not both MemorySegment:" +
" gold[" + i + "].getClass() = " + g.getClass().getSimpleName() +
" result[" + i + "].getClass() = " + r.getClass().getSimpleName());
}
mr = (MemorySegment)r;
}
if (mg.byteSize() != mr.byteSize()) {
throw new RuntimeException("verify " + name + ": memory segment must have same length:" +
" gold[" + i + "].length = " + mg.byteSize() +
" result[" + i + "].length = " + mr.byteSize());
}
verifyMS(name, i, mg, mr);
}
}
static void verifyMS(String name, int i, MemorySegment g, MemorySegment r) {
for (long j = 0; j < g.byteSize(); j++) {
byte vg = g.get(ValueLayout.JAVA_BYTE, j);
byte vr = r.get(ValueLayout.JAVA_BYTE, j);
if (vg != vr) {
throw new RuntimeException("verify " + name + ": arrays must have same content:" +
" gold[" + i + "][" + j + "] = " + vg +
" result[" + i + "][" + j + "] = " + vr);
}
}
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testArrayBB(byte[] a, byte[] b) {
for (int i = 0; i < a.length; i++) {
b[i+0] = (byte)(a[i] + 1);
}
return new Object[]{ a, b };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// Same int invariant summands, but added in a different order.
static Object[] testArrayBBInvar3(byte[] a, byte[] b, int invar1, int invar2, int invar3) {
int i1 = invar1 + invar2 + invar3;
int i2 = invar2 + invar3 + invar1;
for (int i = 0; i < a.length; i++) {
b[i + i1] = (byte)(a[i + i2] + 1);
}
return new Object[]{ a, b };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// Just a simple pattern, without any (explicit) invariant.
static Object[] testMemorySegmentB(MemorySegment m) {
for (int i = 0; i < (int)m.byteSize(); i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i);
m.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// Does not vectorize: RangeChecks are not eliminated.
// Filed RFE: JDK-8327209
static Object[] testMemorySegmentBInvarI(MemorySegment m, int invar, int size) {
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + invar);
m.set(ValueLayout.JAVA_BYTE, i + invar, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// Has different invariants, before sorting:
//
// 3125 AddL = ((CastLL(Param 11) + ConvI2L(1460 Phi)) + 530 LoadL)
// 3127 AddL = (ConvI2L(1460 Phi) + (11 Param + 530 LoadL))
//
static Object[] testMemorySegmentBInvarL(MemorySegment m, long invar, int size) {
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + invar);
m.set(ValueLayout.JAVA_BYTE, i + invar, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// Does not vectorize: RangeChecks are not eliminated.
// Filed RFE: JDK-8327209
static Object[] testMemorySegmentBInvarIAdr(MemorySegment m, int invar, int size) {
for (int i = 0; i < size; i++) {
long adr = i + invar;
byte v = m.get(ValueLayout.JAVA_BYTE, adr);
m.set(ValueLayout.JAVA_BYTE, adr, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// Since we add "i + invar", the invariant is already equivalent without sorting.
static Object[] testMemorySegmentBInvarLAdr(MemorySegment m, long invar, int size) {
for (int i = 0; i < size; i++) {
long adr = i + invar;
byte v = m.get(ValueLayout.JAVA_BYTE, adr);
m.set(ValueLayout.JAVA_BYTE, adr, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentBInvarI3a(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3 + invar1); // equivalent
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + i1);
m.set(ValueLayout.JAVA_BYTE, i + i2, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentBInvarI3b(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3 + invar1); // equivalent
for (int i = 0; i < size; i+=2) {
byte v0 = m.get(ValueLayout.JAVA_BYTE, i + i1 + 0);
byte v1 = m.get(ValueLayout.JAVA_BYTE, i + i2 + 1);
m.set(ValueLayout.JAVA_BYTE, i + i1 + 0, (byte)(v0 + 1));
m.set(ValueLayout.JAVA_BYTE, i + i2 + 1, (byte)(v1 + 1));
}
return new Object[]{ m };
}
@Test
// Currently, we don't vectorize. But we may vectorize this, once we implement something like aliasing analysis,
// though in this particular case we know that the values at runtime will alias.
static Object[] testMemorySegmentBInvarI3c(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3) + (long)(invar1); // not equivalent!
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + i1);
m.set(ValueLayout.JAVA_BYTE, i + i2, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentBInvarI3d(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3) + (long)(invar1);
for (int i = 0; i < size; i+=2) {
byte v0 = m.get(ValueLayout.JAVA_BYTE, i + i1 + 0);
byte v1 = m.get(ValueLayout.JAVA_BYTE, i + i2 + 1);
m.set(ValueLayout.JAVA_BYTE, i + i1 + 0, (byte)(v0 + 1));
m.set(ValueLayout.JAVA_BYTE, i + i2 + 1, (byte)(v1 + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentBInvarI3e(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(invar1 + invar2 - invar3);
long i2 = (long)(invar2 - invar3 + invar1); // equivalent
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + i1);
m.set(ValueLayout.JAVA_BYTE, i + i2, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentBInvarI3f(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(invar1 - (invar2 - invar3));
long i2 = (long)(-invar2 + invar3 + invar1); // equivalent
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + i1);
m.set(ValueLayout.JAVA_BYTE, i + i2, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentBInvarL3g(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = invar1 - (invar2 - invar3);
long i2 = -invar2 + invar3 + invar1; // equivalent
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + i1);
m.set(ValueLayout.JAVA_BYTE, i + i2, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentBInvarL3h(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = -invar1 - invar2 - invar3;
long i2 = -invar2 - invar3 - invar1; // equivalent
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + i1);
m.set(ValueLayout.JAVA_BYTE, i + i2, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
IRNode.ADD_VB, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentBInvarL3k(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = -invar1 + invar2 + invar3;
long i2 = invar2 + invar3 - invar1; // equivalent
for (int i = 0; i < size; i++) {
byte v = m.get(ValueLayout.JAVA_BYTE, i + i1);
m.set(ValueLayout.JAVA_BYTE, i + i2, (byte)(v + 1));
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
IRNode.ADD_VI, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentIInvarL3a(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = invar1 + invar2 + invar3;
long i2 = invar2 + invar3 + invar1; // equivalent
for (int i = 0; i < size; i++) {
int v = m.getAtIndex(ValueLayout.JAVA_INT, i + i1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i2, v + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
IRNode.ADD_VI, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentIInvarL3b(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = -invar1 - invar2 - invar3;
long i2 = -invar2 - invar3 - invar1; // equivalent
for (int i = 0; i < size; i++) {
int v = m.getAtIndex(ValueLayout.JAVA_INT, i + i1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i2, v + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
IRNode.ADD_VI, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentIInvarL3c(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = -invar1 + invar2 + invar3;
long i2 = invar2 + invar3 - invar1; // equivalent
for (int i = 0; i < size; i++) {
int v = m.getAtIndex(ValueLayout.JAVA_INT, i + i1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i2, v + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
@IR(counts = {IRNode.LOAD_VECTOR_I, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization.
static Object[] testMemorySegmentIInvarL3d(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(-invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3 - invar1); // equivalent
for (int i = 0; i < size; i+=2) {
int v0 = m.getAtIndex(ValueLayout.JAVA_INT, i + i1 + 0);
int v1 = m.getAtIndex(ValueLayout.JAVA_INT, i + i2 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i1 + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i2 + 1, v1 + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
@IR(counts = {IRNode.LOAD_VECTOR_I, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization.
static Object[] testMemorySegmentIInvarL3d2(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(-invar1 + invar2 + invar3);
for (int i = 0; i < size; i+=2) {
int v0 = m.getAtIndex(ValueLayout.JAVA_INT, i + i1 + 0);
int v1 = m.getAtIndex(ValueLayout.JAVA_INT, i + i1 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i1 + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i1 + 1, v1 + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
IRNode.ADD_VI, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// But here the "offsetPlain" is folded away
static Object[] testMemorySegmentIInvarL3d3(MemorySegment m, int size) {
for (int i = 0; i < size; i+=2) {
int v0 = m.getAtIndex(ValueLayout.JAVA_INT, i + 0);
int v1 = m.getAtIndex(ValueLayout.JAVA_INT, i + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + 1, v1 + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
@IR(counts = {IRNode.LOAD_VECTOR_I, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization.
static Object[] testMemorySegmentIInvarL3e(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(-invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3) - (long)(invar1); // not equivalent
for (int i = 0; i < size; i+=2) {
int v0 = m.getAtIndex(ValueLayout.JAVA_INT, i + i1 + 0);
int v1 = m.getAtIndex(ValueLayout.JAVA_INT, i + i2 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i1 + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i2 + 1, v1 + 1);
}
return new Object[]{ m };
}
// Same as testMemorySegmentIInvarL3e, but with long[] input.
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// Should never vectorize, since i1 and i2 are not guaranteed to be adjacent
// invar2 + invar3 could overflow, and the address be valid with and without overflow.
// So both addresses are valid, and not adjacent.
static Object[] testMemorySegmentIInvarL3f(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(-invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3) - (long)(invar1); // not equivalent
for (int i = 0; i < size; i+=2) {
int v0 = m.getAtIndex(ValueLayout.JAVA_INT, i + i1 + 0);
int v1 = m.getAtIndex(ValueLayout.JAVA_INT, i + i2 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i1 + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_INT, i + i2 + 1, v1 + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
IRNode.ADD_VI, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentIInvarL3g(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = -invar1 + invar2 + invar3;
long i2 = invar2 + invar3 - invar1; // equivalent
for (int i = 0; i < size; i++) {
// Scale the index manually
int v = m.get(ValueLayout.JAVA_INT, 4 * (i + i1));
m.set(ValueLayout.JAVA_INT, 4 * (i + i2), v + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_L, "> 0",
IRNode.ADD_VL, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentLInvarL3a(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = invar1 + invar2 + invar3;
long i2 = invar2 + invar3 + invar1; // equivalent
for (int i = 0; i < size; i++) {
long v = m.getAtIndex(ValueLayout.JAVA_LONG, i + i1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i2, v + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_L, "> 0",
IRNode.ADD_VL, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentLInvarL3b(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = -invar1 - invar2 - invar3;
long i2 = -invar2 - invar3 - invar1; // equivalent
for (int i = 0; i < size; i++) {
long v = m.getAtIndex(ValueLayout.JAVA_LONG, i + i1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i2, v + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_L, "> 0",
IRNode.ADD_VL, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentLInvarL3c(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = -invar1 + invar2 + invar3;
long i2 = invar2 + invar3 - invar1; // equivalent
for (int i = 0; i < size; i++) {
long v = m.getAtIndex(ValueLayout.JAVA_LONG, i + i1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i2, v + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_L, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
@IR(counts = {IRNode.LOAD_VECTOR_L, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization.
static Object[] testMemorySegmentLInvarL3d(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(-invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3 - invar1); // equivalent
for (int i = 0; i < size; i+=2) {
long v0 = m.getAtIndex(ValueLayout.JAVA_LONG, i + i1 + 0);
long v1 = m.getAtIndex(ValueLayout.JAVA_LONG, i + i2 + 1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i1 + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i2 + 1, v1 + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_L, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
@IR(counts = {IRNode.LOAD_VECTOR_L, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization.
static Object[] testMemorySegmentLInvarL3d2(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(-invar1 + invar2 + invar3);
for (int i = 0; i < size; i+=2) {
long v0 = m.getAtIndex(ValueLayout.JAVA_LONG, i + i1 + 0);
long v1 = m.getAtIndex(ValueLayout.JAVA_LONG, i + i1 + 1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i1 + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i1 + 1, v1 + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_L, "> 0",
IRNode.ADD_VL, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// But here the "offsetPlain" is folded away
static Object[] testMemorySegmentLInvarL3d3(MemorySegment m, int size) {
for (int i = 0; i < size; i+=2) {
long v0 = m.getAtIndex(ValueLayout.JAVA_LONG, i + 0);
long v1 = m.getAtIndex(ValueLayout.JAVA_LONG, i + 1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + 1, v1 + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_L, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
@IR(counts = {IRNode.LOAD_VECTOR_L, "= 0",
IRNode.STORE_VECTOR, "= 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
// With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization.
static Object[] testMemorySegmentLInvarL3e(MemorySegment m, int invar1, int invar2, int invar3, int size) {
long i1 = (long)(-invar1 + invar2 + invar3);
long i2 = (long)(invar2 + invar3) - (long)(invar1); // not equivalent
for (int i = 0; i < size; i+=2) {
long v0 = m.getAtIndex(ValueLayout.JAVA_LONG, i + i1 + 0);
long v1 = m.getAtIndex(ValueLayout.JAVA_LONG, i + i2 + 1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i1 + 0, v0 + 1);
m.setAtIndex(ValueLayout.JAVA_LONG, i + i2 + 1, v1 + 1);
}
return new Object[]{ m };
}
@Test
@IR(counts = {IRNode.LOAD_VECTOR_L, "> 0",
IRNode.ADD_VL, "> 0",
IRNode.STORE_VECTOR, "> 0"},
applyIfPlatform = {"64-bit", "true"},
applyIf = {"AlignVector", "false"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"})
static Object[] testMemorySegmentLInvarL3f(MemorySegment m, long invar1, long invar2, long invar3, int size) {
long i1 = -invar1 + invar2 + invar3;
long i2 = invar2 + invar3 - invar1; // equivalent
for (int i = 0; i < size; i++) {
// Scale the index manually
long v = m.get(ValueLayout.JAVA_LONG, 8 * (i + i1));
m.set(ValueLayout.JAVA_LONG, 8 * (i + i2), v + 1);
}
return new Object[]{ m };
}
@Test
// Traversal through AddI would explode in exponentially many paths, exhausing the node limit.
// For this, we have a traversal size limit.
static Object[] testLargeInvariantSum(byte[] a, int invar1, int invar2, int invar3, int size) {
int e = invar1;
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
e = ((e + invar2) + (e + invar3));
for (int i = 0; i < size; i++) {
a[i + e] += 1;
}
return new Object[]{ a };
}
}