changeset 6558:70191d4fad0c

8173770: Image conversion improvements Reviewed-by: kvn, vlivanov, dlong, rhalade, mschoene, iignatyev
author thartmann
date Thu, 30 Mar 2017 15:28:33 +0200
parents caa1441e595c
children 3a1e34513b37
files src/cpu/sparc/vm/sparc.ad src/cpu/x86/vm/x86_32.ad src/cpu/x86/vm/x86_64.ad src/share/vm/adlc/archDesc.cpp src/share/vm/opto/classes.hpp src/share/vm/opto/loopPredicate.cpp src/share/vm/opto/loopnode.hpp src/share/vm/opto/output.cpp src/share/vm/opto/subnode.cpp src/share/vm/opto/subnode.hpp src/share/vm/runtime/vmStructs.cpp
diffstat 11 files changed, 521 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/sparc/vm/sparc.ad	Wed May 03 03:39:51 2017 +0100
+++ b/src/cpu/sparc/vm/sparc.ad	Thu Mar 30 15:28:33 2017 +0200
@@ -3448,6 +3448,16 @@
   interface(CONST_INTER);
 %}
 
+// Unsigned Long Immediate: 12-bit (non-negative that fits in simm13)
+operand immUL12() %{
+  predicate((0 <= n->get_long()) && (n->get_long() == (int)n->get_long()) && Assembler::is_simm13((int)n->get_long()));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Int Immediate non-negative
 operand immU31()
 %{
@@ -4068,6 +4078,15 @@
   interface(REG_INTER);
 %}
 
+// Condition Code Register, unsigned long comparisons.
+operand flagsRegUL() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+
+  format %{ "xcc_UL" %}
+  interface(REG_INTER);
+%}
+
 // Condition Code Register, floating comparisons, unordered same as "less".
 operand flagsRegF() %{
   constraint(ALLOC_IN_RC(float_flags));
@@ -8864,6 +8883,17 @@
   ins_pipe(ialu_cconly_reg_reg);
 %}
 
+instruct compUL_iReg(flagsRegUL xcc, iRegL op1, iRegL op2) %{
+  match(Set xcc (CmpUL op1 op2));
+  effect(DEF xcc, USE op1, USE op2);
+
+  size(4);
+  format %{ "CMP    $op1,$op2\t! unsigned long" %}
+  opcode(Assembler::subcc_op3, Assembler::arith_op);
+  ins_encode(form3_rs1_rs2_rd(op1, op2, R_G0));
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+
 instruct compI_iReg_imm13(flagsReg icc, iRegI op1, immI13 op2) %{
   match(Set icc (CmpI op1 op2));
   effect( DEF icc, USE op1 );
@@ -8950,6 +8980,17 @@
   ins_pipe(ialu_cconly_reg_imm);
 %}
 
+instruct compUL_iReg_imm13(flagsRegUL xcc, iRegL op1, immUL12 op2) %{
+  match(Set xcc (CmpUL op1 op2));
+  effect(DEF xcc, USE op1, USE op2);
+
+  size(4);
+  format %{ "CMP    $op1,$op2\t! unsigned long" %}
+  opcode(Assembler::subcc_op3, Assembler::arith_op);
+  ins_encode(form3_rs1_simm13_rd(op1, op2, R_G0));
+  ins_pipe(ialu_cconly_reg_imm);
+%}
+
 // Compare Pointers
 instruct compP_iRegP(flagsRegP pcc, iRegP op1, iRegP op2 ) %{
   match(Set pcc (CmpP op1 op2));
@@ -9316,6 +9357,44 @@
   ins_pipe(cmp_br_reg_imm);
 %}
 
+instruct cmpUL_reg_branch(cmpOpU cmp, iRegL op1, iRegL op2, label labl, flagsRegUL xcc) %{
+  match(If cmp (CmpUL op1 op2));
+  effect(USE labl, KILL xcc);
+
+  size(12);
+  ins_cost(BRANCH_COST);
+  format %{ "CMP    $op1,$op2\t! unsigned long\n\t"
+            "BP$cmp   $labl" %}
+  ins_encode %{
+    Label* L = $labl$$label;
+    Assembler::Predict predict_taken =
+      cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
+    __ cmp($op1$$Register, $op2$$Register);
+    __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
+    __ delayed()->nop();
+  %}
+  ins_pipe(cmp_br_reg_reg);
+%}
+
+instruct cmpUL_imm_branch(cmpOpU cmp, iRegL op1, immL5 op2, label labl, flagsRegUL xcc) %{
+  match(If cmp (CmpUL op1 op2));
+  effect(USE labl, KILL xcc);
+
+  size(12);
+  ins_cost(BRANCH_COST);
+  format %{ "CMP    $op1,$op2\t! unsigned long\n\t"
+            "BP$cmp   $labl" %}
+  ins_encode %{
+    Label* L = $labl$$label;
+    Assembler::Predict predict_taken =
+      cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
+    __ cmp($op1$$Register, $op2$$constant);
+    __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
+    __ delayed()->nop();
+  %}
+  ins_pipe(cmp_br_reg_imm);
+%}
+
 instruct cmpL_reg_branch(cmpOp cmp, iRegL op1, iRegL op2, label labl, flagsRegL xcc) %{
   match(If cmp (CmpL op1 op2));
   effect(USE labl, KILL xcc);
@@ -9544,6 +9623,42 @@
   ins_pipe(cbcond_reg_imm);
 %}
 
+instruct cmpUL_reg_branch_short(cmpOpU cmp, iRegL op1, iRegL op2, label labl, flagsRegUL xcc) %{
+  match(If cmp (CmpUL op1 op2));
+  predicate(UseCBCond);
+  effect(USE labl, KILL xcc);
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "CXB$cmp  $op1,$op2,$labl\t! unsigned long" %}
+  ins_encode %{
+    Label* L = $labl$$label;
+    assert(__ use_cbcond(*L), "back to back cbcond");
+    __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$Register, *L);
+  %}
+  ins_short_branch(1);
+  ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
+  ins_pipe(cbcond_reg_reg);
+%}
+
+instruct cmpUL_imm_branch_short(cmpOpU cmp, iRegL op1, immL5 op2, label labl, flagsRegUL xcc) %{
+  match(If cmp (CmpUL op1 op2));
+  predicate(UseCBCond);
+  effect(USE labl, KILL xcc);
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "CXB$cmp  $op1,$op2,$labl\t! unsigned long" %}
+  ins_encode %{
+    Label* L = $labl$$label;
+    assert(__ use_cbcond(*L), "back to back cbcond");
+    __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$constant, *L);
+  %}
+  ins_short_branch(1);
+  ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
+  ins_pipe(cbcond_reg_imm);
+%}
+
 instruct cmpL_reg_branch_short(cmpOp cmp, iRegL op1, iRegL op2, label labl, flagsRegL xcc) %{
   match(If cmp (CmpL op1 op2));
   predicate(UseCBCond);
@@ -9778,6 +9893,25 @@
   ins_pipe(br_cc);
 %}
 
+instruct branchConU_long(cmpOpU cmp, flagsRegUL xcc, label labl) %{
+  match(If cmp xcc);
+  effect(USE labl);
+
+  size(8);
+  ins_cost(BRANCH_COST);
+  format %{ "BP$cmp   $xcc,$labl" %}
+  ins_encode %{
+    Label* L = $labl$$label;
+    Assembler::Predict predict_taken =
+      cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
+
+    __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
+    __ delayed()->nop();
+  %}
+  ins_avoid_back_to_back(AVOID_BEFORE);
+  ins_pipe(br_cc);
+%}
+
 // Manifest a CmpL3 result in an integer register.  Very painful.
 // This is the test to avoid.
 instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{
--- a/src/cpu/x86/vm/x86_32.ad	Wed May 03 03:39:51 2017 +0100
+++ b/src/cpu/x86/vm/x86_32.ad	Thu Mar 30 15:28:33 2017 +0200
@@ -4545,6 +4545,26 @@
   interface(REG_INTER);
 %}
 
+// Condition Code Register used by unsigned long compare
+operand flagsReg_ulong_LTGE() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+  format %{ "FLAGS_U_LTGE" %}
+  interface(REG_INTER);
+%}
+operand flagsReg_ulong_EQNE() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+  format %{ "FLAGS_U_EQNE" %}
+  interface(REG_INTER);
+%}
+operand flagsReg_ulong_LEGT() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+  format %{ "FLAGS_U_LEGT" %}
+  interface(REG_INTER);
+%}
+
 // Float register operands
 operand regDPR() %{
   predicate( UseSSE < 2 );
@@ -5058,7 +5078,7 @@
   %}
 %}
 
-// Comparision Code used in long compares
+// Comparison Code used in long compares
 operand cmpOp_commute() %{
   match(Bool);
 
@@ -5073,6 +5093,23 @@
   %}
 %}
 
+// Comparison Code used in unsigned long compares
+operand cmpOpU_commute() %{
+  match(Bool);
+
+  format %{ "" %}
+  interface(COND_INTER) %{
+    equal(0x4, "e");
+    not_equal(0x5, "ne");
+    less(0x7, "nbe");
+    greater_equal(0x6, "be");
+    less_equal(0x3, "nb");
+    greater(0x2, "b");
+    overflow(0x0, "o");
+    no_overflow(0x1, "no");
+  %}
+%}
+
 //----------OPERAND CLASSES----------------------------------------------------
 // Operand Classes are groups of operands that are used as to simplify
 // instruction definitions by not requiring the AD writer to specify separate
@@ -12502,6 +12539,44 @@
   %}
 %}
 
+//======
+// Manifest a CmpUL result in the normal flags.  Only good for LT or GE
+// compares.  Can be used for LE or GT compares by reversing arguments.
+// NOT GOOD FOR EQ/NE tests.
+instruct cmpUL_zero_flags_LTGE(flagsReg_ulong_LTGE flags, eRegL src, immL0 zero) %{
+  match(Set flags (CmpUL src zero));
+  ins_cost(100);
+  format %{ "TEST   $src.hi,$src.hi" %}
+  opcode(0x85);
+  ins_encode(OpcP, RegReg_Hi2(src, src));
+  ins_pipe(ialu_cr_reg_reg);
+%}
+
+// Manifest a CmpUL result in the normal flags.  Only good for LT or GE
+// compares.  Can be used for LE or GT compares by reversing arguments.
+// NOT GOOD FOR EQ/NE tests.
+instruct cmpUL_reg_flags_LTGE(flagsReg_ulong_LTGE flags, eRegL src1, eRegL src2, rRegI tmp) %{
+  match(Set flags (CmpUL src1 src2));
+  effect(TEMP tmp);
+  ins_cost(300);
+  format %{ "CMP    $src1.lo,$src2.lo\t! Unsigned long compare; set flags for low bits\n\t"
+            "MOV    $tmp,$src1.hi\n\t"
+            "SBB    $tmp,$src2.hi\t! Compute flags for unsigned long compare" %}
+  ins_encode(long_cmp_flags2(src1, src2, tmp));
+  ins_pipe(ialu_cr_reg_reg);
+%}
+
+// Unsigned long compares reg < zero/req OR reg >= zero/req.
+// Just a wrapper for a normal branch, plus the predicate test.
+instruct cmpUL_LTGE(cmpOpU cmp, flagsReg_ulong_LTGE flags, label labl) %{
+  match(If cmp flags);
+  effect(USE labl);
+  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  expand %{
+    jmpCon(cmp, flags, labl);    // JLT or JGE...
+  %}
+%}
+
 // Compare 2 longs and CMOVE longs.
 instruct cmovLL_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, eRegL dst, eRegL src) %{
   match(Set dst (CMoveL (Binary cmp flags) (Binary dst src)));
@@ -12630,6 +12705,41 @@
   %}
 %}
 
+//======
+// Manifest a CmpUL result in the normal flags.  Only good for EQ/NE compares.
+instruct cmpUL_zero_flags_EQNE(flagsReg_ulong_EQNE flags, eRegL src, immL0 zero, rRegI tmp) %{
+  match(Set flags (CmpUL src zero));
+  effect(TEMP tmp);
+  ins_cost(200);
+  format %{ "MOV    $tmp,$src.lo\n\t"
+            "OR     $tmp,$src.hi\t! Unsigned long is EQ/NE 0?" %}
+  ins_encode(long_cmp_flags0(src, tmp));
+  ins_pipe(ialu_reg_reg_long);
+%}
+
+// Manifest a CmpUL result in the normal flags.  Only good for EQ/NE compares.
+instruct cmpUL_reg_flags_EQNE(flagsReg_ulong_EQNE flags, eRegL src1, eRegL src2) %{
+  match(Set flags (CmpUL src1 src2));
+  ins_cost(200+300);
+  format %{ "CMP    $src1.lo,$src2.lo\t! Unsigned long compare; set flags for low bits\n\t"
+            "JNE,s  skip\n\t"
+            "CMP    $src1.hi,$src2.hi\n\t"
+     "skip:\t" %}
+  ins_encode(long_cmp_flags1(src1, src2));
+  ins_pipe(ialu_cr_reg_reg);
+%}
+
+// Unsigned long compare reg == zero/reg OR reg != zero/reg
+// Just a wrapper for a normal branch, plus the predicate test.
+instruct cmpUL_EQNE(cmpOpU cmp, flagsReg_ulong_EQNE flags, label labl) %{
+  match(If cmp flags);
+  effect(USE labl);
+  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);
+  expand %{
+    jmpCon(cmp, flags, labl);    // JEQ or JNE...
+  %}
+%}
+
 // Compare 2 longs and CMOVE longs.
 instruct cmovLL_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, eRegL dst, eRegL src) %{
   match(Set dst (CMoveL (Binary cmp flags) (Binary dst src)));
@@ -12763,6 +12873,46 @@
   %}
 %}
 
+//======
+// Manifest a CmpUL result in the normal flags.  Only good for LE or GT compares.
+// Same as cmpUL_reg_flags_LEGT except must negate src
+instruct cmpUL_zero_flags_LEGT(flagsReg_ulong_LEGT flags, eRegL src, immL0 zero, rRegI tmp) %{
+  match(Set flags (CmpUL src zero));
+  effect(TEMP tmp);
+  ins_cost(300);
+  format %{ "XOR    $tmp,$tmp\t# Unsigned long compare for -$src < 0, use commuted test\n\t"
+            "CMP    $tmp,$src.lo\n\t"
+            "SBB    $tmp,$src.hi\n\t" %}
+  ins_encode(long_cmp_flags3(src, tmp));
+  ins_pipe(ialu_reg_reg_long);
+%}
+
+// Manifest a CmpUL result in the normal flags.  Only good for LE or GT compares.
+// Same as cmpUL_reg_flags_LTGE except operands swapped.  Swapping operands
+// requires a commuted test to get the same result.
+instruct cmpUL_reg_flags_LEGT(flagsReg_ulong_LEGT flags, eRegL src1, eRegL src2, rRegI tmp) %{
+  match(Set flags (CmpUL src1 src2));
+  effect(TEMP tmp);
+  ins_cost(300);
+  format %{ "CMP    $src2.lo,$src1.lo\t! Unsigned long compare, swapped operands, use with commuted test\n\t"
+            "MOV    $tmp,$src2.hi\n\t"
+            "SBB    $tmp,$src1.hi\t! Compute flags for unsigned long compare" %}
+  ins_encode(long_cmp_flags2( src2, src1, tmp));
+  ins_pipe(ialu_cr_reg_reg);
+%}
+
+// Unsigned long compares reg < zero/req OR reg >= zero/req.
+// Just a wrapper for a normal branch, plus the predicate test
+instruct cmpUL_LEGT(cmpOpU_commute cmp, flagsReg_ulong_LEGT flags, label labl) %{
+  match(If cmp flags);
+  effect(USE labl);
+  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le);
+  ins_cost(300);
+  expand %{
+    jmpCon(cmp, flags, labl);    // JGT or JLE...
+  %}
+%}
+
 // Compare 2 longs and CMOVE longs.
 instruct cmovLL_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, eRegL dst, eRegL src) %{
   match(Set dst (CMoveL (Binary cmp flags) (Binary dst src)));
--- a/src/cpu/x86/vm/x86_64.ad	Wed May 03 03:39:51 2017 +0100
+++ b/src/cpu/x86/vm/x86_64.ad	Thu Mar 30 15:28:33 2017 +0200
@@ -10738,6 +10738,48 @@
   ins_pipe(pipe_slow);
 %}
 
+// Unsigned long compare Instructions; really, same as signed long except they
+// produce an rFlagsRegU instead of rFlagsReg.
+instruct compUL_rReg(rFlagsRegU cr, rRegL op1, rRegL op2)
+%{
+  match(Set cr (CmpUL op1 op2));
+
+  format %{ "cmpq    $op1, $op2\t# unsigned" %}
+  opcode(0x3B);  /* Opcode 3B /r */
+  ins_encode(REX_reg_reg_wide(op1, op2), OpcP, reg_reg(op1, op2));
+  ins_pipe(ialu_cr_reg_reg);
+%}
+
+instruct compUL_rReg_imm(rFlagsRegU cr, rRegL op1, immL32 op2)
+%{
+  match(Set cr (CmpUL op1 op2));
+
+  format %{ "cmpq    $op1, $op2\t# unsigned" %}
+  opcode(0x81, 0x07); /* Opcode 81 /7 */
+  ins_encode(OpcSErm_wide(op1, op2), Con8or32(op2));
+  ins_pipe(ialu_cr_reg_imm);
+%}
+
+instruct compUL_rReg_mem(rFlagsRegU cr, rRegL op1, memory op2)
+%{
+  match(Set cr (CmpUL op1 (LoadL op2)));
+
+  format %{ "cmpq    $op1, $op2\t# unsigned" %}
+  opcode(0x3B); /* Opcode 3B /r */
+  ins_encode(REX_reg_mem_wide(op1, op2), OpcP, reg_mem(op1, op2));
+  ins_pipe(ialu_cr_reg_mem);
+%}
+
+instruct testUL_reg(rFlagsRegU cr, rRegL src, immL0 zero)
+%{
+  match(Set cr (CmpUL src zero));
+
+  format %{ "testq   $src, $src\t# unsigned" %}
+  opcode(0x85);
+  ins_encode(REX_reg_reg_wide(src, src), OpcP, reg_reg(src, src));
+  ins_pipe(ialu_cr_reg_imm);
+%}
+
 //----------Max and Min--------------------------------------------------------
 // Min Instructions
 
--- a/src/share/vm/adlc/archDesc.cpp	Wed May 03 03:39:51 2017 +0100
+++ b/src/share/vm/adlc/archDesc.cpp	Thu Mar 30 15:28:33 2017 +0200
@@ -1187,6 +1187,7 @@
          || strcmp(idealName,"CmpP") == 0
          || strcmp(idealName,"CmpN") == 0
          || strcmp(idealName,"CmpL") == 0
+         || strcmp(idealName,"CmpUL") == 0
          || strcmp(idealName,"CmpD") == 0
          || strcmp(idealName,"CmpF") == 0
          || strcmp(idealName,"FastLock") == 0
--- a/src/share/vm/opto/classes.hpp	Wed May 03 03:39:51 2017 +0100
+++ b/src/share/vm/opto/classes.hpp	Thu Mar 30 15:28:33 2017 +0200
@@ -79,6 +79,7 @@
 macro(CmpLTMask)
 macro(CmpP)
 macro(CmpU)
+macro(CmpUL)
 macro(CompareAndSwapI)
 macro(CompareAndSwapL)
 macro(CompareAndSwapP)
--- a/src/share/vm/opto/loopPredicate.cpp	Wed May 03 03:39:51 2017 +0100
+++ b/src/share/vm/opto/loopPredicate.cpp	Thu Mar 30 15:28:33 2017 +0200
@@ -28,6 +28,7 @@
 #include "opto/callnode.hpp"
 #include "opto/connode.hpp"
 #include "opto/loopnode.hpp"
+#include "opto/matcher.hpp"
 #include "opto/mulnode.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/subnode.hpp"
@@ -644,50 +645,140 @@
 //   max(scale*i + offset) = scale*init + offset
 BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl,
                                        int scale, Node* offset,
-                                       Node* init, Node* limit, Node* stride,
-                                       Node* range, bool upper) {
+                                       Node* init, Node* limit, jint stride,
+                                       Node* range, bool upper, bool &overflow) {
+  jint con_limit  = limit->is_Con()  ? limit->get_int()  : 0;
+  jint con_init   = init->is_Con()   ? init->get_int()   : 0;
+  jint con_offset = offset->is_Con() ? offset->get_int() : 0;
+
   stringStream* predString = NULL;
   if (TraceLoopPredicate) {
     predString = new stringStream();
     predString->print("rc_predicate ");
   }
 
-  Node* max_idx_expr  = init;
-  int stride_con = stride->get_int();
-  if ((stride_con > 0) == (scale > 0) == upper) {
-    if (LoopLimitCheck) {
-      // With LoopLimitCheck limit is not exact.
-      // Calculate exact limit here.
-      // Note, counted loop's test is '<' or '>'.
-      limit = exact_limit(loop);
-      max_idx_expr = new (C) SubINode(limit, stride);
-      register_new_node(max_idx_expr, ctrl);
-      if (TraceLoopPredicate) predString->print("(limit - stride) ");
+  overflow = false;
+  Node* max_idx_expr = NULL;
+  const TypeInt* idx_type = TypeInt::INT;
+  if ((stride > 0) == (scale > 0) == upper) {
+    if (TraceLoopPredicate) {
+      predString->print(limit->is_Con() ? "(%d " : "(limit ", con_limit);
+      predString->print("- %d) ", stride);
+    }
+    // Check if (limit - stride) may overflow
+    const TypeInt* limit_type = _igvn.type(limit)->isa_int();
+    jint limit_lo = limit_type->_lo;
+    jint limit_hi = limit_type->_hi;
+    jint res_lo = limit_lo - stride;
+    jint res_hi = limit_hi - stride;
+    if ((stride > 0 && (res_lo < limit_lo)) ||
+        (stride < 0 && (res_hi > limit_hi))) {
+      // No overflow possible
+      ConINode* con_stride = _igvn.intcon(stride);
+      set_ctrl(con_stride, C->root());
+      max_idx_expr = new (C) SubINode(limit, con_stride);
+      idx_type = TypeInt::make(limit_lo - stride, limit_hi - stride, limit_type->_widen);
     } else {
-      max_idx_expr = new (C) SubINode(limit, stride);
-      register_new_node(max_idx_expr, ctrl);
-      if (TraceLoopPredicate) predString->print("(limit - stride) ");
+      // May overflow
+      overflow = true;
+      limit = new (C) ConvI2LNode(limit);
+      register_new_node(limit, ctrl);
+      ConLNode* con_stride = _igvn.longcon(stride);
+      set_ctrl(con_stride, C->root());
+      max_idx_expr = new (C) SubLNode(limit, con_stride);
     }
+    register_new_node(max_idx_expr, ctrl);
   } else {
-    if (TraceLoopPredicate) predString->print("init ");
+    if (TraceLoopPredicate) {
+      predString->print(init->is_Con() ? "%d " : "init ", con_init);
+    }
+    idx_type = _igvn.type(init)->isa_int();
+    max_idx_expr = init;
   }
 
   if (scale != 1) {
     ConNode* con_scale = _igvn.intcon(scale);
-    max_idx_expr = new (C) MulINode(max_idx_expr, con_scale);
+    set_ctrl(con_scale, C->root());
+    if (TraceLoopPredicate) {
+      predString->print("* %d ", scale);
+    }
+    // Check if (scale * max_idx_expr) may overflow
+    const TypeInt* scale_type = TypeInt::make(scale);
+    MulINode* mul = new (C) MulINode(max_idx_expr, con_scale);
+    idx_type = (TypeInt*)mul->mul_ring(idx_type, scale_type);
+    if (overflow || TypeInt::INT->higher_equal(idx_type)) {
+      // May overflow
+      mul->destruct();
+      if (!overflow) {
+        max_idx_expr = new (C) ConvI2LNode(max_idx_expr);
+        register_new_node(max_idx_expr, ctrl);
+      }
+      overflow = true;
+      con_scale = _igvn.longcon(scale);
+      set_ctrl(con_scale, C->root());
+      max_idx_expr = new (C) MulLNode(max_idx_expr, con_scale);
+    } else {
+      // No overflow possible
+      max_idx_expr = mul;
+    }
     register_new_node(max_idx_expr, ctrl);
-    if (TraceLoopPredicate) predString->print("* %d ", scale);
   }
 
-  if (offset && (!offset->is_Con() || offset->get_int() != 0)){
-    max_idx_expr = new (C) AddINode(max_idx_expr, offset);
+  if (offset && (!offset->is_Con() || con_offset != 0)){
+    if (TraceLoopPredicate) {
+      predString->print(offset->is_Con() ? "+ %d " : "+ offset", con_offset);
+    }
+    // Check if (max_idx_expr + offset) may overflow
+    const TypeInt* offset_type = _igvn.type(offset)->isa_int();
+    jint lo = idx_type->_lo + offset_type->_lo;
+    jint hi = idx_type->_hi + offset_type->_hi;
+    if (overflow || (lo > hi) ||
+        ((idx_type->_lo & offset_type->_lo) < 0 && lo >= 0) ||
+        ((~(idx_type->_hi | offset_type->_hi)) < 0 && hi < 0)) {
+      // May overflow
+      if (!overflow) {
+        max_idx_expr = new (C) ConvI2LNode(max_idx_expr);
+        register_new_node(max_idx_expr, ctrl);
+      }
+      overflow = true;
+      offset = new (C) ConvI2LNode(offset);
+      register_new_node(offset, ctrl);
+      max_idx_expr = new (C) AddLNode(max_idx_expr, offset);
+    } else {
+      // No overflow possible
+      max_idx_expr = new (C) AddINode(max_idx_expr, offset);
+    }
     register_new_node(max_idx_expr, ctrl);
-    if (TraceLoopPredicate)
-      if (offset->is_Con()) predString->print("+ %d ", offset->get_int());
-      else predString->print("+ offset ");
   }
 
-  CmpUNode* cmp = new (C) CmpUNode(max_idx_expr, range);
+  CmpNode* cmp = NULL;
+  if (overflow) {
+    // Integer expressions may overflow, do long comparison
+    range = new (C) ConvI2LNode(range);
+    register_new_node(range, ctrl);
+    if (!Matcher::has_match_rule(Op_CmpUL)) {
+      // We don't support unsigned long comparisons. Set 'max_idx_expr'
+      // to max_julong if < 0 to make the signed comparison fail.
+      ConINode* sign_pos = _igvn.intcon(BitsPerLong - 1);
+      set_ctrl(sign_pos, C->root());
+      Node* sign_bit_mask = new (C) RShiftLNode(max_idx_expr, sign_pos);
+      register_new_node(sign_bit_mask, ctrl);
+      // OR with sign bit to set all bits to 1 if negative (otherwise no change)
+      max_idx_expr = new (C) OrLNode(max_idx_expr, sign_bit_mask);
+      register_new_node(max_idx_expr, ctrl);
+      // AND with 0x7ff... to unset the sign bit
+      ConLNode* remove_sign_mask = _igvn.longcon(max_jlong);
+      set_ctrl(remove_sign_mask, C->root());
+      max_idx_expr = new (C) AndLNode(max_idx_expr, remove_sign_mask);
+      register_new_node(max_idx_expr, ctrl);
+
+      cmp = new (C) CmpLNode(max_idx_expr, range);
+    } else {
+      cmp = new (C) CmpULNode(max_idx_expr, range);
+    }
+  } else {
+    cmp = new (C) CmpUNode(max_idx_expr, range);
+  }
   register_new_node(cmp, ctrl);
   BoolNode* bol = new (C) BoolNode(cmp, BoolTest::lt);
   register_new_node(bol, ctrl);
@@ -837,8 +928,11 @@
       assert(ok, "must be index expression");
 
       Node* init    = cl->init_trip();
-      Node* limit   = cl->limit();
-      Node* stride  = cl->stride();
+      // Limit is not exact.
+      // Calculate exact limit here.
+      // Note, counted loop's test is '<' or '>'.
+      Node* limit   = exact_limit(loop);
+      int  stride   = cl->stride()->get_int();
 
       // Build if's for the upper and lower bound tests.  The
       // lower_bound test will dominate the upper bound test and all
@@ -856,16 +950,18 @@
         assert(invar.is_invariant(offset), "offset must be loop invariant");
         offset = invar.clone(offset, ctrl);
       }
+      // If predicate expressions may overflow in the integer range, longs are used.
+      bool overflow = false;
 
       // Test the lower bound
-      Node*  lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false);
+      Node*  lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false, overflow);
       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);
 
       // Test the upper bound
-      Node* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true);
+      Node* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true, overflow);
       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);
--- a/src/share/vm/opto/loopnode.hpp	Wed May 03 03:39:51 2017 +0100
+++ b/src/share/vm/opto/loopnode.hpp	Thu Mar 30 15:28:33 2017 +0200
@@ -910,8 +910,8 @@
   // Construct a range check for a predicate if
   BoolNode* rc_predicate(IdealLoopTree *loop, Node* ctrl,
                          int scale, Node* offset,
-                         Node* init, Node* limit, Node* stride,
-                         Node* range, bool upper);
+                         Node* init, Node* limit, jint stride,
+                         Node* range, bool upper, bool &overflow);
 
   // Implementation of the loop predication to promote checks outside the loop
   bool loop_predication_impl(IdealLoopTree *loop);
--- a/src/share/vm/opto/output.cpp	Wed May 03 03:39:51 2017 +0100
+++ b/src/share/vm/opto/output.cpp	Thu Mar 30 15:28:33 2017 +0200
@@ -2108,6 +2108,7 @@
     if( last->is_MachIf() && last->in(1) == n &&
         ( op == Op_CmpI ||
           op == Op_CmpU ||
+          op == Op_CmpUL ||
           op == Op_CmpP ||
           op == Op_CmpF ||
           op == Op_CmpD ||
--- a/src/share/vm/opto/subnode.cpp	Wed May 03 03:39:51 2017 +0100
+++ b/src/share/vm/opto/subnode.cpp	Thu Mar 30 15:28:33 2017 +0200
@@ -618,6 +618,60 @@
   return TypeInt::CC;           // else use worst case results
 }
 
+
+// Simplify a CmpUL (compare 2 unsigned longs) node, based on local information.
+// If both inputs are constants, compare them.
+const Type* CmpULNode::sub(const Type* t1, const Type* t2) const {
+  assert(!t1->isa_ptr(), "obsolete usage of CmpUL");
+
+  // comparing two unsigned longs
+  const TypeLong* r0 = t1->is_long();   // Handy access
+  const TypeLong* r1 = t2->is_long();
+
+  // Current installed version
+  // Compare ranges for non-overlap
+  julong lo0 = r0->_lo;
+  julong hi0 = r0->_hi;
+  julong lo1 = r1->_lo;
+  julong hi1 = r1->_hi;
+
+  // If either one has both negative and positive values,
+  // it therefore contains both 0 and -1, and since [0..-1] is the
+  // full unsigned range, the type must act as an unsigned bottom.
+  bool bot0 = ((jlong)(lo0 ^ hi0) < 0);
+  bool bot1 = ((jlong)(lo1 ^ hi1) < 0);
+
+  if (bot0 || bot1) {
+    // All unsigned values are LE -1 and GE 0.
+    if (lo0 == 0 && hi0 == 0) {
+      return TypeInt::CC_LE;            //   0 <= bot
+    } else if ((jlong)lo0 == -1 && (jlong)hi0 == -1) {
+      return TypeInt::CC_GE;            // -1 >= bot
+    } else if (lo1 == 0 && hi1 == 0) {
+      return TypeInt::CC_GE;            // bot >= 0
+    } else if ((jlong)lo1 == -1 && (jlong)hi1 == -1) {
+      return TypeInt::CC_LE;            // bot <= -1
+    }
+  } else {
+    // We can use ranges of the form [lo..hi] if signs are the same.
+    assert(lo0 <= hi0 && lo1 <= hi1, "unsigned ranges are valid");
+    // results are reversed, '-' > '+' for unsigned compare
+    if (hi0 < lo1) {
+      return TypeInt::CC_LT;            // smaller
+    } else if (lo0 > hi1) {
+      return TypeInt::CC_GT;            // greater
+    } else if (hi0 == lo1 && lo0 == hi1) {
+      return TypeInt::CC_EQ;            // Equal results
+    } else if (lo0 >= hi1) {
+      return TypeInt::CC_GE;
+    } else if (hi0 <= lo1) {
+      return TypeInt::CC_LE;
+    }
+  }
+
+  return TypeInt::CC;                   // else use worst case results
+}
+
 //=============================================================================
 //------------------------------sub--------------------------------------------
 // Simplify an CmpP (compare 2 pointers) node, based on local information.
--- a/src/share/vm/opto/subnode.hpp	Wed May 03 03:39:51 2017 +0100
+++ b/src/share/vm/opto/subnode.hpp	Thu Mar 30 15:28:33 2017 +0200
@@ -190,6 +190,15 @@
   virtual const Type *sub( const Type *, const Type * ) const;
 };
 
+//------------------------------CmpULNode---------------------------------------
+// Compare 2 unsigned long values, returning condition codes (-1, 0 or 1).
+class CmpULNode : public CmpNode {
+public:
+  CmpULNode(Node* in1, Node* in2) : CmpNode(in1, in2) { }
+  virtual int Opcode() const;
+  virtual const Type* sub(const Type*, const Type*) const;
+};
+
 //------------------------------CmpL3Node--------------------------------------
 // Compare 2 long values, returning integer value (-1, 0 or 1).
 class CmpL3Node : public CmpLNode {
--- a/src/share/vm/runtime/vmStructs.cpp	Wed May 03 03:39:51 2017 +0100
+++ b/src/share/vm/runtime/vmStructs.cpp	Thu Mar 30 15:28:33 2017 +0200
@@ -1930,6 +1930,7 @@
   declare_c2_type(CmpPNode, CmpNode)                                      \
   declare_c2_type(CmpNNode, CmpNode)                                      \
   declare_c2_type(CmpLNode, CmpNode)                                      \
+  declare_c2_type(CmpULNode, CmpNode)                                     \
   declare_c2_type(CmpL3Node, CmpLNode)                                    \
   declare_c2_type(CmpFNode, CmpNode)                                      \
   declare_c2_type(CmpF3Node, CmpFNode)                                    \