mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
915 lines
38 KiB
Java
915 lines
38 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 compiler.lib.verify.*;
|
|
import jdk.test.lib.Utils;
|
|
import java.nio.ByteBuffer;
|
|
import java.util.Map;
|
|
import java.util.HashMap;
|
|
import java.util.Random;
|
|
import java.lang.foreign.*;
|
|
|
|
/*
|
|
* @test id=byte-array
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-array-AlignVector
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-array-NoSpeculativeAliasingCheck
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoSpeculativeAliasingCheck
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-array-AlignVector-NoSpeculativeAliasingCheck
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector NoSpeculativeAliasingCheck
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-array-NoAutoAlignment
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoAutoAlignment
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-array-NoShortRunningLongLoop
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoShortRunningLongLoop
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-array-AlignVector-NoShortRunningLongLoop
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector NoShortRunningLongLoop
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoSpeculativeAliasingCheck NoShortRunningLongLoop
|
|
*/
|
|
|
|
/*
|
|
* @test id=char-array
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing CharArray
|
|
*/
|
|
|
|
/*
|
|
* @test id=short-array
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ShortArray
|
|
*/
|
|
|
|
/*
|
|
* @test id=int-array
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray
|
|
*/
|
|
|
|
/*
|
|
* @test id=int-array-AlignVector
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray AlignVector
|
|
*/
|
|
|
|
/*
|
|
* @test id=int-array-NoSpeculativeAliasingCheck
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoSpeculativeAliasingCheck
|
|
*/
|
|
|
|
/*
|
|
* @test id=int-array-AlignVector-NoSpeculativeAliasingCheck
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray AlignVector NoSpeculativeAliasingCheck
|
|
*/
|
|
|
|
/*
|
|
* @test id=int-array-NoAutoAlignment
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoAutoAlignment
|
|
*/
|
|
|
|
/*
|
|
* @test id=int-array-NoShortRunningLongLoop
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoShortRunningLongLoop
|
|
*/
|
|
|
|
/*
|
|
* @test id=int-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoSpeculativeAliasingCheck NoShortRunningLongLoop
|
|
*/
|
|
|
|
/*
|
|
* @test id=long-array
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray
|
|
*/
|
|
|
|
/*
|
|
* @test id=long-array-AlignVector
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray AlignVector
|
|
*/
|
|
|
|
/*
|
|
* @test id=long-array-NoSpeculativeAliasingCheck
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray NoSpeculativeAliasingCheck
|
|
*/
|
|
|
|
/*
|
|
* @test id=long-array-AlignVector-NoSpeculativeAliasingCheck
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray AlignVector NoSpeculativeAliasingCheck
|
|
*/
|
|
|
|
/*
|
|
* @test id=float-array
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing FloatArray
|
|
*/
|
|
|
|
/*
|
|
* @test id=double-array
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing DoubleArray
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-buffer
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteBuffer
|
|
*/
|
|
|
|
/*
|
|
* @test id=byte-buffer-direct
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteBufferDirect
|
|
*/
|
|
|
|
/*
|
|
* @test id=native
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native
|
|
*/
|
|
|
|
/*
|
|
* @test id=native-AlignVector
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector
|
|
*/
|
|
|
|
/*
|
|
* @test id=native-NoSpeculativeAliasingCheck
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoSpeculativeAliasingCheck
|
|
*/
|
|
|
|
/*
|
|
* @test id=native-AlignVector-NoSpeculativeAliasingCheck
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector NoSpeculativeAliasingCheck
|
|
*/
|
|
|
|
/*
|
|
* @test id=native-NoShortRunningLongLoop
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoShortRunningLongLoop
|
|
*/
|
|
|
|
/*
|
|
* @test id=native-AlignVector-NoShortRunningLongLoop
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector NoShortRunningLongLoop
|
|
*/
|
|
|
|
/*
|
|
* @test id=native-NoSpeculativeAliasingCheck-NoShortRunningLongLoop
|
|
* @bug 8324751
|
|
* @summary Test vectorization of loops over MemorySegment
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoSpeculativeAliasingCheck NoShortRunningLongLoop
|
|
*/
|
|
|
|
public class TestMemorySegmentAliasing {
|
|
public static void main(String[] args) {
|
|
TestFramework framework = new TestFramework(TestMemorySegmentAliasingImpl.class);
|
|
framework.addFlags("-DmemorySegmentProviderNameForTestVM=" + args[0]);
|
|
for (int i = 1; i < args.length; i++) {
|
|
String tag = args[i];
|
|
switch (tag) {
|
|
case "AlignVector" -> framework.addFlags("-XX:+AlignVector");
|
|
case "NoSpeculativeAliasingCheck" -> framework.addFlags("-XX:-UseAutoVectorizationSpeculativeAliasingChecks");
|
|
// automatic alignment has an impact on where the main-loop starts, and that affects init and limit
|
|
// of the main loop.
|
|
case "NoAutoAlignment" -> framework.addFlags("-XX:SuperWordAutomaticAlignment=0");
|
|
// Disabling the ShortRunningLongLoop optimization changes the shape of the loop.
|
|
// Testing both with and without it allows us to simulate long running loops with short running loops,
|
|
// i.e. we don't need to allocate massive amounts of memory.
|
|
case "NoShortRunningLongLoop" -> framework.addFlags("-XX:-ShortRunningLongLoop");
|
|
default -> throw new RuntimeException("Bad tag: " + tag);
|
|
}
|
|
}
|
|
framework.setDefaultWarmup(100);
|
|
framework.start();
|
|
}
|
|
}
|
|
|
|
class TestMemorySegmentAliasingImpl {
|
|
static final int BACKING_SIZE = 1024 * 8;
|
|
static final Random RANDOM = Utils.getRandomInstance();
|
|
|
|
|
|
interface TestFunction {
|
|
void run();
|
|
}
|
|
|
|
interface MemorySegmentProvider {
|
|
MemorySegment newMemorySegment();
|
|
}
|
|
|
|
public static MemorySegmentProvider provider;
|
|
|
|
static {
|
|
String providerName = System.getProperty("memorySegmentProviderNameForTestVM");
|
|
provider = switch (providerName) {
|
|
case "ByteArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteArray;
|
|
case "CharArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfCharArray;
|
|
case "ShortArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfShortArray;
|
|
case "IntArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfIntArray;
|
|
case "LongArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfLongArray;
|
|
case "FloatArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfFloatArray;
|
|
case "DoubleArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfDoubleArray;
|
|
case "ByteBuffer" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteBuffer;
|
|
case "ByteBufferDirect" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteBufferDirect;
|
|
case "Native" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfNative;
|
|
case "MixedArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixedArray;
|
|
case "MixedBuffer" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixedBuffer;
|
|
case "Mixed" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixed;
|
|
default -> throw new RuntimeException("Test argument not recognized: " + providerName);
|
|
};
|
|
}
|
|
|
|
// Map of goldTests
|
|
public static Map<String, TestFunction> goldTests = new HashMap<>();
|
|
|
|
// Map of gold for the goldTests, the results from the first run before compilation
|
|
public static Map<String, Object> golds = new HashMap<>();
|
|
|
|
// Map of referenceTests, i.e. tests that have a reference implementation that is run with the interpreter.
|
|
// The TestFunction must run both the test and reference methods.
|
|
public static Map<String, TestFunction> referenceTests = new HashMap<>();
|
|
|
|
// Original data.
|
|
public static MemorySegment ORIG_A = fillRandom(newMemorySegment());
|
|
public static MemorySegment ORIG_B = fillRandom(newMemorySegment());
|
|
public static MemorySegment ORIG_C = fillRandom(newMemorySegment());
|
|
|
|
// The data we use in the tests. It is initialized from ORIG_* every time.
|
|
public static MemorySegment A = newMemorySegment();
|
|
public static MemorySegment B = newMemorySegment();
|
|
public static MemorySegment C = newMemorySegment();
|
|
|
|
// Parallel to data above, but for use in reference methods.
|
|
public static MemorySegment A_REFERENCE = newMemorySegment();
|
|
public static MemorySegment B_REFERENCE = newMemorySegment();
|
|
public static MemorySegment C_REFERENCE = newMemorySegment();
|
|
|
|
public TestMemorySegmentAliasingImpl () {
|
|
// Add all goldTests to list
|
|
goldTests.put("test_byte_incr_noaliasing", () -> test_byte_incr_noaliasing(A, B));
|
|
goldTests.put("test_byte_incr_aliasing", () -> test_byte_incr_aliasing(A, A));
|
|
goldTests.put("test_byte_incr_aliasing_fwd3", () -> {
|
|
MemorySegment x = A.asSlice(0, BACKING_SIZE - 3);
|
|
MemorySegment y = A.asSlice(3, BACKING_SIZE - 3);
|
|
test_byte_incr_aliasing_fwd3(x, y);
|
|
});
|
|
goldTests.put("test_byte_incr_noaliasing_fwd128", () -> {
|
|
MemorySegment x = A.asSlice(0, BACKING_SIZE - 128);
|
|
MemorySegment y = A.asSlice(120, BACKING_SIZE - 128);
|
|
test_byte_incr_noaliasing_fwd128(x, y);
|
|
});
|
|
|
|
goldTests.put("test_int_to_long_noaliasing", () -> test_int_to_long_noaliasing(A, B));
|
|
|
|
// Compute gold value for all test methods before compilation
|
|
for (Map.Entry<String,TestFunction> entry : goldTests.entrySet()) {
|
|
String name = entry.getKey();
|
|
TestFunction test = entry.getValue();
|
|
init();
|
|
test.run();
|
|
Object gold = snapshotCopy();
|
|
golds.put(name, gold);
|
|
}
|
|
|
|
referenceTests.put("test_fill_byte_sameMS_alias", () -> {
|
|
int invar1 = RANDOM.nextInt(64);
|
|
int invar2 = RANDOM.nextInt(64);
|
|
test_fill_byte_sameMS_alias(A, A, invar1, invar2);
|
|
reference_fill_byte_sameMS_alias(A_REFERENCE, A_REFERENCE, invar1, invar2);
|
|
});
|
|
referenceTests.put("test_fill_byte_sameMS_noalias", () -> {
|
|
// The accesses either start at the middle and go out,
|
|
// or start from opposite sides and meet in the middle.
|
|
// But they never overlap.
|
|
// <------|------>
|
|
// ------>|<------
|
|
//
|
|
// This tests that the checks we emit are not too relaxed.
|
|
int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256);
|
|
int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256);
|
|
int invar1 = middle;
|
|
int invar2 = middle;
|
|
if (RANDOM.nextBoolean()) {
|
|
invar1 -= limit;
|
|
invar2 += limit;
|
|
}
|
|
test_fill_byte_sameMS_noalias(A, A, invar1, invar2, limit);
|
|
reference_fill_byte_sameMS_noalias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit);
|
|
});
|
|
referenceTests.put("test_fill_byte_sameMS_maybeAlias", () -> {
|
|
// The accesses either start at the middle and go out,
|
|
// or start from opposite sides and meet in the middle.
|
|
// In the middle, sometimes we overlap and sometimes not.
|
|
// <------|------>
|
|
// ------>|<------
|
|
//
|
|
// This tests that the checks we emit are not too relaxed.
|
|
int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256);
|
|
int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256);
|
|
int invar1 = middle + RANDOM.nextInt(-256, 256);
|
|
int invar2 = middle + RANDOM.nextInt(-256, 256);
|
|
// Are the bounds safe? Assume extreme values:
|
|
// invar1 = 8k/2 + 256 + 256
|
|
// limit = 8k/3 + 256
|
|
// invar1 + limit = 8k * 5/6 + 3 * 256
|
|
// = 8k * 5/6 + 3/4 * 1k = 7.41k < 8k
|
|
if (RANDOM.nextBoolean()) {
|
|
invar1 -= limit;
|
|
invar2 += limit;
|
|
}
|
|
test_fill_byte_sameMS_maybeAlias(A, A, invar1, invar2, limit);
|
|
reference_fill_byte_sameMS_maybeAlias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit);
|
|
});
|
|
referenceTests.put("test_fill_int_sameMS_alias", () -> {
|
|
int invar1 = RANDOM.nextInt(64);
|
|
int invar2 = RANDOM.nextInt(64);
|
|
test_fill_int_sameMS_alias(A, A, invar1, invar2);
|
|
reference_fill_int_sameMS_alias(A_REFERENCE, A_REFERENCE, invar1, invar2);
|
|
});
|
|
referenceTests.put("test_fill_int_sameMS_noalias", () -> {
|
|
// The accesses either start at the middle and go out,
|
|
// or start from opposite sides and meet in the middle.
|
|
// But they never overlap.
|
|
// <------|------>
|
|
// ------>|<------
|
|
//
|
|
// This tests that the checks we emit are not too relaxed.
|
|
int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256);
|
|
int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256);
|
|
int invar1 = middle;
|
|
int invar2 = middle;
|
|
if (RANDOM.nextBoolean()) {
|
|
invar1 -= limit;
|
|
invar2 += limit;
|
|
}
|
|
test_fill_int_sameMS_noalias(A, A, invar1, invar2, limit);
|
|
reference_fill_int_sameMS_noalias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit);
|
|
});
|
|
referenceTests.put("test_fill_int_sameMS_maybeAlias", () -> {
|
|
// The accesses either start at the middle and go out,
|
|
// or start from opposite sides and meet in the middle.
|
|
// In the middle, sometimes we overlap and sometimes not.
|
|
// <------|------>
|
|
// ------>|<------
|
|
//
|
|
// This tests that the checks we emit are not too relaxed.
|
|
int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256);
|
|
int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256);
|
|
int invar1 = middle + RANDOM.nextInt(-256, 256);
|
|
int invar2 = middle + RANDOM.nextInt(-256, 256);
|
|
// Are the bounds safe? Assume extreme values:
|
|
// invar1 = 8k/2 + 256 + 256
|
|
// limit = 8k/3 + 256
|
|
// invar1 + limit = 8k * 5/6 + 3 * 256
|
|
// = 8k * 5/6 + 3/4 * 1k = 7.41k < 8k
|
|
if (RANDOM.nextBoolean()) {
|
|
invar1 -= limit;
|
|
invar2 += limit;
|
|
}
|
|
test_fill_int_sameMS_maybeAlias(A, A, invar1, invar2, limit);
|
|
reference_fill_int_sameMS_maybeAlias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit);
|
|
});
|
|
}
|
|
|
|
static MemorySegment newMemorySegment() {
|
|
return provider.newMemorySegment();
|
|
}
|
|
|
|
static MemorySegment copy(MemorySegment src) {
|
|
MemorySegment dst = newMemorySegment();
|
|
dst.copyFrom(src);
|
|
return dst;
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfByteArray() {
|
|
return MemorySegment.ofArray(new byte[BACKING_SIZE]);
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfCharArray() {
|
|
return MemorySegment.ofArray(new char[BACKING_SIZE / 2]);
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfShortArray() {
|
|
return MemorySegment.ofArray(new short[BACKING_SIZE / 2]);
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfIntArray() {
|
|
return MemorySegment.ofArray(new int[BACKING_SIZE / 4]);
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfLongArray() {
|
|
return MemorySegment.ofArray(new long[BACKING_SIZE / 8]);
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfFloatArray() {
|
|
return MemorySegment.ofArray(new float[BACKING_SIZE / 4]);
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfDoubleArray() {
|
|
return MemorySegment.ofArray(new double[BACKING_SIZE / 8]);
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfByteBuffer() {
|
|
return MemorySegment.ofBuffer(ByteBuffer.allocate(BACKING_SIZE));
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfByteBufferDirect() {
|
|
return MemorySegment.ofBuffer(ByteBuffer.allocateDirect(BACKING_SIZE));
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfNative() {
|
|
// Auto arena: GC decides when there is no reference to the MemorySegment,
|
|
// and then it deallocates the backing memory.
|
|
return Arena.ofAuto().allocate(BACKING_SIZE, 1);
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfMixedArray() {
|
|
switch(RANDOM.nextInt(7)) {
|
|
case 0 -> { return newMemorySegmentOfByteArray(); }
|
|
case 1 -> { return newMemorySegmentOfCharArray(); }
|
|
case 2 -> { return newMemorySegmentOfShortArray(); }
|
|
case 3 -> { return newMemorySegmentOfIntArray(); }
|
|
case 4 -> { return newMemorySegmentOfLongArray(); }
|
|
case 5 -> { return newMemorySegmentOfFloatArray(); }
|
|
default -> { return newMemorySegmentOfDoubleArray(); }
|
|
}
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfMixedBuffer() {
|
|
switch (RANDOM.nextInt(2)) {
|
|
case 0 -> { return newMemorySegmentOfByteBuffer(); }
|
|
default -> { return newMemorySegmentOfByteBufferDirect(); }
|
|
}
|
|
}
|
|
|
|
static MemorySegment newMemorySegmentOfMixed() {
|
|
switch (RANDOM.nextInt(3)) {
|
|
case 0 -> { return newMemorySegmentOfMixedArray(); }
|
|
case 1 -> { return newMemorySegmentOfMixedBuffer(); }
|
|
default -> { return newMemorySegmentOfNative(); }
|
|
}
|
|
}
|
|
|
|
static MemorySegment fillRandom(MemorySegment data) {
|
|
for (int i = 0; i < (int)data.byteSize(); i += 8) {
|
|
data.set(ValueLayout.JAVA_LONG_UNALIGNED, i, RANDOM.nextLong());
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static void init() {
|
|
A.copyFrom(ORIG_A);
|
|
B.copyFrom(ORIG_B);
|
|
C.copyFrom(ORIG_C);
|
|
}
|
|
|
|
public static void initReference() {
|
|
A_REFERENCE.copyFrom(ORIG_A);
|
|
B_REFERENCE.copyFrom(ORIG_B);
|
|
C_REFERENCE.copyFrom(ORIG_C);
|
|
}
|
|
|
|
public static Object snapshotCopy() {
|
|
return new Object[]{copy(A), copy(B), copy(C)};
|
|
}
|
|
|
|
public static Object snapshot() {
|
|
return new Object[]{A, B, C};
|
|
}
|
|
|
|
public static Object snapshotReference() {
|
|
return new Object[]{A_REFERENCE, B_REFERENCE, C_REFERENCE};
|
|
}
|
|
|
|
@Run(test = {"test_byte_incr_noaliasing",
|
|
"test_byte_incr_aliasing",
|
|
"test_byte_incr_aliasing_fwd3",
|
|
"test_byte_incr_noaliasing_fwd128",
|
|
"test_int_to_long_noaliasing",
|
|
"test_fill_byte_sameMS_alias",
|
|
"test_fill_byte_sameMS_noalias",
|
|
"test_fill_byte_sameMS_maybeAlias",
|
|
"test_fill_int_sameMS_alias",
|
|
"test_fill_int_sameMS_noalias",
|
|
"test_fill_int_sameMS_maybeAlias"})
|
|
void runTests(RunInfo info) {
|
|
for (Map.Entry<String,TestFunction> entry : goldTests.entrySet()) {
|
|
String name = entry.getKey();
|
|
TestFunction test = entry.getValue();
|
|
// Recall gold value from before compilation
|
|
Object gold = golds.get(name);
|
|
// Compute new result
|
|
init();
|
|
test.run();
|
|
Object result = snapshot();
|
|
// Compare gold and new result
|
|
try {
|
|
Verify.checkEQ(gold, result);
|
|
} catch (VerifyException e) {
|
|
throw new RuntimeException("Verify failed for " + name, e);
|
|
}
|
|
}
|
|
|
|
// Once warmup is over (100x), repeat 10x to get reasonable coverage of the
|
|
// randomness in the tests.
|
|
int reps = info.isWarmUp() ? 10 : 1;
|
|
for (int r = 0; r < reps; r++) {
|
|
for (Map.Entry<String,TestFunction> entry : referenceTests.entrySet()) {
|
|
String name = entry.getKey();
|
|
TestFunction test = entry.getValue();
|
|
// Init data for test and reference
|
|
init();
|
|
initReference();
|
|
// Run test and reference
|
|
test.run();
|
|
// Capture results from test and reference
|
|
Object result = snapshot();
|
|
Object expected = snapshotReference();
|
|
// Compare expected and new result
|
|
try {
|
|
Verify.checkEQ(expected, result);
|
|
} catch (VerifyException e) {
|
|
throw new RuntimeException("Verify failed for " + name, e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
|
|
IRNode.ADD_VB, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0",
|
|
".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES
|
|
phase = CompilePhase.PRINT_IDEAL,
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
static void test_byte_incr_noaliasing(MemorySegment a, MemorySegment b) {
|
|
for (long i = 0; i < a.byteSize(); i++) {
|
|
byte v = a.get(ValueLayout.JAVA_BYTE, i);
|
|
b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1));
|
|
}
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
|
|
IRNode.ADD_VB, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0",
|
|
".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS
|
|
phase = CompilePhase.PRINT_IDEAL,
|
|
applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
static void test_byte_incr_aliasing(MemorySegment a, MemorySegment b) {
|
|
for (long i = 0; i < a.byteSize(); i++) {
|
|
byte v = a.get(ValueLayout.JAVA_BYTE, i);
|
|
b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1));
|
|
}
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
|
|
IRNode.ADD_VB, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0",
|
|
".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS
|
|
phase = CompilePhase.PRINT_IDEAL,
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
static void test_byte_incr_aliasing_fwd3(MemorySegment a, MemorySegment b) {
|
|
for (long i = 0; i < a.byteSize(); i++) {
|
|
byte v = a.get(ValueLayout.JAVA_BYTE, i);
|
|
b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1));
|
|
}
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_B, "> 0",
|
|
IRNode.ADD_VB, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0",
|
|
".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES
|
|
phase = CompilePhase.PRINT_IDEAL,
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
static void test_byte_incr_noaliasing_fwd128(MemorySegment a, MemorySegment b) {
|
|
for (long i = 0; i < a.byteSize(); i++) {
|
|
byte v = a.get(ValueLayout.JAVA_BYTE, i);
|
|
b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1));
|
|
}
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0",
|
|
IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0",
|
|
IRNode.STORE_VECTOR, "> 0",
|
|
".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES
|
|
phase = CompilePhase.PRINT_IDEAL,
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
|
|
// In this case, the limit is pre-loop independent, but its assigned
|
|
// ctrl sits between main and pre loop. Only the early ctrl is before
|
|
// the pre loop.
|
|
static void test_int_to_long_noaliasing(MemorySegment a, MemorySegment b) {
|
|
long limit = a.byteSize() / 8L;
|
|
for (long i = 0; i < limit; i++) {
|
|
int v = a.get(ValueLayout.JAVA_INT_UNALIGNED, 4L * i);
|
|
b.set(ValueLayout.JAVA_LONG_UNALIGNED, 8L * i, v);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
// @IR(counts = {IRNode.STORE_VECTOR, "> 0",
|
|
// ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS
|
|
// phase = CompilePhase.PRINT_IDEAL,
|
|
// applyIfPlatform = {"64-bit", "true"},
|
|
// applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
// applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
//
|
|
// FAILS: but only on "native" and "byte-buffer-direct"
|
|
// The issue is that one of the VPointers is invalid.
|
|
static void test_fill_byte_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) {
|
|
for (long i = 0; i < a.byteSize() - 100; i++) {
|
|
a.set(ValueLayout.JAVA_BYTE, i + invar1, (byte)0x0a);
|
|
b.set(ValueLayout.JAVA_BYTE, a.byteSize() - i - 1 - invar2, (byte)0x0b);
|
|
}
|
|
}
|
|
|
|
@DontCompile
|
|
static void reference_fill_byte_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) {
|
|
for (long i = 0; i < a.byteSize() - 100; i++) {
|
|
a.set(ValueLayout.JAVA_BYTE, i + invar1, (byte)0x0a);
|
|
b.set(ValueLayout.JAVA_BYTE, a.byteSize() - i - 1 - invar2, (byte)0x0b);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
// @IR(counts = {IRNode.STORE_VECTOR, "> 0",
|
|
// ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES
|
|
// phase = CompilePhase.PRINT_IDEAL,
|
|
// applyIfPlatform = {"64-bit", "true"},
|
|
// applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
// applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
//
|
|
// FAILS: but only on "native" and "byte-buffer-direct"
|
|
// The issue is that one of the VPointers is invalid.
|
|
//
|
|
// For now, we just assert that there is never multiversioning, which holds with or without vectorization:
|
|
@IR(counts = {".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES
|
|
phase = CompilePhase.PRINT_IDEAL,
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
static void test_fill_byte_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) {
|
|
for (long i = 0; i < limit; i++) {
|
|
a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa);
|
|
b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb);
|
|
}
|
|
}
|
|
|
|
@DontCompile
|
|
static void reference_fill_byte_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) {
|
|
for (long i = 0; i < limit; i++) {
|
|
a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa);
|
|
b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
// @IR(counts = {IRNode.STORE_VECTOR, "> 0"},
|
|
// phase = CompilePhase.PRINT_IDEAL,
|
|
// applyIfPlatform = {"64-bit", "true"},
|
|
// applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
// applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
//
|
|
// FAILS: but only on "native" and "byte-buffer-direct"
|
|
// The issue is that one of the VPointers is invalid.
|
|
//
|
|
// Note: we may or may not use multiversioning, depending if we alias or not at runtime.
|
|
static void test_fill_byte_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) {
|
|
for (long i = 0; i < limit; i++) {
|
|
a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa);
|
|
b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb);
|
|
}
|
|
}
|
|
|
|
@DontCompile
|
|
static void reference_fill_byte_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) {
|
|
for (long i = 0; i < limit; i++) {
|
|
a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa);
|
|
b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
// @IR(counts = {IRNode.STORE_VECTOR, "> 0",
|
|
// ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS
|
|
// phase = CompilePhase.PRINT_IDEAL,
|
|
// applyIfPlatform = {"64-bit", "true"},
|
|
// applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
// applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
//
|
|
// FAILS: but only on "native" and "byte-buffer-direct"
|
|
// The issue is that one of the VPointers is invalid.
|
|
static void test_fill_int_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) {
|
|
for (long i = 0; i < a.byteSize() - 100; i+=4) {
|
|
a.set(ValueLayout.JAVA_INT_UNALIGNED, i + invar1, 0x01020304);
|
|
b.set(ValueLayout.JAVA_INT_UNALIGNED, a.byteSize() - i - 4 - invar2, 0x11121314);
|
|
}
|
|
}
|
|
|
|
@DontCompile
|
|
static void reference_fill_int_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) {
|
|
for (long i = 0; i < a.byteSize() - 100; i+=4) {
|
|
a.set(ValueLayout.JAVA_INT_UNALIGNED, i + invar1, 0x01020304);
|
|
b.set(ValueLayout.JAVA_INT_UNALIGNED, a.byteSize() - i - 4 - invar2, 0x11121314);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
// @IR(counts = {IRNode.STORE_VECTOR, "> 0",
|
|
// ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES
|
|
// phase = CompilePhase.PRINT_IDEAL,
|
|
// applyIfPlatform = {"64-bit", "true"},
|
|
// applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
// applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
//
|
|
// FAILS: but only on "native" and "byte-buffer-direct"
|
|
// The issue is that one of the VPointers is invalid.
|
|
//
|
|
// For now, we just assert that there is never multiversioning, which holds with or without vectorization:
|
|
@IR(counts = {".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES
|
|
phase = CompilePhase.PRINT_IDEAL,
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
static void test_fill_int_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) {
|
|
for (long i = 0; i <= limit - 4; i+=4) {
|
|
a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304);
|
|
b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314);
|
|
}
|
|
}
|
|
|
|
@DontCompile
|
|
static void reference_fill_int_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) {
|
|
for (long i = 0; i <= limit - 4; i+=4) {
|
|
a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304);
|
|
b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
// @IR(counts = {IRNode.STORE_VECTOR, "> 0"},
|
|
// phase = CompilePhase.PRINT_IDEAL,
|
|
// applyIfPlatform = {"64-bit", "true"},
|
|
// applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"},
|
|
// applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
//
|
|
// FAILS: but only on "native" and "byte-buffer-direct"
|
|
// The issue is that one of the VPointers is invalid.
|
|
//
|
|
// Note: we may or may not use multiversioning, depending if we alias or not at runtime.
|
|
static void test_fill_int_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) {
|
|
for (long i = 0; i <= limit - 4; i+=4) {
|
|
a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304);
|
|
b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314);
|
|
}
|
|
}
|
|
|
|
@DontCompile
|
|
static void reference_fill_int_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) {
|
|
for (long i = 0; i <= limit - 4; i+=4) {
|
|
a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304);
|
|
b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314);
|
|
}
|
|
}
|
|
}
|