提交 ab0a9776 编写于 作者: A asaha

Merge

...@@ -974,3 +974,6 @@ e318654a4fa352a06935dd56eebf88ae387b31f9 jdk8u131-b32 ...@@ -974,3 +974,6 @@ e318654a4fa352a06935dd56eebf88ae387b31f9 jdk8u131-b32
62b0b4a31b44e8b159bff106c04ecfabc9d78d9b jdk8u141-b04 62b0b4a31b44e8b159bff106c04ecfabc9d78d9b jdk8u141-b04
53a48dc8e4418ed422c69361193add798cb4ed55 jdk8u141-b05 53a48dc8e4418ed422c69361193add798cb4ed55 jdk8u141-b05
4b7067065b0ad08c41a6334b44877319cbb2de54 jdk8u141-b06 4b7067065b0ad08c41a6334b44877319cbb2de54 jdk8u141-b06
42f196fd7c589e439c4e6d86b7d845ff024cfe45 jdk8u141-b07
37ba410ffd431c76961255b87398f6ace7b6794f jdk8u141-b08
b23c5879a33cf2c2e7c3e2cdfb0285bb7e64198e jdk8u141-b09
...@@ -3458,6 +3458,16 @@ operand immI5() %{ ...@@ -3458,6 +3458,16 @@ operand immI5() %{
interface(CONST_INTER); 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 // Int Immediate non-negative
operand immU31() operand immU31()
%{ %{
...@@ -4083,6 +4093,15 @@ operand flagsRegL() %{ ...@@ -4083,6 +4093,15 @@ operand flagsRegL() %{
interface(REG_INTER); 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". // Condition Code Register, floating comparisons, unordered same as "less".
operand flagsRegF() %{ operand flagsRegF() %{
constraint(ALLOC_IN_RC(float_flags)); constraint(ALLOC_IN_RC(float_flags));
...@@ -8962,6 +8981,17 @@ instruct compU_iReg(flagsRegU icc, iRegI op1, iRegI op2) %{ ...@@ -8962,6 +8981,17 @@ instruct compU_iReg(flagsRegU icc, iRegI op1, iRegI op2) %{
ins_pipe(ialu_cconly_reg_reg); 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) %{ instruct compI_iReg_imm13(flagsReg icc, iRegI op1, immI13 op2) %{
match(Set icc (CmpI op1 op2)); match(Set icc (CmpI op1 op2));
effect( DEF icc, USE op1 ); effect( DEF icc, USE op1 );
...@@ -9048,6 +9078,17 @@ instruct compU_iReg_imm13(flagsRegU icc, iRegI op1, immU12 op2 ) %{ ...@@ -9048,6 +9078,17 @@ instruct compU_iReg_imm13(flagsRegU icc, iRegI op1, immU12 op2 ) %{
ins_pipe(ialu_cconly_reg_imm); 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 // Compare Pointers
instruct compP_iRegP(flagsRegP pcc, iRegP op1, iRegP op2 ) %{ instruct compP_iRegP(flagsRegP pcc, iRegP op1, iRegP op2 ) %{
match(Set pcc (CmpP op1 op2)); match(Set pcc (CmpP op1 op2));
...@@ -9421,6 +9462,44 @@ instruct cmpU_imm_branch(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU ...@@ -9421,6 +9462,44 @@ instruct cmpU_imm_branch(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU
ins_pipe(cmp_br_reg_imm); 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) %{ instruct cmpL_reg_branch(cmpOp cmp, iRegL op1, iRegL op2, label labl, flagsRegL xcc) %{
match(If cmp (CmpL op1 op2)); match(If cmp (CmpL op1 op2));
effect(USE labl, KILL xcc); effect(USE labl, KILL xcc);
...@@ -9649,6 +9728,42 @@ instruct cmpU_imm_branch_short(cmpOpU cmp, iRegI op1, immI5 op2, label labl, fla ...@@ -9649,6 +9728,42 @@ instruct cmpU_imm_branch_short(cmpOpU cmp, iRegI op1, immI5 op2, label labl, fla
ins_pipe(cbcond_reg_imm); 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) %{ instruct cmpL_reg_branch_short(cmpOp cmp, iRegL op1, iRegL op2, label labl, flagsRegL xcc) %{
match(If cmp (CmpL op1 op2)); match(If cmp (CmpL op1 op2));
predicate(UseCBCond); predicate(UseCBCond);
...@@ -9887,6 +10002,25 @@ instruct branchCon_long(cmpOp cmp, flagsRegL xcc, label labl) %{ ...@@ -9887,6 +10002,25 @@ instruct branchCon_long(cmpOp cmp, flagsRegL xcc, label labl) %{
ins_pipe(br_cc); 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. // Manifest a CmpL3 result in an integer register. Very painful.
// This is the test to avoid. // This is the test to avoid.
instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{ instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{
......
...@@ -3948,6 +3948,26 @@ operand flagsReg_long_LEGT() %{ ...@@ -3948,6 +3948,26 @@ operand flagsReg_long_LEGT() %{
interface(REG_INTER); 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 // Float register operands
operand regDPR() %{ operand regDPR() %{
predicate( UseSSE < 2 ); predicate( UseSSE < 2 );
...@@ -4473,7 +4493,7 @@ operand cmpOp_fcmov() %{ ...@@ -4473,7 +4493,7 @@ operand cmpOp_fcmov() %{
%} %}
%} %}
// Comparision Code used in long compares // Comparison Code used in long compares
operand cmpOp_commute() %{ operand cmpOp_commute() %{
match(Bool); match(Bool);
...@@ -4490,6 +4510,23 @@ operand cmpOp_commute() %{ ...@@ -4490,6 +4510,23 @@ operand cmpOp_commute() %{
%} %}
%} %}
// 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----------------------------------------------------
// Operand Classes are groups of operands that are used as to simplify // Operand Classes are groups of operands that are used as to simplify
// instruction definitions by not requiring the AD writer to specify separate // instruction definitions by not requiring the AD writer to specify separate
...@@ -12382,6 +12419,44 @@ instruct cmpL_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, label labl) %{ ...@@ -12382,6 +12419,44 @@ instruct cmpL_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, label labl) %{
%} %}
%} %}
//======
// 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. // Compare 2 longs and CMOVE longs.
instruct cmovLL_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, eRegL dst, eRegL src) %{ instruct cmovLL_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, eRegL dst, eRegL src) %{
match(Set dst (CMoveL (Binary cmp flags) (Binary dst src))); match(Set dst (CMoveL (Binary cmp flags) (Binary dst src)));
...@@ -12510,6 +12585,41 @@ instruct cmpL_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, label labl) %{ ...@@ -12510,6 +12585,41 @@ instruct cmpL_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, label labl) %{
%} %}
%} %}
//======
// 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. // Compare 2 longs and CMOVE longs.
instruct cmovLL_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, eRegL dst, eRegL src) %{ instruct cmovLL_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, eRegL dst, eRegL src) %{
match(Set dst (CMoveL (Binary cmp flags) (Binary dst src))); match(Set dst (CMoveL (Binary cmp flags) (Binary dst src)));
...@@ -12643,6 +12753,46 @@ instruct cmpL_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, label labl) %{ ...@@ -12643,6 +12753,46 @@ instruct cmpL_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, label labl) %{
%} %}
%} %}
//======
// 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. // Compare 2 longs and CMOVE longs.
instruct cmovLL_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, eRegL dst, eRegL src) %{ 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))); match(Set dst (CMoveL (Binary cmp flags) (Binary dst src)));
......
...@@ -11068,6 +11068,48 @@ instruct cmpL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags) ...@@ -11068,6 +11068,48 @@ instruct cmpL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags)
ins_pipe(pipe_slow); 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-------------------------------------------------------- //----------Max and Min--------------------------------------------------------
// Min Instructions // Min Instructions
......
...@@ -1189,6 +1189,7 @@ void ArchDesc::buildMustCloneMap(FILE *fp_hpp, FILE *fp_cpp) { ...@@ -1189,6 +1189,7 @@ void ArchDesc::buildMustCloneMap(FILE *fp_hpp, FILE *fp_cpp) {
|| strcmp(idealName,"CmpP") == 0 || strcmp(idealName,"CmpP") == 0
|| strcmp(idealName,"CmpN") == 0 || strcmp(idealName,"CmpN") == 0
|| strcmp(idealName,"CmpL") == 0 || strcmp(idealName,"CmpL") == 0
|| strcmp(idealName,"CmpUL") == 0
|| strcmp(idealName,"CmpD") == 0 || strcmp(idealName,"CmpD") == 0
|| strcmp(idealName,"CmpF") == 0 || strcmp(idealName,"CmpF") == 0
|| strcmp(idealName,"FastLock") == 0 || strcmp(idealName,"FastLock") == 0
......
...@@ -449,8 +449,8 @@ public: ...@@ -449,8 +449,8 @@ public:
void delete_replaced_nodes() { void delete_replaced_nodes() {
_replaced_nodes.reset(); _replaced_nodes.reset();
} }
void apply_replaced_nodes() { void apply_replaced_nodes(uint idx) {
_replaced_nodes.apply(this); _replaced_nodes.apply(this, idx);
} }
void merge_replaced_nodes_with(SafePointNode* sfpt) { void merge_replaced_nodes_with(SafePointNode* sfpt) {
_replaced_nodes.merge_with(sfpt->_replaced_nodes); _replaced_nodes.merge_with(sfpt->_replaced_nodes);
......
...@@ -79,6 +79,7 @@ macro(CmpL3) ...@@ -79,6 +79,7 @@ macro(CmpL3)
macro(CmpLTMask) macro(CmpLTMask)
macro(CmpP) macro(CmpP)
macro(CmpU) macro(CmpU)
macro(CmpUL)
macro(CompareAndSwapI) macro(CompareAndSwapI)
macro(CompareAndSwapL) macro(CompareAndSwapL)
macro(CompareAndSwapP) macro(CompareAndSwapP)
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "opto/callnode.hpp" #include "opto/callnode.hpp"
#include "opto/connode.hpp" #include "opto/connode.hpp"
#include "opto/loopnode.hpp" #include "opto/loopnode.hpp"
#include "opto/matcher.hpp"
#include "opto/mulnode.hpp" #include "opto/mulnode.hpp"
#include "opto/rootnode.hpp" #include "opto/rootnode.hpp"
#include "opto/subnode.hpp" #include "opto/subnode.hpp"
...@@ -593,50 +594,140 @@ bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invari ...@@ -593,50 +594,140 @@ bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invari
// max(scale*i + offset) = scale*init + offset // max(scale*i + offset) = scale*init + offset
BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl, BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl,
int scale, Node* offset, int scale, Node* offset,
Node* init, Node* limit, Node* stride, Node* init, Node* limit, jint stride,
Node* range, bool upper) { 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; stringStream* predString = NULL;
if (TraceLoopPredicate) { if (TraceLoopPredicate) {
predString = new stringStream(); predString = new stringStream();
predString->print("rc_predicate "); predString->print("rc_predicate ");
} }
Node* max_idx_expr = init; overflow = false;
int stride_con = stride->get_int(); Node* max_idx_expr = NULL;
if ((stride_con > 0) == (scale > 0) == upper) { const TypeInt* idx_type = TypeInt::INT;
if (LoopLimitCheck) { if ((stride > 0) == (scale > 0) == upper) {
// With LoopLimitCheck limit is not exact. if (TraceLoopPredicate) {
// Calculate exact limit here. predString->print(limit->is_Con() ? "(%d " : "(limit ", con_limit);
// Note, counted loop's test is '<' or '>'. predString->print("- %d) ", stride);
limit = exact_limit(loop); }
max_idx_expr = new (C) SubINode(limit, stride); // Check if (limit - stride) may overflow
register_new_node(max_idx_expr, ctrl); const TypeInt* limit_type = _igvn.type(limit)->isa_int();
if (TraceLoopPredicate) predString->print("(limit - stride) "); 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 { } else {
max_idx_expr = new (C) SubINode(limit, stride); // May overflow
register_new_node(max_idx_expr, ctrl); overflow = true;
if (TraceLoopPredicate) predString->print("(limit - stride) "); 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 { } 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) { if (scale != 1) {
ConNode* con_scale = _igvn.intcon(scale); 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); register_new_node(max_idx_expr, ctrl);
if (TraceLoopPredicate) predString->print("* %d ", scale);
} }
if (offset && (!offset->is_Con() || offset->get_int() != 0)){ 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); max_idx_expr = new (C) AddINode(max_idx_expr, offset);
}
register_new_node(max_idx_expr, ctrl); 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); register_new_node(cmp, ctrl);
BoolNode* bol = new (C) BoolNode(cmp, BoolTest::lt); BoolNode* bol = new (C) BoolNode(cmp, BoolTest::lt);
register_new_node(bol, ctrl); register_new_node(bol, ctrl);
...@@ -786,8 +877,11 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { ...@@ -786,8 +877,11 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
assert(ok, "must be index expression"); assert(ok, "must be index expression");
Node* init = cl->init_trip(); Node* init = cl->init_trip();
Node* limit = cl->limit(); // Limit is not exact.
Node* stride = cl->stride(); // 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 // Build if's for the upper and lower bound tests. The
// lower_bound test will dominate the upper bound test and all // lower_bound test will dominate the upper bound test and all
...@@ -805,16 +899,18 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { ...@@ -805,16 +899,18 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
assert(invar.is_invariant(offset), "offset must be loop invariant"); assert(invar.is_invariant(offset), "offset must be loop invariant");
offset = invar.clone(offset, ctrl); offset = invar.clone(offset, ctrl);
} }
// If predicate expressions may overflow in the integer range, longs are used.
bool overflow = false;
// Test the lower bound // 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(); IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If();
_igvn.hash_delete(lower_bound_iff); _igvn.hash_delete(lower_bound_iff);
lower_bound_iff->set_req(1, lower_bound_bol); lower_bound_iff->set_req(1, lower_bound_bol);
if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx); if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx);
// Test the upper bound // 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(); IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If();
_igvn.hash_delete(upper_bound_iff); _igvn.hash_delete(upper_bound_iff);
upper_bound_iff->set_req(1, upper_bound_bol); upper_bound_iff->set_req(1, upper_bound_bol);
......
...@@ -905,8 +905,8 @@ public: ...@@ -905,8 +905,8 @@ public:
// Construct a range check for a predicate if // Construct a range check for a predicate if
BoolNode* rc_predicate(IdealLoopTree *loop, Node* ctrl, BoolNode* rc_predicate(IdealLoopTree *loop, Node* ctrl,
int scale, Node* offset, int scale, Node* offset,
Node* init, Node* limit, Node* stride, Node* init, Node* limit, jint stride,
Node* range, bool upper); Node* range, bool upper, bool &overflow);
// Implementation of the loop predication to promote checks outside the loop // Implementation of the loop predication to promote checks outside the loop
bool loop_predication_impl(IdealLoopTree *loop); bool loop_predication_impl(IdealLoopTree *loop);
......
...@@ -2095,6 +2095,7 @@ void Scheduling::AddNodeToAvailableList(Node *n) { ...@@ -2095,6 +2095,7 @@ void Scheduling::AddNodeToAvailableList(Node *n) {
if( last->is_MachIf() && last->in(1) == n && if( last->is_MachIf() && last->in(1) == n &&
( op == Op_CmpI || ( op == Op_CmpI ||
op == Op_CmpU || op == Op_CmpU ||
op == Op_CmpUL ||
op == Op_CmpP || op == Op_CmpP ||
op == Op_CmpF || op == Op_CmpF ||
op == Op_CmpD || op == Op_CmpD ||
......
...@@ -1048,7 +1048,7 @@ void Parse::do_exits() { ...@@ -1048,7 +1048,7 @@ void Parse::do_exits() {
kit.make_dtrace_method_exit(method()); kit.make_dtrace_method_exit(method());
} }
if (_replaced_nodes_for_exceptions) { if (_replaced_nodes_for_exceptions) {
kit.map()->apply_replaced_nodes(); kit.map()->apply_replaced_nodes(_new_idx);
} }
// Done with exception-path processing. // Done with exception-path processing.
ex_map = kit.make_exception_state(ex_oop); ex_map = kit.make_exception_state(ex_oop);
...@@ -1069,7 +1069,7 @@ void Parse::do_exits() { ...@@ -1069,7 +1069,7 @@ void Parse::do_exits() {
_exits.add_exception_state(ex_map); _exits.add_exception_state(ex_map);
} }
} }
_exits.map()->apply_replaced_nodes(); _exits.map()->apply_replaced_nodes(_new_idx);
} }
//-----------------------------create_entry_map------------------------------- //-----------------------------create_entry_map-------------------------------
......
...@@ -91,14 +91,18 @@ void ReplacedNodes::reset() { ...@@ -91,14 +91,18 @@ void ReplacedNodes::reset() {
} }
// Perfom node replacement (used when returning to caller) // Perfom node replacement (used when returning to caller)
void ReplacedNodes::apply(Node* n) { void ReplacedNodes::apply(Node* n, uint idx) {
if (is_empty()) { if (is_empty()) {
return; return;
} }
for (int i = 0; i < _replaced_nodes->length(); i++) { for (int i = 0; i < _replaced_nodes->length(); i++) {
ReplacedNode replaced = _replaced_nodes->at(i); ReplacedNode replaced = _replaced_nodes->at(i);
// Only apply if improved node was created in a callee to avoid
// issues with irreducible loops in the caller
if (replaced.improved()->_idx >= idx) {
n->replace_edge(replaced.initial(), replaced.improved()); n->replace_edge(replaced.initial(), replaced.improved());
} }
}
} }
static void enqueue_use(Node* n, Node* use, Unique_Node_List& work) { static void enqueue_use(Node* n, Node* use, Unique_Node_List& work) {
......
...@@ -71,7 +71,7 @@ class ReplacedNodes VALUE_OBJ_CLASS_SPEC { ...@@ -71,7 +71,7 @@ class ReplacedNodes VALUE_OBJ_CLASS_SPEC {
void record(Node* initial, Node* improved); void record(Node* initial, Node* improved);
void transfer_from(const ReplacedNodes& other, uint idx); void transfer_from(const ReplacedNodes& other, uint idx);
void reset(); void reset();
void apply(Node* n); void apply(Node* n, uint idx);
void merge_with(const ReplacedNodes& other); void merge_with(const ReplacedNodes& other);
bool is_empty() const; bool is_empty() const;
void dump(outputStream *st) const; void dump(outputStream *st) const;
......
...@@ -707,6 +707,60 @@ const Type *CmpLNode::sub( const Type *t1, const Type *t2 ) const { ...@@ -707,6 +707,60 @@ const Type *CmpLNode::sub( const Type *t1, const Type *t2 ) const {
return TypeInt::CC; // else use worst case results 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-------------------------------------------- //------------------------------sub--------------------------------------------
// Simplify an CmpP (compare 2 pointers) node, based on local information. // Simplify an CmpP (compare 2 pointers) node, based on local information.
......
...@@ -192,6 +192,15 @@ public: ...@@ -192,6 +192,15 @@ public:
virtual const Type *sub( const Type *, const Type * ) const; 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-------------------------------------- //------------------------------CmpL3Node--------------------------------------
// Compare 2 long values, returning integer value (-1, 0 or 1). // Compare 2 long values, returning integer value (-1, 0 or 1).
class CmpL3Node : public CmpLNode { class CmpL3Node : public CmpLNode {
......
...@@ -1942,6 +1942,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable; ...@@ -1942,6 +1942,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
declare_c2_type(CmpPNode, CmpNode) \ declare_c2_type(CmpPNode, CmpNode) \
declare_c2_type(CmpNNode, CmpNode) \ declare_c2_type(CmpNNode, CmpNode) \
declare_c2_type(CmpLNode, CmpNode) \ declare_c2_type(CmpLNode, CmpNode) \
declare_c2_type(CmpULNode, CmpNode) \
declare_c2_type(CmpL3Node, CmpLNode) \ declare_c2_type(CmpL3Node, CmpLNode) \
declare_c2_type(CmpFNode, CmpNode) \ declare_c2_type(CmpFNode, CmpNode) \
declare_c2_type(CmpF3Node, CmpFNode) \ declare_c2_type(CmpF3Node, CmpFNode) \
......
/*
* Copyright (c) 2017, 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 8174164
* @summary SafePointNode::_replaced_nodes breaks with irreducible loops
* @run main/othervm -XX:-BackgroundCompilation TestReplacedNodesOSR
*
*/
public class TestReplacedNodesOSR {
static Object dummy;
static interface I {
}
static class A implements I {
}
static final class MyException extends Exception {
}
static final A obj = new A();
static I static_field() { return obj; }
// When OSR compiled, this method has an irreducible loop
static void test(int v, MyException e) {
int i = 0;
for (;;) {
if (i == 1000) {
break;
}
try {
if ((i%2) == 0) {
int j = 0;
for (;;) {
j++;
if (i+j != v) {
if (j == 1000) {
break;
}
} else {
A a = (A)static_field();
// replaced node recorded here
throw e;
}
}
}
} catch(MyException ex) {
}
i++;
// replaced node applied on return of the method
// replaced node used here
dummy = static_field();
}
}
static public void main(String[] args) {
for (int i = 0; i < 1000; i++) {
test(1100, new MyException());
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册