--- a/hotspot/src/cpu/arm/vm/arm.ad Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/cpu/arm/vm/arm.ad Thu Jul 13 21:32:55 2017 -0700
@@ -2695,6 +2695,30 @@
format %{ "apsr_L_LEGT" %}
interface(REG_INTER);
%}
+
+operand flagsRegUL_LTGE() %{
+ constraint(ALLOC_IN_RC(int_flags));
+ match(RegFlags);
+
+ format %{ "apsr_UL_LTGE" %}
+ interface(REG_INTER);
+%}
+
+operand flagsRegUL_EQNE() %{
+ constraint(ALLOC_IN_RC(int_flags));
+ match(RegFlags);
+
+ format %{ "apsr_UL_EQNE" %}
+ interface(REG_INTER);
+%}
+
+operand flagsRegUL_LEGT() %{
+ constraint(ALLOC_IN_RC(int_flags));
+ match(RegFlags);
+
+ format %{ "apsr_UL_LEGT" %}
+ interface(REG_INTER);
+%}
#endif
// Condition Code Register, floating comparisons, unordered same as "less".
@@ -3249,6 +3273,39 @@
%}
%}
+operand cmpOpUL() %{
+ match(Bool);
+
+ format %{ "UL" %}
+ interface(COND_INTER) %{
+ equal(0x0);
+ not_equal(0x1);
+ less(0x3);
+ greater_equal(0x2);
+ less_equal(0x9);
+ greater(0x8);
+ overflow(0x0); // unsupported/unimplemented
+ no_overflow(0x0); // unsupported/unimplemented
+ %}
+%}
+
+operand cmpOpUL_commute() %{
+ match(Bool);
+
+ format %{ "UL" %}
+ interface(COND_INTER) %{
+ equal(0x0);
+ not_equal(0x1);
+ less(0x8);
+ greater_equal(0x9);
+ less_equal(0x2);
+ greater(0x3);
+ overflow(0x0); // unsupported/unimplemented
+ no_overflow(0x0); // unsupported/unimplemented
+ %}
+%}
+
+
//----------OPERAND CLASSES----------------------------------------------------
// Operand Classes are groups of operands that are used to simplify
// instruction definitions by not requiring the AD writer to specify separate
@@ -10467,6 +10524,17 @@
%}
ins_pipe(ialu_cconly_reg_reg);
%}
+
+instruct compUL_iReg(flagsRegU xcc, iRegL op1, iRegL op2) %{
+ match(Set xcc (CmpUL op1 op2));
+
+ size(4);
+ format %{ "CMP $op1,$op2\t! unsigned long" %}
+ ins_encode %{
+ __ cmp($op1$$Register, $op2$$Register);
+ %}
+ ins_pipe(ialu_cconly_reg_reg);
+%}
#else
instruct compL_reg_reg_LTGE(flagsRegL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp) %{
match(Set xcc (CmpL op1 op2));
@@ -10481,6 +10549,20 @@
%}
ins_pipe(ialu_cconly_reg_reg);
%}
+
+instruct compUL_reg_reg_LTGE(flagsRegUL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp) %{
+ match(Set xcc (CmpUL op1 op2));
+ effect(DEF xcc, USE op1, USE op2, TEMP tmp);
+
+ size(8);
+ format %{ "SUBS $tmp,$op1.low,$op2.low\t\t! unsigned long\n\t"
+ "SBCS $tmp,$op1.hi,$op2.hi" %}
+ ins_encode %{
+ __ subs($tmp$$Register, $op1$$Register, $op2$$Register);
+ __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), $op2$$Register->successor());
+ %}
+ ins_pipe(ialu_cconly_reg_reg);
+%}
#endif
#ifdef AARCH64
@@ -10496,6 +10578,19 @@
ins_pipe(ialu_cconly_reg_imm);
%}
+
+instruct compUL_reg_con(flagsRegU xcc, iRegL op1, aimmL con) %{
+ match(Set xcc (CmpUL op1 con));
+ effect(DEF xcc, USE op1, USE con);
+
+ size(8);
+ format %{ "CMP $op1,$con\t\t! unsigned long" %}
+ ins_encode %{
+ __ cmp($op1$$Register, $con$$constant);
+ %}
+
+ ins_pipe(ialu_cconly_reg_imm);
+%}
#else
instruct compL_reg_reg_EQNE(flagsRegL_EQNE xcc, iRegL op1, iRegL op2) %{
match(Set xcc (CmpL op1 op2));
@@ -10575,6 +10670,85 @@
ins_pipe(ialu_cconly_reg_reg);
%}
+
+instruct compUL_reg_reg_EQNE(flagsRegUL_EQNE xcc, iRegL op1, iRegL op2) %{
+ match(Set xcc (CmpUL op1 op2));
+ effect(DEF xcc, USE op1, USE op2);
+
+ size(8);
+ format %{ "TEQ $op1.hi,$op2.hi\t\t! unsigned long\n\t"
+ "TEQ.eq $op1.lo,$op2.lo" %}
+ ins_encode %{
+ __ teq($op1$$Register->successor(), $op2$$Register->successor());
+ __ teq($op1$$Register, $op2$$Register, eq);
+ %}
+ ins_pipe(ialu_cconly_reg_reg);
+%}
+
+instruct compUL_reg_reg_LEGT(flagsRegUL_LEGT xcc, iRegL op1, iRegL op2, iRegL tmp) %{
+ match(Set xcc (CmpUL op1 op2));
+ effect(DEF xcc, USE op1, USE op2, TEMP tmp);
+
+ size(8);
+ format %{ "SUBS $tmp,$op2.low,$op1.low\t\t! unsigned long\n\t"
+ "SBCS $tmp,$op2.hi,$op1.hi" %}
+ ins_encode %{
+ __ subs($tmp$$Register, $op2$$Register, $op1$$Register);
+ __ sbcs($tmp$$Register->successor(), $op2$$Register->successor(), $op1$$Register->successor());
+ %}
+ ins_pipe(ialu_cconly_reg_reg);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct compUL_reg_con_LTGE(flagsRegUL_LTGE xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
+ match(Set xcc (CmpUL op1 con));
+ effect(DEF xcc, USE op1, USE con, TEMP tmp);
+
+ size(8);
+ format %{ "SUBS $tmp,$op1.low,$con\t\t! unsigned long\n\t"
+ "SBCS $tmp,$op1.hi,0" %}
+ ins_encode %{
+ __ subs($tmp$$Register, $op1$$Register, $con$$constant);
+ __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
+ %}
+
+ ins_pipe(ialu_cconly_reg_reg);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct compUL_reg_con_EQNE(flagsRegUL_EQNE xcc, iRegL op1, immLlowRot con) %{
+ match(Set xcc (CmpUL op1 con));
+ effect(DEF xcc, USE op1, USE con);
+
+ size(8);
+ format %{ "TEQ $op1.hi,0\t\t! unsigned long\n\t"
+ "TEQ.eq $op1.lo,$con" %}
+ ins_encode %{
+ __ teq($op1$$Register->successor(), 0);
+ __ teq($op1$$Register, $con$$constant, eq);
+ %}
+
+ ins_pipe(ialu_cconly_reg_reg);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct compUL_reg_con_LEGT(flagsRegUL_LEGT xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
+ match(Set xcc (CmpUL op1 con));
+ effect(DEF xcc, USE op1, USE con, TEMP tmp);
+
+ size(8);
+ format %{ "RSBS $tmp,$op1.low,$con\t\t! unsigned long\n\t"
+ "RSCS $tmp,$op1.hi,0" %}
+ ins_encode %{
+ __ rsbs($tmp$$Register, $op1$$Register, $con$$constant);
+ __ rscs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
+ %}
+
+ ins_pipe(ialu_cconly_reg_reg);
+%}
#endif
/* instruct testL_reg_reg(flagsRegL xcc, iRegL op1, iRegL op2, immL0 zero) %{ */
@@ -11126,6 +11300,48 @@
%}
ins_pipe(br_cc);
%}
+
+instruct branchConUL_LTGE(cmpOpUL cmp, flagsRegUL_LTGE xcc, label labl) %{
+ match(If cmp xcc);
+ effect(USE labl);
+ predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+
+ size(4);
+ ins_cost(BRANCH_COST);
+ format %{ "B$cmp $xcc,$labl" %}
+ ins_encode %{
+ __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+ %}
+ ins_pipe(br_cc);
+%}
+
+instruct branchConUL_EQNE(cmpOpUL cmp, flagsRegUL_EQNE xcc, label labl) %{
+ match(If cmp xcc);
+ effect(USE labl);
+ predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);
+
+ size(4);
+ ins_cost(BRANCH_COST);
+ format %{ "B$cmp $xcc,$labl" %}
+ ins_encode %{
+ __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+ %}
+ ins_pipe(br_cc);
+%}
+
+instruct branchConUL_LEGT(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, label labl) %{
+ match(If cmp xcc);
+ effect(USE labl);
+ predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le);
+
+ size(4);
+ ins_cost(BRANCH_COST);
+ format %{ "B$cmp $xcc,$labl" %}
+ ins_encode %{
+ __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+ %}
+ ins_pipe(br_cc);
+%}
#endif
instruct branchLoopEnd(cmpOp cmp, flagsReg icc, label labl) %{
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad Thu Jul 13 21:32:55 2017 -0700
@@ -11048,6 +11048,29 @@
ins_pipe(pipe_class_compare);
%}
+// Added CmpUL for LoopPredicate.
+instruct cmpUL_reg_reg(flagsReg crx, iRegLsrc src1, iRegLsrc src2) %{
+ match(Set crx (CmpUL src1 src2));
+ format %{ "CMPLD $crx, $src1, $src2" %}
+ size(4);
+ ins_encode %{
+ // TODO: PPC port $archOpcode(ppc64Opcode_cmpl);
+ __ cmpld($crx$$CondRegister, $src1$$Register, $src2$$Register);
+ %}
+ ins_pipe(pipe_class_compare);
+%}
+
+instruct cmpUL_reg_imm16(flagsReg crx, iRegLsrc src1, uimmL16 src2) %{
+ match(Set crx (CmpUL src1 src2));
+ format %{ "CMPLDI $crx, $src1, $src2" %}
+ size(4);
+ ins_encode %{
+ // TODO: PPC port $archOpcode(ppc64Opcode_cmpli);
+ __ cmpldi($crx$$CondRegister, $src1$$Register, $src2$$constant);
+ %}
+ ins_pipe(pipe_class_compare);
+%}
+
instruct testL_reg_reg(flagsRegCR0 cr0, iRegLsrc src1, iRegLsrc src2, immL_0 zero) %{
match(Set cr0 (CmpL (AndL src1 src2) zero));
// r0 is killed
--- a/hotspot/src/cpu/s390/vm/s390.ad Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/cpu/s390/vm/s390.ad Thu Jul 13 21:32:55 2017 -0700
@@ -8475,6 +8475,24 @@
%}
// LONG unsigned
+// Added CmpUL for LoopPredicate.
+instruct compUL_reg_reg(flagsReg cr, iRegL op1, iRegL op2) %{
+ match(Set cr (CmpUL op1 op2));
+ size(4);
+ format %{ "CLGR $op1,$op2\t # long" %}
+ opcode(CLGR_ZOPC);
+ ins_encode(z_rreform(op1, op2));
+ ins_pipe(pipe_class_dummy);
+%}
+
+instruct compUL_reg_imm32(flagsReg cr, iRegL op1, uimmL32 con) %{
+ match(Set cr (CmpUL op1 con));
+ size(6);
+ format %{ "CLGFI $op1,$con" %}
+ opcode(CLGFI_ZOPC);
+ ins_encode(z_rilform_unsigned(op1, con));
+ ins_pipe(pipe_class_dummy);
+%}
// PTR unsigned
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Thu Jul 13 21:32:55 2017 -0700
@@ -3403,6 +3403,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);
+%}
+
// Integer Immediate non-negative
operand immU31()
%{
@@ -3936,6 +3946,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));
@@ -8797,6 +8816,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 );
@@ -8883,6 +8913,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));
@@ -9256,6 +9297,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);
@@ -9484,6 +9563,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);
@@ -9722,6 +9837,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/hotspot/src/cpu/x86/vm/x86_32.ad Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Thu Jul 13 21:32:55 2017 -0700
@@ -4030,6 +4030,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 );
@@ -4588,7 +4608,7 @@
%}
%}
-// Comparision Code used in long compares
+// Comparison Code used in long compares
operand cmpOp_commute() %{
match(Bool);
@@ -4605,6 +4625,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
@@ -12639,6 +12676,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)));
@@ -12767,6 +12842,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)));
@@ -12900,6 +13010,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/hotspot/src/cpu/x86/vm/x86_64.ad Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Thu Jul 13 21:32:55 2017 -0700
@@ -11518,6 +11518,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/hotspot/src/share/vm/adlc/archDesc.cpp Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/share/vm/adlc/archDesc.cpp Thu Jul 13 21:32:55 2017 -0700
@@ -1166,6 +1166,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/hotspot/src/share/vm/opto/classes.hpp Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/share/vm/opto/classes.hpp Thu Jul 13 21:32:55 2017 -0700
@@ -81,6 +81,7 @@
macro(CmpLTMask)
macro(CmpP)
macro(CmpU)
+macro(CmpUL)
macro(CompareAndSwapB)
macro(CompareAndSwapS)
macro(CompareAndSwapI)
--- a/hotspot/src/share/vm/opto/loopPredicate.cpp Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/share/vm/opto/loopPredicate.cpp Thu Jul 13 21:32:55 2017 -0700
@@ -29,6 +29,7 @@
#include "opto/connode.hpp"
#include "opto/convertnode.hpp"
#include "opto/loopnode.hpp"
+#include "opto/matcher.hpp"
#include "opto/mulnode.hpp"
#include "opto/opaquenode.hpp"
#include "opto/rootnode.hpp"
@@ -629,45 +630,138 @@
// 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) {
- // Limit is not exact.
- // Calculate exact limit here.
- // Note, counted loop's test is '<' or '>'.
- limit = exact_limit(loop);
- max_idx_expr = new SubINode(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;
+ if ((stride > 0 && (java_subtract(limit_lo, stride) < limit_lo)) ||
+ (stride < 0 && (java_subtract(limit_hi, stride) > limit_hi))) {
+ // No overflow possible
+ ConINode* con_stride = _igvn.intcon(stride);
+ set_ctrl(con_stride, C->root());
+ max_idx_expr = new SubINode(limit, con_stride);
+ idx_type = TypeInt::make(limit_lo - stride, limit_hi - stride, limit_type->_widen);
+ } else {
+ // May overflow
+ overflow = true;
+ limit = new ConvI2LNode(limit);
+ register_new_node(limit, ctrl);
+ ConLNode* con_stride = _igvn.longcon(stride);
+ set_ctrl(con_stride, C->root());
+ max_idx_expr = new SubLNode(limit, con_stride);
+ }
register_new_node(max_idx_expr, ctrl);
- if (TraceLoopPredicate) predString->print("(limit - stride) ");
} 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);
set_ctrl(con_scale, C->root());
- max_idx_expr = new MulINode(max_idx_expr, con_scale);
+ if (TraceLoopPredicate) {
+ predString->print("* %d ", scale);
+ }
+ // Check if (scale * max_idx_expr) may overflow
+ const TypeInt* scale_type = TypeInt::make(scale);
+ MulINode* mul = new 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 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 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 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 = java_add(idx_type->_lo, offset_type->_lo);
+ jint hi = java_add(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 ConvI2LNode(max_idx_expr);
+ register_new_node(max_idx_expr, ctrl);
+ }
+ overflow = true;
+ offset = new ConvI2LNode(offset);
+ register_new_node(offset, ctrl);
+ max_idx_expr = new AddLNode(max_idx_expr, offset);
+ } else {
+ // No overflow possible
+ max_idx_expr = new 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 CmpUNode(max_idx_expr, range);
+ CmpNode* cmp = NULL;
+ if (overflow) {
+ // Integer expressions may overflow, do long comparison
+ range = new 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 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 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 AndLNode(max_idx_expr, remove_sign_mask);
+ register_new_node(max_idx_expr, ctrl);
+
+ cmp = new CmpLNode(max_idx_expr, range);
+ } else {
+ cmp = new CmpULNode(max_idx_expr, range);
+ }
+ } else {
+ cmp = new CmpUNode(max_idx_expr, range);
+ }
register_new_node(cmp, ctrl);
BoolNode* bol = new BoolNode(cmp, BoolTest::lt);
register_new_node(bol, ctrl);
@@ -814,28 +908,30 @@
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
// 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, NULL, Deoptimization::Reason_predicate, iff->Opcode());
- ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate, iff->Opcode());
- 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.
+ Node *ctrl = predicate_proj->in(0)->as_If()->in(0);
rng = invar.clone(rng, ctrl);
if (offset && offset != zero) {
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
- BoolNode* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false);
+ BoolNode* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false, overflow);
// Negate test if necessary
bool negated = false;
if (proj->_con != predicate_proj->_con) {
@@ -843,19 +939,22 @@
register_new_node(lower_bound_bol, ctrl);
negated = true;
}
+ ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate, overflow ? Op_If : iff->Opcode());
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: %s %d ", negated ? " negated" : "", lower_bound_iff->_idx);
// Test the upper bound
- BoolNode* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true);
+ BoolNode* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true, overflow);
negated = false;
if (proj->_con != predicate_proj->_con) {
upper_bound_bol = new BoolNode(upper_bound_bol->in(1), upper_bound_bol->_test.negate());
register_new_node(upper_bound_bol, ctrl);
negated = true;
}
+ ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate, overflow ? Op_If : iff->Opcode());
+ assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate");
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/hotspot/src/share/vm/opto/loopnode.hpp Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/share/vm/opto/loopnode.hpp Thu Jul 13 21:32:55 2017 -0700
@@ -983,8 +983,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/hotspot/src/share/vm/opto/output.cpp Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/share/vm/opto/output.cpp Thu Jul 13 21:32:55 2017 -0700
@@ -1982,6 +1982,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/hotspot/src/share/vm/opto/subnode.cpp Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/share/vm/opto/subnode.cpp Thu Jul 13 21:32:55 2017 -0700
@@ -738,6 +738,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/hotspot/src/share/vm/opto/subnode.hpp Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/share/vm/opto/subnode.hpp Thu Jul 13 21:32:55 2017 -0700
@@ -198,6 +198,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/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Jul 13 17:32:49 2017 +0000
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Jul 13 21:32:55 2017 -0700
@@ -2008,6 +2008,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) \