7b38bfea33
Reviewed-by: chagedorn, kvn
758 lines
28 KiB
Java
758 lines
28 KiB
Java
/*
|
|
* Copyright (c) 2024, 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.test.whitebox.WhiteBox;
|
|
import java.lang.reflect.Array;
|
|
import java.util.Map;
|
|
import java.util.HashMap;
|
|
import java.util.Random;
|
|
import java.nio.ByteOrder;
|
|
|
|
/*
|
|
* @test
|
|
* @bug 8326139
|
|
* @summary Test splitting packs in SuperWord
|
|
* @library /test/lib /
|
|
* @run driver compiler.loopopts.superword.TestSplitPacks
|
|
*/
|
|
|
|
public class TestSplitPacks {
|
|
static int RANGE = 1024*8;
|
|
static int RANGE_FINAL = 1024*8;
|
|
private static final Random RANDOM = Utils.getRandomInstance();
|
|
|
|
// Inputs
|
|
byte[] aB;
|
|
byte[] bB;
|
|
byte mB = (byte)31;
|
|
short[] aS;
|
|
short[] bS;
|
|
short mS = (short)0xF0F0;
|
|
int[] aI;
|
|
int[] bI;
|
|
int mI = 0xF0F0F0F0;
|
|
long[] aL;
|
|
long[] bL;
|
|
long mL = 0xF0F0F0F0F0F0F0F0L;
|
|
|
|
// 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("-XX:+IgnoreUnrecognizedVMOptions", "-XX:LoopUnrollLimit=1000");
|
|
}
|
|
|
|
public TestSplitPacks() {
|
|
// Generate input once
|
|
aB = generateB();
|
|
bB = generateB();
|
|
aS = generateS();
|
|
bS = generateS();
|
|
aI = generateI();
|
|
bI = generateI();
|
|
aL = generateL();
|
|
bL = generateL();
|
|
|
|
// Add all tests to list
|
|
tests.put("test0", () -> { return test0(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test1a", () -> { return test1a(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test1b", () -> { return test1b(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test1c", () -> { return test1c(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test1d", () -> { return test1d(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test2a", () -> { return test2a(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test2b", () -> { return test2b(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test2c", () -> { return test2c(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test2d", () -> { return test2d(aI.clone(), bI.clone(), mI); });
|
|
tests.put("test3a", () -> { return test3a(aS.clone(), bS.clone(), mS); });
|
|
tests.put("test4a", () -> { return test4a(aS.clone(), bS.clone()); });
|
|
tests.put("test4b", () -> { return test4b(aS.clone(), bS.clone()); });
|
|
tests.put("test4c", () -> { return test4c(aS.clone(), bS.clone()); });
|
|
tests.put("test4d", () -> { return test4d(aS.clone(), bS.clone()); });
|
|
tests.put("test4e", () -> { return test4e(aS.clone(), bS.clone()); });
|
|
tests.put("test4f", () -> { return test4f(aS.clone(), bS.clone()); });
|
|
tests.put("test4g", () -> { return test4g(aS.clone(), bS.clone()); });
|
|
tests.put("test5a", () -> { return test5a(aS.clone(), bS.clone(), mS); });
|
|
tests.put("test6a", () -> { return test6a(aI.clone(), bI.clone()); });
|
|
tests.put("test7a", () -> { return test7a(aI.clone(), bI.clone()); });
|
|
|
|
// 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 = {"test0",
|
|
"test1a",
|
|
"test1b",
|
|
"test1c",
|
|
"test1d",
|
|
"test2a",
|
|
"test2b",
|
|
"test2c",
|
|
"test2d",
|
|
"test3a",
|
|
"test4a",
|
|
"test4b",
|
|
"test4c",
|
|
"test4d",
|
|
"test4e",
|
|
"test4f",
|
|
"test4g",
|
|
"test5a",
|
|
"test6a",
|
|
"test7a"})
|
|
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.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 (g == r) {
|
|
throw new RuntimeException("verify " + name + ": should be two separate arrays (with identical content):" +
|
|
" gold[" + i + "] == result[" + i + "]");
|
|
}
|
|
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) {
|
|
verifyB(name, i, (byte[])g, (byte[])r);
|
|
} else if (c == short.class) {
|
|
verifyS(name, i, (short[])g, (short[])r);
|
|
} else if (c == int.class) {
|
|
verifyI(name, i, (int[])g, (int[])r);
|
|
} else if (c == long.class) {
|
|
verifyL(name, i, (long[])g, (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());
|
|
}
|
|
}
|
|
}
|
|
|
|
static void verifyB(String name, int i, byte[] g, byte[] r) {
|
|
for (int j = 0; j < g.length; j++) {
|
|
if (g[j] != r[j]) {
|
|
throw new RuntimeException("verify " + name + ": arrays must have same content:" +
|
|
" gold[" + i + "][" + j + "] = " + g[j] +
|
|
" result[" + i + "][" + j + "] = " + r[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void verifyS(String name, int i, short[] g, short[] r) {
|
|
for (int j = 0; j < g.length; j++) {
|
|
if (g[j] != r[j]) {
|
|
throw new RuntimeException("verify " + name + ": arrays must have same content:" +
|
|
" gold[" + i + "][" + j + "] = " + g[j] +
|
|
" result[" + i + "][" + j + "] = " + r[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void verifyI(String name, int i, int[] g, int[] r) {
|
|
for (int j = 0; j < g.length; j++) {
|
|
if (g[j] != r[j]) {
|
|
throw new RuntimeException("verify " + name + ": arrays must have same content:" +
|
|
" gold[" + i + "][" + j + "] = " + g[j] +
|
|
" result[" + i + "][" + j + "] = " + r[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void verifyL(String name, int i, long[] g, long[] r) {
|
|
for (int j = 0; j < g.length; j++) {
|
|
if (g[j] != r[j]) {
|
|
throw new RuntimeException("verify " + name + ": arrays must have same content:" +
|
|
" gold[" + i + "][" + j + "] = " + g[j] +
|
|
" result[" + i + "][" + j + "] = " + r[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Load and store are already split
|
|
//
|
|
// 0 1 - - 4 5 6 7
|
|
// | | | | | |
|
|
// 0 1 - - 4 5 6 7
|
|
static Object[] test0(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
int b0 = a[i+0] & mask;
|
|
int b1 = a[i+1] & mask;
|
|
|
|
int b4 = a[i+4] & mask;
|
|
int b5 = a[i+5] & mask;
|
|
int b6 = a[i+6] & mask;
|
|
int b7 = a[i+7] & mask;
|
|
|
|
b[i+0] = b0;
|
|
b[i+1] = b1;
|
|
|
|
b[i+4] = b4;
|
|
b[i+5] = b5;
|
|
b[i+6] = b6;
|
|
b[i+7] = b7;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.ADD_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.MUL_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Adjacent Load and Store, but split by Add/Mul
|
|
static Object[] test1a(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
b[i+0] = a[i+0] + mask; // Add
|
|
b[i+1] = a[i+1] + mask;
|
|
b[i+2] = a[i+2] + mask;
|
|
b[i+3] = a[i+3] + mask;
|
|
|
|
b[i+4] = a[i+4] * mask; // Mul
|
|
b[i+5] = a[i+5] * mask;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.ADD_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.MUL_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Adjacent Load and Store, but split by Add/Mul
|
|
static Object[] test1b(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
b[i+0] = a[i+0] * mask; // Mul
|
|
b[i+1] = a[i+1] * mask;
|
|
b[i+2] = a[i+2] * mask;
|
|
b[i+3] = a[i+3] * mask;
|
|
|
|
b[i+4] = a[i+4] + mask; // Add
|
|
b[i+5] = a[i+5] + mask;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.ADD_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.MUL_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"})
|
|
// Adjacent Load and Store, but split by Add/Mul
|
|
static Object[] test1c(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
b[i+0] = a[i+0] + mask; // Add
|
|
b[i+1] = a[i+1] + mask;
|
|
|
|
b[i+2] = a[i+2] * mask; // Mul
|
|
b[i+3] = a[i+3] * mask;
|
|
b[i+4] = a[i+4] * mask;
|
|
b[i+5] = a[i+5] * mask;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.ADD_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.MUL_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"})
|
|
// Adjacent Load and Store, but split by Add/Mul
|
|
static Object[] test1d(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
b[i+0] = a[i+0] * mask; // Mul
|
|
b[i+1] = a[i+1] * mask;
|
|
|
|
b[i+2] = a[i+2] + mask; // Add
|
|
b[i+3] = a[i+3] + mask;
|
|
b[i+4] = a[i+4] + mask;
|
|
b[i+5] = a[i+5] + mask;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Split the load
|
|
//
|
|
// 0 1 2 3 4 5 - -
|
|
// | | \ \ \ \
|
|
// | | \ \ \ \
|
|
// | | \ \ \ \
|
|
// 0 1 - - 4 5 6 7
|
|
//
|
|
static Object[] test2a(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
int b0 = a[i+0] & mask;
|
|
int b1 = a[i+1] & mask;
|
|
int b2 = a[i+2] & mask;
|
|
int b3 = a[i+3] & mask;
|
|
int b4 = a[i+4] & mask;
|
|
int b5 = a[i+5] & mask;
|
|
|
|
b[i+0] = b0;
|
|
b[i+1] = b1;
|
|
|
|
b[i+4] = b2;
|
|
b[i+5] = b3;
|
|
b[i+6] = b4;
|
|
b[i+7] = b5;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Split the load
|
|
//
|
|
// 0 1 2 3 4 5 - -
|
|
// | | | | \ \
|
|
// | | | | \ \
|
|
// | | | | \ \
|
|
// 0 1 2 3 -- 6 7
|
|
//
|
|
static Object[] test2b(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
int b0 = a[i+0] & mask;
|
|
int b1 = a[i+1] & mask;
|
|
int b2 = a[i+2] & mask;
|
|
int b3 = a[i+3] & mask;
|
|
int b4 = a[i+4] & mask;
|
|
int b5 = a[i+5] & mask;
|
|
|
|
b[i+0] = b0;
|
|
b[i+1] = b1;
|
|
b[i+2] = b2;
|
|
b[i+3] = b3;
|
|
|
|
b[i+6] = b4;
|
|
b[i+7] = b5;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Split the load
|
|
//
|
|
// 0 1 - - 4 5 6 7
|
|
// | | / / / /
|
|
// | | / / / /
|
|
// | | / / / /
|
|
// 0 1 2 3 4 5 - -
|
|
//
|
|
static Object[] test2c(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
int b0 = a[i+0] & mask;
|
|
int b1 = a[i+1] & mask;
|
|
|
|
int b4 = a[i+4] & mask;
|
|
int b5 = a[i+5] & mask;
|
|
int b6 = a[i+6] & mask;
|
|
int b7 = a[i+7] & mask;
|
|
|
|
b[i+0] = b0;
|
|
b[i+1] = b1;
|
|
b[i+2] = b4;
|
|
b[i+3] = b5;
|
|
b[i+4] = b6;
|
|
b[i+5] = b7;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Split the load
|
|
//
|
|
// 0 1 2 3 - - 6 7
|
|
// | | | | / /
|
|
// | | | | / /
|
|
// | | | | / /
|
|
// 0 1 2 3 4 5 - -
|
|
//
|
|
static Object[] test2d(int[] a, int[] b, int mask) {
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
int b0 = a[i+0] & mask;
|
|
int b1 = a[i+1] & mask;
|
|
int b2 = a[i+2] & mask;
|
|
int b3 = a[i+3] & mask;
|
|
|
|
int b6 = a[i+6] & mask;
|
|
int b7 = a[i+7] & mask;
|
|
|
|
b[i+0] = b0;
|
|
b[i+1] = b1;
|
|
b[i+2] = b2;
|
|
b[i+3] = b3;
|
|
b[i+4] = b6;
|
|
b[i+5] = b7;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// 0 1 2 3 4 5 6 7 -
|
|
// | | | | | | | |
|
|
// | + + + | | | |
|
|
// | | | | |
|
|
// | v | | | | v
|
|
// | | | | | | |
|
|
// 1 - - 3 4 5 6 7 8
|
|
static Object[] test3a(short[] a, short[] b, short val) {
|
|
int sum = 0;
|
|
for (int i = 0; i < RANGE; i+=16) {
|
|
short a0 = a[i+0]; // required for alignment / offsets, technical limitation.
|
|
|
|
short a1 = a[i+1]; // adjacent to 4-pack, but need to be split off
|
|
short a2 = a[i+2];
|
|
short a3 = a[i+3];
|
|
|
|
short a4 = a[i+4]; // 4-pack
|
|
short a5 = a[i+5];
|
|
short a6 = a[i+6];
|
|
short a7 = a[i+7];
|
|
|
|
|
|
b[i+0] = a0; // required for alignment / offsets, technical limitation.
|
|
|
|
sum += a1 + a2 + a3; // not packed
|
|
|
|
b[i+3] = val; // adjacent to 4-pack but needs to be split off
|
|
|
|
b[i+4] = a4; // 4-pack
|
|
b[i+5] = a5;
|
|
b[i+6] = a6;
|
|
b[i+7] = a7;
|
|
|
|
b[i+8] = val; // adjacent to 4-pack but needs to be split off
|
|
}
|
|
return new Object[]{ a, b, new int[]{ sum } };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true"})
|
|
// Cyclic dependency with distance 2 -> split into 2-packs
|
|
static Object[] test4a(short[] a, short[] b) {
|
|
for (int i = 0; i < RANGE-64; i++) {
|
|
b[i+2] = a[i+0];
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"AlignVector", "false"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true"})
|
|
// Cyclic dependency with distance 3 -> split into 2-packs
|
|
static Object[] test4b(short[] a, short[] b) {
|
|
for (int i = 0; i < RANGE-64; i++) {
|
|
b[i+3] = a[i+0];
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=8"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Cyclic dependency with distance 4 -> split into 4-packs
|
|
static Object[] test4c(short[] a, short[] b) {
|
|
for (int i = 0; i < RANGE-64; i++) {
|
|
b[i+4] = a[i+0];
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Cyclic dependency with distance 5 -> split into 4-packs
|
|
static Object[] test4d(short[] a, short[] b) {
|
|
for (int i = 0; i < RANGE-64; i++) {
|
|
b[i+5] = a[i+0];
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Cyclic dependency with distance 6 -> split into 4-packs
|
|
static Object[] test4e(short[] a, short[] b) {
|
|
for (int i = 0; i < RANGE-64; i++) {
|
|
b[i+6] = a[i+0];
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Cyclic dependency with distance 7 -> split into 4-packs
|
|
static Object[] test4f(short[] a, short[] b) {
|
|
for (int i = 0; i < RANGE-64; i++) {
|
|
b[i+7] = a[i+0];
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Cyclic dependency with distance 8 -> split into 8-packs
|
|
static Object[] test4g(short[] a, short[] b) {
|
|
for (int i = 0; i < RANGE-64; i++) {
|
|
b[i+8] = a[i+0];
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0",
|
|
IRNode.ADD_VS, IRNode.VECTOR_SIZE_2, "> 0",
|
|
IRNode.ADD_VS, IRNode.VECTOR_SIZE_8, "> 0",
|
|
IRNode.ADD_VS, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.STORE_VECTOR, "> 0"},
|
|
applyIfAnd = {"MaxVectorSize", ">=32", "AlignVector", "false"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Split pack into power-of-2 sizes
|
|
static Object[] test5a(short[] a, short[] b, short val) {
|
|
for (int i = 0; i < RANGE; i+=16) {
|
|
b[i+ 0] = (short)(a[i+ 0] + val); // 8 pack
|
|
b[i+ 1] = (short)(a[i+ 1] + val);
|
|
b[i+ 2] = (short)(a[i+ 2] + val);
|
|
b[i+ 3] = (short)(a[i+ 3] + val);
|
|
b[i+ 4] = (short)(a[i+ 4] + val);
|
|
b[i+ 5] = (short)(a[i+ 5] + val);
|
|
b[i+ 6] = (short)(a[i+ 6] + val);
|
|
b[i+ 7] = (short)(a[i+ 7] + val);
|
|
|
|
b[i+ 8] = (short)(a[i+ 8] + val); // 4-pack
|
|
b[i+ 9] = (short)(a[i+ 9] + val);
|
|
b[i+10] = (short)(a[i+10] + val);
|
|
b[i+11] = (short)(a[i+11] + val);
|
|
|
|
b[i+12] = (short)(a[i+12] + val); // 2-pack
|
|
b[i+13] = (short)(a[i+13] + val);
|
|
|
|
b[i+14] = (short)(a[i+14] + val);
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.MUL_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0",
|
|
IRNode.ADD_VI, IRNode.VECTOR_SIZE_4, "> 0", // reduction moved out of loop
|
|
IRNode.ADD_REDUCTION_V, "> 0"},
|
|
applyIf = {"MaxVectorSize", ">=32"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
|
|
// Split packs including reductions
|
|
static Object[] test6a(int[] a, int[] b) {
|
|
int s = 0;
|
|
for (int i = 0; i < RANGE; i+=8) {
|
|
s += a[i+0] * b[i+0];
|
|
s += a[i+1] * b[i+1];
|
|
s += a[i+2] * b[i+2];
|
|
s += a[i+3] * b[i+3];
|
|
|
|
s += a[i+4] & b[i+4];
|
|
s += a[i+5] & b[i+5];
|
|
s += a[i+6] & b[i+6];
|
|
s += a[i+7] & b[i+7];
|
|
}
|
|
return new Object[]{ a, b, new int[]{ s } };
|
|
}
|
|
|
|
@Test
|
|
@IR(counts = {IRNode.LOAD_VECTOR_I, "> 0",
|
|
IRNode.MUL_VI, "> 0",
|
|
IRNode.POPULATE_INDEX, "> 0"},
|
|
applyIfPlatform = {"64-bit", "true"},
|
|
applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"})
|
|
// Index Populate:
|
|
// There can be an issue when all the (iv + 1), (iv + 2), ...
|
|
// get packed, but not (iv). Then we have a pack that is one element
|
|
// too short, and we start splitting everything in a bad way.
|
|
static Object[] test7a(int[] a, int[] b) {
|
|
for (int i = 0; i < RANGE; i++) {
|
|
a[i] = b[i] * i;
|
|
}
|
|
return new Object[]{ a, b };
|
|
}
|
|
}
|