/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Tests for ABS vectorization.
*/
public class Main {
private final static boolean isDalvik =
System.getProperty("java.vm.name").equals("Dalvik");
private static final int SPQUIET = 1 << 22;
private static final long DPQUIET = 1L << 51;
/// CHECK-START: void Main.doitByte(byte[]) loop_optimization (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitByte(byte[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
private static void doitByte(byte[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = (byte) Math.abs(x[i]);
}
}
/// CHECK-START: void Main.doitChar(char[]) loop_optimization (before)
/// CHECK-NOT: Abs
//
/// CHECK-START: void Main.doitChar(char[]) loop_optimization (after)
/// CHECK-NOT: VecAbs
private static void doitChar(char[] x) {
// Basically a nop due to zero extension.
for (int i = 0; i < x.length; i++) {
x[i] = (char) Math.abs(x[i]);
}
}
/// CHECK-START: void Main.doitShort(short[]) loop_optimization (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitShort(short[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
private static void doitShort(short[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = (short) Math.abs(x[i]);
}
}
/// CHECK-START: void Main.doitCastedChar(char[]) loop_optimization (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.doitCastedChar(char[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
private static void doitCastedChar(char[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = (char) Math.abs((short) x[i]);
}
}
/// CHECK-START: void Main.doitInt(int[]) loop_optimization (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitInt(int[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
private static void doitInt(int[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = Math.abs(x[i]);
}
}
/// CHECK-START: void Main.doitLong(long[]) loop_optimization (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-{ARM64,MIPS64}: void Main.doitLong(long[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
private static void doitLong(long[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = Math.abs(x[i]);
}
}
/// CHECK-START: void Main.doitFloat(float[]) loop_optimization (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-{ARM64,MIPS64}: void Main.doitFloat(float[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
private static void doitFloat(float[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = Math.abs(x[i]);
}
}
/// CHECK-START: void Main.doitDouble(double[]) loop_optimization (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-{ARM64,MIPS64}: void Main.doitDouble(double[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> outer_loop:none
/// CHECK-DAG: Abs loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
private static void doitDouble(double[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = Math.abs(x[i]);
}
}
public static void main(String[] args) {
// Bytes, chars, shorts.
byte[] xb = new byte[256];
for (int i = 0; i < 256; i++) {
xb[i] = (byte) i;
}
doitByte(xb);
for (int i = 0; i < 256; i++) {
expectEquals32((byte) Math.abs((byte) i), xb[i]);
}
char[] xc = new char[1024 * 64];
for (int i = 0; i < 1024 * 64; i++) {
xc[i] = (char) i;
}
doitChar(xc);
for (int i = 0; i < 1024 * 64; i++) {
expectEquals32((char) Math.abs((char) i), xc[i]);
}
short[] xs = new short[1024 * 64];
for (int i = 0; i < 1024 * 64; i++) {
xs[i] = (short) i;
}
doitShort(xs);
for (int i = 0; i < 1024 * 64; i++) {
expectEquals32((short) Math.abs((short) i), xs[i]);
}
for (int i = 0; i < 1024 * 64; i++) {
xc[i] = (char) i;
}
doitCastedChar(xc);
for (int i = 0; i < 1024 * 64; i++) {
expectEquals32((char) Math.abs((short) i), xc[i]);
}
// Set up minint32, maxint32 and some others.
int[] xi = new int[8];
xi[0] = 0x80000000;
xi[1] = 0x7fffffff;
xi[2] = 0x80000001;
xi[3] = -13;
xi[4] = -1;
xi[5] = 0;
xi[6] = 1;
xi[7] = 999;
doitInt(xi);
expectEquals32(0x80000000, xi[0]);
expectEquals32(0x7fffffff, xi[1]);
expectEquals32(0x7fffffff, xi[2]);
expectEquals32(13, xi[3]);
expectEquals32(1, xi[4]);
expectEquals32(0, xi[5]);
expectEquals32(1, xi[6]);
expectEquals32(999, xi[7]);
// Set up minint64, maxint64 and some others.
long[] xl = new long[8];
xl[0] = 0x8000000000000000L;
xl[1] = 0x7fffffffffffffffL;
xl[2] = 0x8000000000000001L;
xl[3] = -13;
xl[4] = -1;
xl[5] = 0;
xl[6] = 1;
xl[7] = 999;
doitLong(xl);
expectEquals64(0x8000000000000000L, xl[0]);
expectEquals64(0x7fffffffffffffffL, xl[1]);
expectEquals64(0x7fffffffffffffffL, xl[2]);
expectEquals64(13, xl[3]);
expectEquals64(1, xl[4]);
expectEquals64(0, xl[5]);
expectEquals64(1, xl[6]);
expectEquals64(999, xl[7]);
// Set up float NaN and some others.
float[] xf = new float[16];
xf[0] = Float.intBitsToFloat(0x7f800001);
xf[1] = Float.intBitsToFloat(0x7fa00000);
xf[2] = Float.intBitsToFloat(0x7fc00000);
xf[3] = Float.intBitsToFloat(0x7fffffff);
xf[4] = Float.intBitsToFloat(0xff800001);
xf[5] = Float.intBitsToFloat(0xffa00000);
xf[6] = Float.intBitsToFloat(0xffc00000);
xf[7] = Float.intBitsToFloat(0xffffffff);
xf[8] = Float.NEGATIVE_INFINITY;
xf[9] = -99.2f;
xf[10] = -1.0f;
xf[11] = -0.0f;
xf[12] = +0.0f;
xf[13] = +1.0f;
xf[14] = +99.2f;
xf[15] = Float.POSITIVE_INFINITY;
doitFloat(xf);
expectEqualsNaN32(0x7f800001, Float.floatToRawIntBits(xf[0]));
expectEqualsNaN32(0x7fa00000, Float.floatToRawIntBits(xf[1]));
expectEqualsNaN32(0x7fc00000, Float.floatToRawIntBits(xf[2]));
expectEqualsNaN32(0x7fffffff, Float.floatToRawIntBits(xf[3]));
expectEqualsNaN32(0x7f800001, Float.floatToRawIntBits(xf[4]));
expectEqualsNaN32(0x7fa00000, Float.floatToRawIntBits(xf[5]));
expectEqualsNaN32(0x7fc00000, Float.floatToRawIntBits(xf[6]));
expectEqualsNaN32(0x7fffffff, Float.floatToRawIntBits(xf[7]));
expectEquals32(
Float.floatToRawIntBits(Float.POSITIVE_INFINITY),
Float.floatToRawIntBits(xf[8]));
expectEquals32(
Float.floatToRawIntBits(99.2f),
Float.floatToRawIntBits(xf[9]));
expectEquals32(
Float.floatToRawIntBits(1.0f),
Float.floatToRawIntBits(xf[10]));
expectEquals32(0, Float.floatToRawIntBits(xf[11]));
expectEquals32(0, Float.floatToRawIntBits(xf[12]));
expectEquals32(
Float.floatToRawIntBits(1.0f),
Float.floatToRawIntBits(xf[13]));
expectEquals32(
Float.floatToRawIntBits(99.2f),
Float.floatToRawIntBits(xf[14]));
expectEquals32(
Float.floatToRawIntBits(Float.POSITIVE_INFINITY),
Float.floatToRawIntBits(xf[15]));
// Set up double NaN and some others.
double[] xd = new double[16];
xd[0] = Double.longBitsToDouble(0x7ff0000000000001L);
xd[1] = Double.longBitsToDouble(0x7ff4000000000000L);
xd[2] = Double.longBitsToDouble(0x7ff8000000000000L);
xd[3] = Double.longBitsToDouble(0x7fffffffffffffffL);
xd[4] = Double.longBitsToDouble(0xfff0000000000001L);
xd[5] = Double.longBitsToDouble(0xfff4000000000000L);
xd[6] = Double.longBitsToDouble(0xfff8000000000000L);
xd[7] = Double.longBitsToDouble(0xffffffffffffffffL);
xd[8] = Double.NEGATIVE_INFINITY;
xd[9] = -99.2f;
xd[10] = -1.0f;
xd[11] = -0.0f;
xd[12] = +0.0f;
xd[13] = +1.0f;
xd[14] = +99.2f;
xd[15] = Double.POSITIVE_INFINITY;
doitDouble(xd);
expectEqualsNaN64(0x7ff0000000000001L, Double.doubleToRawLongBits(xd[0]));
expectEqualsNaN64(0x7ff4000000000000L, Double.doubleToRawLongBits(xd[1]));
expectEqualsNaN64(0x7ff8000000000000L, Double.doubleToRawLongBits(xd[2]));
expectEqualsNaN64(0x7fffffffffffffffL, Double.doubleToRawLongBits(xd[3]));
expectEqualsNaN64(0x7ff0000000000001L, Double.doubleToRawLongBits(xd[4]));
expectEqualsNaN64(0x7ff4000000000000L, Double.doubleToRawLongBits(xd[5]));
expectEqualsNaN64(0x7ff8000000000000L, Double.doubleToRawLongBits(xd[6]));
expectEqualsNaN64(0x7fffffffffffffffL, Double.doubleToRawLongBits(xd[7]));
expectEquals64(
Double.doubleToRawLongBits(Double.POSITIVE_INFINITY),
Double.doubleToRawLongBits(xd[8]));
expectEquals64(
Double.doubleToRawLongBits(99.2f),
Double.doubleToRawLongBits(xd[9]));
expectEquals64(
Double.doubleToRawLongBits(1.0f),
Double.doubleToRawLongBits(xd[10]));
expectEquals64(0, Double.doubleToRawLongBits(xd[11]));
expectEquals64(0, Double.doubleToRawLongBits(xd[12]));
expectEquals64(
Double.doubleToRawLongBits(1.0f),
Double.doubleToRawLongBits(xd[13]));
expectEquals64(
Double.doubleToRawLongBits(99.2f),
Double.doubleToRawLongBits(xd[14]));
expectEquals64(
Double.doubleToRawLongBits(Double.POSITIVE_INFINITY),
Double.doubleToRawLongBits(xd[15]));
System.out.println("passed");
}
private static void expectEquals32(int expected, int result) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
}
}
private static void expectEquals64(long expected, long result) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
}
}
// We allow that an expected NaN result has become quiet.
private static void expectEqualsNaN32(int expected, int result) {
if (expected != result && (expected | SPQUIET) != result) {
if (!isDalvik) {
// If not on ART, relax the expected value more towards just
// "spec compliance" and allow sign bit to remain set for NaN.
if (expected == (result & Integer.MAX_VALUE)) {
return;
}
}
throw new Error("Expected: 0x" + Integer.toHexString(expected)
+ ", found: 0x" + Integer.toHexString(result));
}
}
// We allow that an expected NaN result has become quiet.
private static void expectEqualsNaN64(long expected, long result) {
if (expected != result && (expected | DPQUIET) != result) {
if (!isDalvik) {
// If not on ART, relax the expected value more towards just
// "spec compliance" and allow sign bit to remain set for NaN.
if (expected == (result & Long.MAX_VALUE)) {
return;
}
}
throw new Error("Expected: 0x" + Long.toHexString(expected)
+ ", found: 0x" + Long.toHexString(result));
}
}
}