8213419: C2 may hang in MulLNode::Ideal()/MulINode::Ideal() with gcc 8.2.1
authorroland
Wed, 14 Nov 2018 13:15:54 +0100
changeset 52632 1089e8fd8439
parent 52631 3009ca99de32
child 52633 f94ac11610b3
8213419: C2 may hang in MulLNode::Ideal()/MulINode::Ideal() with gcc 8.2.1 Reviewed-by: kvn, dlong, aph
src/hotspot/cpu/aarch64/assembler_aarch64.hpp
src/hotspot/share/opto/mulnode.cpp
src/hotspot/share/utilities/globalDefinitions.hpp
test/hotspot/jtreg/compiler/integerArithmetic/MultiplyByIntegerMinHang.java
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp	Tue Nov 20 20:00:15 2018 -0800
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp	Wed Nov 14 13:15:54 2018 +0100
@@ -317,29 +317,6 @@
   enum operation { uxtb, uxth, uxtw, uxtx, sxtb, sxth, sxtw, sxtx };
 };
 
-// abs methods which cannot overflow and so are well-defined across
-// the entire domain of integer types.
-static inline unsigned int uabs(unsigned int n) {
-  union {
-    unsigned int result;
-    int value;
-  };
-  result = n;
-  if (value < 0) result = -result;
-  return result;
-}
-static inline unsigned long uabs(unsigned long n) {
-  union {
-    unsigned long result;
-    long value;
-  };
-  result = n;
-  if (value < 0) result = -result;
-  return result;
-}
-static inline unsigned long uabs(long n) { return uabs((unsigned long)n); }
-static inline unsigned long uabs(int n) { return uabs((unsigned int)n); }
-
 // Addressing modes
 class Address {
  public:
--- a/src/hotspot/share/opto/mulnode.cpp	Tue Nov 20 20:00:15 2018 -0800
+++ b/src/hotspot/share/opto/mulnode.cpp	Wed Nov 14 13:15:54 2018 +0100
@@ -170,7 +170,6 @@
   return mul_ring(t1,t2);            // Local flavor of type multiplication
 }
 
-
 //=============================================================================
 //------------------------------Ideal------------------------------------------
 // Check for power-of-2 multiply, then try the regular MulNode::Ideal
@@ -185,42 +184,43 @@
   }
 
   // Now we have a constant Node on the right and the constant in con
-  if( con == 0 ) return NULL;   // By zero is handled by Value call
-  if( con == 1 ) return NULL;   // By one  is handled by Identity call
+  if (con == 0) return NULL;   // By zero is handled by Value call
+  if (con == 1) return NULL;   // By one  is handled by Identity call
 
   // Check for negative constant; if so negate the final result
   bool sign_flip = false;
-  if( con < 0 ) {
-    con = -con;
+
+  unsigned int abs_con = uabs(con);
+  if (abs_con != (unsigned int)con) {
     sign_flip = true;
   }
 
   // Get low bit; check for being the only bit
   Node *res = NULL;
-  jint bit1 = con & -con;       // Extract low bit
-  if( bit1 == con ) {           // Found a power of 2?
-    res = new LShiftINode( in(1), phase->intcon(log2_intptr(bit1)) );
+  unsigned int bit1 = abs_con & (0-abs_con);       // Extract low bit
+  if (bit1 == abs_con) {           // Found a power of 2?
+    res = new LShiftINode(in(1), phase->intcon(log2_intptr(bit1)));
   } else {
 
     // Check for constant with 2 bits set
-    jint bit2 = con-bit1;
-    bit2 = bit2 & -bit2;          // Extract 2nd bit
-    if( bit2 + bit1 == con ) {    // Found all bits in con?
-      Node *n1 = phase->transform( new LShiftINode( in(1), phase->intcon(log2_intptr(bit1)) ) );
-      Node *n2 = phase->transform( new LShiftINode( in(1), phase->intcon(log2_intptr(bit2)) ) );
-      res = new AddINode( n2, n1 );
+    unsigned int bit2 = abs_con-bit1;
+    bit2 = bit2 & (0-bit2);          // Extract 2nd bit
+    if (bit2 + bit1 == abs_con) {    // Found all bits in con?
+      Node *n1 = phase->transform( new LShiftINode(in(1), phase->intcon(log2_intptr(bit1))));
+      Node *n2 = phase->transform( new LShiftINode(in(1), phase->intcon(log2_intptr(bit2))));
+      res = new AddINode(n2, n1);
 
-    } else if (is_power_of_2(con+1)) {
+    } else if (is_power_of_2(abs_con+1)) {
       // Sleezy: power-of-2 -1.  Next time be generic.
-      jint temp = (jint) (con + 1);
-      Node *n1 = phase->transform( new LShiftINode( in(1), phase->intcon(log2_intptr(temp)) ) );
-      res = new SubINode( n1, in(1) );
+      unsigned int temp = abs_con + 1;
+      Node *n1 = phase->transform(new LShiftINode(in(1), phase->intcon(log2_intptr(temp))));
+      res = new SubINode(n1, in(1));
     } else {
       return MulNode::Ideal(phase, can_reshape);
     }
   }
 
-  if( sign_flip ) {             // Need to negate result?
+  if (sign_flip) {             // Need to negate result?
     res = phase->transform(res);// Transform, before making the zero con
     res = new SubINode(phase->intcon(0),res);
   }
@@ -281,42 +281,42 @@
   }
 
   // Now we have a constant Node on the right and the constant in con
-  if( con == CONST64(0) ) return NULL;  // By zero is handled by Value call
-  if( con == CONST64(1) ) return NULL;  // By one  is handled by Identity call
+  if (con == CONST64(0)) return NULL;  // By zero is handled by Value call
+  if (con == CONST64(1)) return NULL;  // By one  is handled by Identity call
 
   // Check for negative constant; if so negate the final result
   bool sign_flip = false;
-  if( con < 0 ) {
-    con = -con;
+  unsigned long abs_con = uabs(con);
+  if (abs_con != (unsigned long)con) {
     sign_flip = true;
   }
 
   // Get low bit; check for being the only bit
   Node *res = NULL;
-  jlong bit1 = con & -con;      // Extract low bit
-  if( bit1 == con ) {           // Found a power of 2?
-    res = new LShiftLNode( in(1), phase->intcon(log2_long(bit1)) );
+  unsigned long bit1 = abs_con & (0-abs_con);      // Extract low bit
+  if (bit1 == abs_con) {           // Found a power of 2?
+    res = new LShiftLNode(in(1), phase->intcon(log2_long(bit1)));
   } else {
 
     // Check for constant with 2 bits set
-    jlong bit2 = con-bit1;
-    bit2 = bit2 & -bit2;          // Extract 2nd bit
-    if( bit2 + bit1 == con ) {    // Found all bits in con?
-      Node *n1 = phase->transform( new LShiftLNode( in(1), phase->intcon(log2_long(bit1)) ) );
-      Node *n2 = phase->transform( new LShiftLNode( in(1), phase->intcon(log2_long(bit2)) ) );
-      res = new AddLNode( n2, n1 );
+    unsigned long bit2 = abs_con-bit1;
+    bit2 = bit2 & (0-bit2);          // Extract 2nd bit
+    if (bit2 + bit1 == abs_con) {    // Found all bits in con?
+      Node *n1 = phase->transform(new LShiftLNode(in(1), phase->intcon(log2_long(bit1))));
+      Node *n2 = phase->transform(new LShiftLNode(in(1), phase->intcon(log2_long(bit2))));
+      res = new AddLNode(n2, n1);
 
-    } else if (is_power_of_2_long(con+1)) {
+    } else if (is_power_of_2_long(abs_con+1)) {
       // Sleezy: power-of-2 -1.  Next time be generic.
-      jlong temp = (jlong) (con + 1);
-      Node *n1 = phase->transform( new LShiftLNode( in(1), phase->intcon(log2_long(temp)) ) );
-      res = new SubLNode( n1, in(1) );
+      unsigned long temp = abs_con + 1;
+      Node *n1 = phase->transform( new LShiftLNode(in(1), phase->intcon(log2_long(temp))));
+      res = new SubLNode(n1, in(1));
     } else {
       return MulNode::Ideal(phase, can_reshape);
     }
   }
 
-  if( sign_flip ) {             // Need to negate result?
+  if (sign_flip) {             // Need to negate result?
     res = phase->transform(res);// Transform, before making the zero con
     res = new SubLNode(phase->longcon(0),res);
   }
--- a/src/hotspot/share/utilities/globalDefinitions.hpp	Tue Nov 20 20:00:15 2018 -0800
+++ b/src/hotspot/share/utilities/globalDefinitions.hpp	Wed Nov 14 13:15:54 2018 +0100
@@ -1034,10 +1034,10 @@
 // Returns largest i such that 2^i <= x.
 // If x < 0, the function returns 31 on a 32-bit machine and 63 on a 64-bit machine.
 // If x == 0, the function returns -1.
-inline int log2_intptr(intptr_t x) {
+inline int log2_intptr(uintptr_t x) {
   int i = -1;
   uintptr_t p = 1;
-  while (p != 0 && p <= (uintptr_t)x) {
+  while (p != 0 && p <= x) {
     // p = 2^(i+1) && p <= x (i.e., 2^(i+1) <= x)
     i++; p *= 2;
   }
@@ -1048,10 +1048,10 @@
 
 //* largest i such that 2^i <= x
 //  A negative value of 'x' will return '63'
-inline int log2_long(jlong x) {
+inline int log2_long(unsigned long x) {
   int i = -1;
   julong p =  1;
-  while (p != 0 && p <= (julong)x) {
+  while (p != 0 && p <= x) {
     // p = 2^(i+1) && p <= x (i.e., 2^(i+1) <= x)
     i++; p *= 2;
   }
@@ -1060,6 +1060,22 @@
   return i;
 }
 
+inline int log2_intptr(intptr_t x) {
+  return log2_intptr((uintptr_t)x);
+}
+
+inline int log2_intptr(int x) {
+  return log2_intptr((uintptr_t)x);
+}
+
+inline int log2_intptr(uint x) {
+  return log2_intptr((uintptr_t)x);
+}
+
+inline int log2_long(jlong x) {
+  return log2_long((unsigned long)x);
+}
+
 //* the argument must be exactly a power of 2
 inline int exact_log2(intptr_t x) {
   assert(is_power_of_2(x), "x must be a power of 2: " INTPTR_FORMAT, x);
@@ -1075,6 +1091,29 @@
 inline bool is_odd (intx x) { return x & 1;      }
 inline bool is_even(intx x) { return !is_odd(x); }
 
+// abs methods which cannot overflow and so are well-defined across
+// the entire domain of integer types.
+static inline unsigned int uabs(unsigned int n) {
+  union {
+    unsigned int result;
+    int value;
+  };
+  result = n;
+  if (value < 0) result = 0-result;
+  return result;
+}
+static inline unsigned long uabs(unsigned long n) {
+  union {
+    unsigned long result;
+    long value;
+  };
+  result = n;
+  if (value < 0) result = 0-result;
+  return result;
+}
+static inline unsigned long uabs(jlong n) { return uabs((unsigned long)n); }
+static inline unsigned int uabs(int n) { return uabs((unsigned int)n); }
+
 // "to" should be greater than "from."
 inline intx byte_size(void* from, void* to) {
   return (address)to - (address)from;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/integerArithmetic/MultiplyByIntegerMinHang.java	Wed Nov 14 13:15:54 2018 +0100
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018, Red Hat, Inc. 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 8213419
+ * @summary C2 may hang in MulLNode::Ideal()/MulINode::Ideal() with gcc 8.2.1
+ *
+ * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement MultiplyByIntegerMinHang
+ *
+ */
+
+public class MultiplyByIntegerMinHang {
+    public static void main(String[] args) {
+        for (int i = 0; i < 20_000; i++) {
+            if (test1(0) != 0) {
+                throw new RuntimeException("incorrect result");
+            }
+            if (test1(1) != Integer.MIN_VALUE) {
+                throw new RuntimeException("incorrect result");
+            }
+            if (test1(2) != 0) {
+                throw new RuntimeException("incorrect result");
+            }
+            if (test2(0) != 0) {
+                throw new RuntimeException("incorrect result");
+            }
+            if (test2(1) != Long.MIN_VALUE) {
+                throw new RuntimeException("incorrect result");
+            }
+            if (test2(2) != 0) {
+                throw new RuntimeException("incorrect result");
+            }
+        }
+    }
+
+    private static int test1(int v) {
+        return v * Integer.MIN_VALUE;
+    }
+
+    private static long test2(long v) {
+        return v * Long.MIN_VALUE;
+    }
+}