/* * 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)); } } }