changeset 1295:f3fb145b87ba

6930043: C2: SIGSEGV in javasoft.sqe.tests.lang.arr017.arr01702.arr01702.loop_forw(II)I Reviewed-by: kvn
author never
date Thu, 18 Mar 2010 13:25:46 -0700
parents 2cb394bd7f8f
children 13b5f241341a
files src/share/vm/opto/loopTransform.cpp src/share/vm/opto/loopnode.hpp test/compiler/6930043/Test6930043.java
diffstat 3 files changed, 179 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/opto/loopTransform.cpp	Tue Mar 16 15:58:47 2010 -0700
+++ b/src/share/vm/opto/loopTransform.cpp	Thu Mar 18 13:25:46 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2010 Sun Microsystems, 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
@@ -2088,29 +2088,41 @@
 BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl,
                                        int scale, Node* offset,
                                        Node* init, Node* limit, Node* stride,
-                                       Node* range) {
+                                       Node* range, bool upper) {
+  DEBUG_ONLY(ttyLocker ttyl);
+  if (TraceLoopPredicate) tty->print("rc_predicate ");
+
   Node* max_idx_expr  = init;
   int stride_con = stride->get_int();
-  if ((stride_con > 0) == (scale > 0)) {
+  if ((stride_con > 0) == (scale > 0) == upper) {
     max_idx_expr = new (C, 3) SubINode(limit, stride);
     register_new_node(max_idx_expr, ctrl);
+    if (TraceLoopPredicate) tty->print("(limit - stride) ");
+  } else {
+    if (TraceLoopPredicate) tty->print("init ");
   }
 
   if (scale != 1) {
     ConNode* con_scale = _igvn.intcon(scale);
     max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale);
     register_new_node(max_idx_expr, ctrl);
+    if (TraceLoopPredicate) tty->print("* %d ", scale);
   }
 
   if (offset && (!offset->is_Con() || offset->get_int() != 0)){
     max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset);
     register_new_node(max_idx_expr, ctrl);
+    if (TraceLoopPredicate)
+      if (offset->is_Con()) tty->print("+ %d ", offset->get_int());
+      else tty->print("+ offset ");
   }
 
   CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range);
   register_new_node(cmp, ctrl);
   BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt);
   register_new_node(bol, ctrl);
+
+  if (TraceLoopPredicate) tty->print_cr("<u range");
   return bol;
 }
 
@@ -2187,7 +2199,6 @@
   while (if_proj_list.size() > 0) {
     // Following are changed to nonnull when a predicate can be hoisted
     ProjNode* new_predicate_proj = NULL;
-    BoolNode* new_predicate_bol   = NULL;
 
     ProjNode* proj = if_proj_list.pop()->as_Proj();
     IfNode*   iff  = proj->in(0)->as_If();
@@ -2218,93 +2229,120 @@
       // Invariant test
       new_predicate_proj = create_new_if_for_predicate(predicate_proj);
       Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0);
-      new_predicate_bol  = invar.clone(bol, ctrl)->as_Bool();
-      if (TraceLoopPredicate) tty->print("invariant");
+      BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool();
+
+      // Negate test if necessary
+      bool negated = false;
+      if (proj->_con != predicate_proj->_con) {
+        new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate());
+        register_new_node(new_predicate_bol, ctrl);
+        negated = true;
+      }
+      IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If();
+      _igvn.hash_delete(new_predicate_iff);
+      new_predicate_iff->set_req(1, new_predicate_bol);
+      if (TraceLoopPredicate) tty->print_cr("invariant if%s: %d", negated ? " negated" : "", new_predicate_iff->_idx);
+
     } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) {
-      // Range check (only for counted loops)
-      new_predicate_proj = create_new_if_for_predicate(predicate_proj);
-      Node *ctrl = new_predicate_proj->in(0)->as_If()->in(0);
+      assert(proj->_con == predicate_proj->_con, "must match");
+
+      // Range check for counted loops
       const Node*    cmp    = bol->in(1)->as_Cmp();
       Node*          idx    = cmp->in(1);
       assert(!invar.is_invariant(idx), "index is variant");
       assert(cmp->in(2)->Opcode() == Op_LoadRange, "must be");
-      LoadRangeNode* ld_rng = (LoadRangeNode*)cmp->in(2); // LoadRangeNode
+      Node* ld_rng = cmp->in(2); // LoadRangeNode
       assert(invar.is_invariant(ld_rng), "load range must be invariant");
-      ld_rng = (LoadRangeNode*)invar.clone(ld_rng, ctrl);
       int scale    = 1;
       Node* offset = zero;
       bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset);
       assert(ok, "must be index expression");
+
+      Node* init    = cl->init_trip();
+      Node* limit   = cl->limit();
+      Node* stride  = cl->stride();
+
+      // Build if's for the upper and lower bound tests.  The
+      // lower_bound test will dominate the upper bound test and all
+      // cloned or created nodes will use the lower bound test as
+      // their declared control.
+      ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj);
+      ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj);
+      assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate");
+      Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0);
+
+      // Perform cloning to keep Invariance state correct since the
+      // late schedule will place invariant things in the loop.
+      ld_rng = invar.clone(ld_rng, ctrl);
       if (offset && offset != zero) {
         assert(invar.is_invariant(offset), "offset must be loop invariant");
         offset = invar.clone(offset, ctrl);
       }
-      Node* init    = cl->init_trip();
-      Node* limit   = cl->limit();
-      Node* stride  = cl->stride();
-      new_predicate_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng);
-      if (TraceLoopPredicate) tty->print("range check");
-    }
+
+      // Test the lower bound
+      Node*  lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng, false);
+      IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If();
+      _igvn.hash_delete(lower_bound_iff);
+      lower_bound_iff->set_req(1, lower_bound_bol);
+      if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx);
 
-    if (new_predicate_proj == NULL) {
+      // Test the upper bound
+      Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng, true);
+      IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If();
+      _igvn.hash_delete(upper_bound_iff);
+      upper_bound_iff->set_req(1, upper_bound_bol);
+      if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx);
+
+      // Fall through into rest of the clean up code which will move
+      // any dependent nodes onto the upper bound test.
+      new_predicate_proj = upper_bound_proj;
+    } else {
       // The other proj of the "iff" is a uncommon trap projection, and we can assume
       // the other proj will not be executed ("executed" means uct raised).
       continue;
-    } else {
-      // Success - attach condition (new_predicate_bol) to predicate if
-      invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate
-      IfNode* new_iff = new_predicate_proj->in(0)->as_If();
+    }
 
-      // Negate test if necessary
-      if (proj->_con != predicate_proj->_con) {
-        new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate());
-        register_new_node(new_predicate_bol, new_iff->in(0));
-        if (TraceLoopPredicate) tty->print_cr(" if negated: %d", iff->_idx);
-      } else {
-        if (TraceLoopPredicate) tty->print_cr(" if: %d", iff->_idx);
-      }
+    // Success - attach condition (new_predicate_bol) to predicate if
+    invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate
 
-      _igvn.hash_delete(new_iff);
-      new_iff->set_req(1, new_predicate_bol);
-
-      _igvn.hash_delete(iff);
-      iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true);
+    // Eliminate the old if in the loop body
+    _igvn.hash_delete(iff);
+    iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true);
 
-      Node* ctrl = new_predicate_proj; // new control
-      ProjNode* dp = proj;     // old control
-      assert(get_loop(dp) == loop, "guarenteed at the time of collecting proj");
-      // Find nodes (depends only on the test) off the surviving projection;
-      // move them outside the loop with the control of proj_clone
-      for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) {
-        Node* cd = dp->fast_out(i); // Control-dependent node
-        if (cd->depends_only_on_test()) {
-          assert(cd->in(0) == dp, "");
-          _igvn.hash_delete(cd);
-          cd->set_req(0, ctrl); // ctrl, not NULL
-          set_early_ctrl(cd);
-          _igvn._worklist.push(cd);
-          IdealLoopTree *new_loop = get_loop(get_ctrl(cd));
-          if (new_loop != loop) {
-            if (!loop->_child) loop->_body.yank(cd);
-            if (!new_loop->_child ) new_loop->_body.push(cd);
-          }
-          --i;
-          --imax;
+    Node* ctrl = new_predicate_proj; // new control
+    ProjNode* dp = proj;     // old control
+    assert(get_loop(dp) == loop, "guaranteed at the time of collecting proj");
+    // Find nodes (depends only on the test) off the surviving projection;
+    // move them outside the loop with the control of proj_clone
+    for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) {
+      Node* cd = dp->fast_out(i); // Control-dependent node
+      if (cd->depends_only_on_test()) {
+        assert(cd->in(0) == dp, "");
+        _igvn.hash_delete(cd);
+        cd->set_req(0, ctrl); // ctrl, not NULL
+        set_early_ctrl(cd);
+        _igvn._worklist.push(cd);
+        IdealLoopTree *new_loop = get_loop(get_ctrl(cd));
+        if (new_loop != loop) {
+          if (!loop->_child) loop->_body.yank(cd);
+          if (!new_loop->_child ) new_loop->_body.push(cd);
         }
+        --i;
+        --imax;
       }
+    }
 
-      hoisted = true;
-      C->set_major_progress();
-    }
+    hoisted = true;
+    C->set_major_progress();
   } // end while
 
 #ifndef PRODUCT
-    // report that the loop predication has been actually performed
-    // for this loop
-    if (TraceLoopPredicate && hoisted) {
-      tty->print("Loop Predication Performed:");
-      loop->dump_head();
-    }
+  // report that the loop predication has been actually performed
+  // for this loop
+  if (TraceLoopPredicate && hoisted) {
+    tty->print("Loop Predication Performed:");
+    loop->dump_head();
+  }
 #endif
 
   return hoisted;
--- a/src/share/vm/opto/loopnode.hpp	Tue Mar 16 15:58:47 2010 -0700
+++ b/src/share/vm/opto/loopnode.hpp	Thu Mar 18 13:25:46 2010 -0700
@@ -821,7 +821,7 @@
   BoolNode* rc_predicate(Node* ctrl,
                          int scale, Node* offset,
                          Node* init, Node* limit, Node* stride,
-                         Node* range);
+                         Node* range, bool upper);
 
   // Implementation of the loop predication to promote checks outside the loop
   bool loop_predication_impl(IdealLoopTree *loop);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/6930043/Test6930043.java	Thu Mar 18 13:25:46 2010 -0700
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010 Sun Microsystems, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6930043
+ * @summary C2: SIGSEGV in javasoft.sqe.tests.lang.arr017.arr01702.arr01702.loop_forw(II)I
+ *
+ * @run main Test6930043
+ */
+
+import java.io.PrintStream;
+
+public class Test6930043 {
+    int[] a;
+    int idx;
+
+    public int loop_back(int i, int i_0_) {
+        int i_1_ = 0;
+        int[] is = a;
+        if (is == null) return 0;
+        for (int i_2_ = i; i_2_ >= i_0_; i_2_--)
+            i_1_ += is[idx = i_2_];
+        return i_1_;
+    }
+
+    public int loop_forw(int start, int end) {
+        int result = 0;
+        int[] is = a;
+        if (is == null) return 0;
+        for (int index = start; index < end; index++)
+            result += is[index];
+            // result += is[idx = index];
+        return result;
+    }
+
+    public static void main(String[] strings) {
+        Test6930043 var_Test6930043 = new Test6930043();
+        var_Test6930043.a = new int[1000000];
+        var_Test6930043.loop_forw(10, 999990);
+        var_Test6930043.loop_forw(10, 999990);
+        for (int i = 0; i < 3; i++) {
+            try {
+                if (var_Test6930043.loop_forw(-1, 999990) != 0) throw new InternalError();
+            } catch (ArrayIndexOutOfBoundsException e) { }
+        }
+        var_Test6930043.loop_back(999990, 10);
+        var_Test6930043.loop_back(999990, 10);
+        for (int i = 0; i < 3; i++) {
+            try {
+                if (var_Test6930043.loop_back(999990, -1) != 0) throw new InternalError();
+            } catch (ArrayIndexOutOfBoundsException e) { }
+        }
+    }
+}