Merge
This commit is contained in:
commit
7150e2f4df
@ -2695,6 +2695,30 @@ operand flagsRegL_LEGT() %{
|
||||
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 cmpOpL_commute() %{
|
||||
%}
|
||||
%}
|
||||
|
||||
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 @@ instruct compL_reg_reg(flagsReg xcc, iRegL op1, iRegL op2)
|
||||
%}
|
||||
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 @@ instruct compL_reg_reg_LTGE(flagsRegL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp)
|
||||
%}
|
||||
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 @@ instruct compL_reg_con(flagsReg xcc, iRegL op1, aimmL con) %{
|
||||
|
||||
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 @@ instruct compL_reg_con_LEGT(flagsRegL_LEGT xcc, iRegL op1, immLlowRot con, iRegL
|
||||
|
||||
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 @@ instruct branchConL_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, label labl) %{
|
||||
%}
|
||||
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) %{
|
||||
|
@ -11048,6 +11048,29 @@ instruct cmpL_reg_imm16(flagsReg crx, iRegLsrc src1, immL16 src2) %{
|
||||
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
|
||||
|
@ -8475,6 +8475,24 @@ instruct compL_reg_memI(iRegL dst, memory src, flagsReg cr)%{
|
||||
%}
|
||||
|
||||
// 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
|
||||
|
||||
|
@ -3403,6 +3403,16 @@ operand immU12() %{
|
||||
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 @@ operand flagsRegL() %{
|
||||
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 @@ instruct compU_iReg(flagsRegU icc, iRegI op1, iRegI op2) %{
|
||||
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 @@ instruct compU_iReg_imm13(flagsRegU icc, iRegI op1, immU12 op2 ) %{
|
||||
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 @@ instruct cmpU_imm_branch(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU
|
||||
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 @@ instruct cmpU_imm_branch_short(cmpOpU cmp, iRegI op1, immI5 op2, label labl, fla
|
||||
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 @@ instruct branchCon_long(cmpOp cmp, flagsRegL xcc, label labl) %{
|
||||
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 ) %{
|
||||
|
@ -4030,6 +4030,26 @@ operand flagsReg_long_LEGT() %{
|
||||
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 @@ operand cmpOp_fcmov() %{
|
||||
%}
|
||||
%}
|
||||
|
||||
// Comparision Code used in long compares
|
||||
// Comparison Code used in long compares
|
||||
operand cmpOp_commute() %{
|
||||
match(Bool);
|
||||
|
||||
@ -4605,6 +4625,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 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 @@ 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.
|
||||
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 @@ 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.
|
||||
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 @@ 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.
|
||||
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)));
|
||||
|
@ -11518,6 +11518,48 @@ instruct cmpL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags)
|
||||
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
|
||||
|
||||
|
@ -1166,6 +1166,7 @@ void ArchDesc::buildMustCloneMap(FILE *fp_hpp, FILE *fp_cpp) {
|
||||
|| 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
|
||||
|
@ -81,6 +81,7 @@ macro(CmpL3)
|
||||
macro(CmpLTMask)
|
||||
macro(CmpP)
|
||||
macro(CmpU)
|
||||
macro(CmpUL)
|
||||
macro(CompareAndSwapB)
|
||||
macro(CompareAndSwapS)
|
||||
macro(CompareAndSwapI)
|
||||
|
@ -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 @@ bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invari
|
||||
// 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 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
|
||||
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 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
|
||||
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);
|
||||
|
@ -983,8 +983,8 @@ public:
|
||||
// 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);
|
||||
|
@ -1982,6 +1982,7 @@ void Scheduling::AddNodeToAvailableList(Node *n) {
|
||||
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 ||
|
||||
|
@ -738,6 +738,60 @@ const Type *CmpLNode::sub( const Type *t1, const Type *t2 ) const {
|
||||
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.
|
||||
|
@ -198,6 +198,15 @@ public:
|
||||
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 {
|
||||
|
@ -2008,6 +2008,7 @@ typedef CompactHashtable<Symbol*, char> SymbolCompactHashTable;
|
||||
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) \
|
||||
|
Loading…
Reference in New Issue
Block a user