8261022: Fix incorrect result of Math.abs() with char type

Reviewed-by: thartmann, neliasso
diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp
index af9d6fa..00f4a50 100644
--- a/src/hotspot/share/opto/superword.cpp
+++ b/src/hotspot/share/opto/superword.cpp
@@ -3217,21 +3217,23 @@
             }
           }
           if (same_type) {
-            // For right shifts of small integer types (bool, byte, char, short)
-            // we need precise information about sign-ness. Only Load nodes have
-            // this information because Store nodes are the same for signed and
-            // unsigned values. And any arithmetic operation after a load may
-            // expand a value to signed Int so such right shifts can't be used
-            // because vector elements do not have upper bits of Int.
+            // In any Java arithmetic operation, operands of small integer types
+            // (boolean, byte, char & short) should be promoted to int first. As
+            // vector elements of small types don't have upper bits of int, for
+            // RShiftI or AbsI operations, the compiler has to know the precise
+            // signedness info of the 1st operand. These operations shouldn't be
+            // vectorized if the signedness info is imprecise.
             const Type* vt = vtn;
-            if (VectorNode::is_shift(in)) {
+            int op = in->Opcode();
+            if (VectorNode::is_shift_opcode(op) || op == Op_AbsI) {
               Node* load = in->in(1);
               if (load->is_Load() && in_bb(load) && (velt_type(load)->basic_type() == T_INT)) {
+                // Only Load nodes distinguish signed (LoadS/LoadB) and unsigned
+                // (LoadUS/LoadUB) values. Store nodes only have one version.
                 vt = velt_type(load);
-              } else if (in->Opcode() != Op_LShiftI) {
-                // Widen type to Int to avoid creation of right shift vector
-                // (align + data_size(s1) check in stmts_can_pack() will fail).
-                // Note, left shifts work regardless type.
+              } else if (op != Op_LShiftI) {
+                // Widen type to int to avoid the creation of vector nodes. Note
+                // that left shifts work regardless of the signedness.
                 vt = TypeInt::INT;
               }
             }
diff --git a/test/hotspot/jtreg/compiler/vectorization/TestAbsCharVector.java b/test/hotspot/jtreg/compiler/vectorization/TestAbsCharVector.java
new file mode 100644
index 0000000..33ff772
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/vectorization/TestAbsCharVector.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, Arm Limited. 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.
+ */
+
+/**
+ * @test
+ * @bug 8261022
+ * @summary Test vectorization of Math.abs() with unsigned type
+ * @run main/othervm compiler.vectorization.TestAbsCharVector
+ */
+
+package compiler.vectorization;
+
+public class TestAbsCharVector {
+
+    private static int SIZE = 60000;
+
+    public static void main(String args[]) {
+        char[] a = new char[SIZE];
+        char[] b = new char[SIZE];
+
+        for (int i = 0; i < SIZE; i++) {
+            a[i] = b[i] = (char) i;
+        }
+
+        for (int i = 0; i < 20000; i++) {
+            arrayAbs(a);
+        }
+
+        for (int i = 0; i < SIZE; i++) {
+            if (a[i] != b[i]) {
+                throw new RuntimeException("Broken!");
+            }
+        }
+    }
+
+    private static void arrayAbs(char[] arr) {
+        for (int i = 0; i < SIZE; i++) {
+            arr[i] = (char) Math.abs(arr[i]);
+        }
+    }
+}
+