7063629: use cbcond in C2 generated code on T4

Use new short branch instruction in C2 generated code.

Reviewed-by: never
This commit is contained in:
Vladimir Kozlov 2011-08-11 12:08:11 -07:00
parent 52f678435a
commit ac99f413d7
20 changed files with 1298 additions and 500 deletions

View file

@ -1192,6 +1192,8 @@ class Assembler : public AbstractAssembler {
assert(offset() == 0 || !cbcond_before(), "cbcond should not follow an other cbcond"); assert(offset() == 0 || !cbcond_before(), "cbcond should not follow an other cbcond");
} }
public:
bool use_cbcond(Label& L) { bool use_cbcond(Label& L) {
if (!UseCBCond || cbcond_before()) return false; if (!UseCBCond || cbcond_before()) return false;
intptr_t x = intptr_t(target_distance(L)) - intptr_t(pc()); intptr_t x = intptr_t(target_distance(L)) - intptr_t(pc());
@ -1199,7 +1201,6 @@ class Assembler : public AbstractAssembler {
return is_simm(x, 12); return is_simm(x, 12);
} }
public:
// Tells assembler you know that next instruction is delayed // Tells assembler you know that next instruction is delayed
Assembler* delayed() { Assembler* delayed() {
#ifdef CHECK_DELAY #ifdef CHECK_DELAY
@ -1248,6 +1249,10 @@ public:
inline void bpr(RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt = relocInfo::none); inline void bpr(RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt = relocInfo::none);
inline void bpr(RCondition c, bool a, Predict p, Register s1, Label& L); inline void bpr(RCondition c, bool a, Predict p, Register s1, Label& L);
// compare and branch
inline void cbcond(Condition c, CC cc, Register s1, Register s2, Label& L);
inline void cbcond(Condition c, CC cc, Register s1, int simm5, Label& L);
protected: // use MacroAssembler::br instead protected: // use MacroAssembler::br instead
// pp 138 // pp 138
@ -1275,10 +1280,6 @@ public:
inline void cb( Condition c, bool a, address d, relocInfo::relocType rt = relocInfo::none ); inline void cb( Condition c, bool a, address d, relocInfo::relocType rt = relocInfo::none );
inline void cb( Condition c, bool a, Label& L ); inline void cb( Condition c, bool a, Label& L );
// compare and branch
inline void cbcond(Condition c, CC cc, Register s1, Register s2, Label& L);
inline void cbcond(Condition c, CC cc, Register s1, int simm5, Label& L);
// pp 149 // pp 149
inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type );

View file

@ -1834,8 +1834,10 @@ const bool Matcher::convL2FSupported(void) {
// //
// NOTE: If the platform does not provide any short branch variants, then // NOTE: If the platform does not provide any short branch variants, then
// this method should return false for offset 0. // this method should return false for offset 0.
bool Matcher::is_short_branch_offset(int rule, int offset) { bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
return false; // The passed offset is relative to address of the branch.
// Don't need to adjust the offset.
return UseCBCond && Assembler::is_simm(offset, 12);
} }
const bool Matcher::isSimpleConstant64(jlong value) { const bool Matcher::isSimpleConstant64(jlong value) {
@ -3315,6 +3317,7 @@ op_attrib op_cost(1); // Required cost attribute
//----------Instruction Attributes--------------------------------------------- //----------Instruction Attributes---------------------------------------------
ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute
ins_attrib ins_size(32); // Required size attribute (in bits) ins_attrib ins_size(32); // Required size attribute (in bits)
ins_attrib ins_avoid_back_to_back(0); // instruction should not be generated back to back
ins_attrib ins_short_branch(0); // Required flag: is this instruction a ins_attrib ins_short_branch(0); // Required flag: is this instruction a
// non-matching short branch variant of some // non-matching short branch variant of some
// long branch? // long branch?
@ -3402,6 +3405,15 @@ operand immI11() %{
interface(CONST_INTER); interface(CONST_INTER);
%} %}
// Integer Immediate: 5-bit
operand immI5() %{
predicate(Assembler::is_simm(n->get_int(), 5));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: 0-bit // Integer Immediate: 0-bit
operand immI0() %{ operand immI0() %{
predicate(n->get_int() == 0); predicate(n->get_int() == 0);
@ -3625,6 +3637,15 @@ operand immL0() %{
interface(CONST_INTER); interface(CONST_INTER);
%} %}
// Integer Immediate: 5-bit
operand immL5() %{
predicate(n->get_long() == (int)n->get_long() && Assembler::is_simm((int)n->get_long(), 5));
match(ConL);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Long Immediate: 13-bit // Long Immediate: 13-bit
operand immL13() %{ operand immL13() %{
predicate((-4096L < n->get_long()) && (n->get_long() <= 4095L)); predicate((-4096L < n->get_long()) && (n->get_long() <= 4095L));
@ -5157,6 +5178,42 @@ pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{
MS : R; MS : R;
%} %}
// Compare and branch
pipe_class cmp_br_reg_reg(Universe br, cmpOp cmp, iRegI src1, iRegI src2, label labl, flagsReg cr) %{
instruction_count(2); has_delay_slot;
cr : E(write);
src1 : R(read);
src2 : R(read);
IALU : R;
BR : R;
%}
// Compare and branch
pipe_class cmp_br_reg_imm(Universe br, cmpOp cmp, iRegI src1, immI13 src2, label labl, flagsReg cr) %{
instruction_count(2); has_delay_slot;
cr : E(write);
src1 : R(read);
IALU : R;
BR : R;
%}
// Compare and branch using cbcond
pipe_class cbcond_reg_reg(Universe br, cmpOp cmp, iRegI src1, iRegI src2, label labl) %{
single_instruction;
src1 : E(read);
src2 : E(read);
IALU : R;
BR : R;
%}
// Compare and branch using cbcond
pipe_class cbcond_reg_imm(Universe br, cmpOp cmp, iRegI src1, immI5 src2, label labl) %{
single_instruction;
src1 : E(read);
IALU : R;
BR : R;
%}
pipe_class br_fcc(Universe br, cmpOpF cc, flagsReg cr, label labl) %{ pipe_class br_fcc(Universe br, cmpOpF cc, flagsReg cr, label labl) %{
single_instruction_with_delay_slot; single_instruction_with_delay_slot;
cr : E(read); cr : E(read);
@ -9198,6 +9255,25 @@ instruct branch(label labl) %{
ins_pipe(br); ins_pipe(br);
%} %}
// Direct Branch, short with no delay slot
instruct branch_short(label labl) %{
match(Goto);
predicate(UseCBCond);
effect(USE labl);
size(4);
ins_cost(BRANCH_COST);
format %{ "BA $labl\t! short branch" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ ba_short(*L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_imm);
%}
// Conditional Direct Branch // Conditional Direct Branch
instruct branchCon(cmpOp cmp, flagsReg icc, label labl) %{ instruct branchCon(cmpOp cmp, flagsReg icc, label labl) %{
match(If cmp icc); match(If cmp icc);
@ -9211,50 +9287,11 @@ instruct branchCon(cmpOp cmp, flagsReg icc, label labl) %{
ins_pipe(br_cc); ins_pipe(br_cc);
%} %}
// Branch-on-register tests all 64 bits. We assume that values
// in 64-bit registers always remains zero or sign extended
// unless our code munges the high bits. Interrupts can chop
// the high order bits to zero or sign at any time.
instruct branchCon_regI(cmpOp_reg cmp, iRegI op1, immI0 zero, label labl) %{
match(If cmp (CmpI op1 zero));
predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
effect(USE labl);
size(8);
ins_cost(BRANCH_COST);
format %{ "BR$cmp $op1,$labl" %}
ins_encode( enc_bpr( labl, cmp, op1 ) );
ins_pipe(br_reg);
%}
instruct branchCon_regP(cmpOp_reg cmp, iRegP op1, immP0 null, label labl) %{
match(If cmp (CmpP op1 null));
predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
effect(USE labl);
size(8);
ins_cost(BRANCH_COST);
format %{ "BR$cmp $op1,$labl" %}
ins_encode( enc_bpr( labl, cmp, op1 ) );
ins_pipe(br_reg);
%}
instruct branchCon_regL(cmpOp_reg cmp, iRegL op1, immL0 zero, label labl) %{
match(If cmp (CmpL op1 zero));
predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
effect(USE labl);
size(8);
ins_cost(BRANCH_COST);
format %{ "BR$cmp $op1,$labl" %}
ins_encode( enc_bpr( labl, cmp, op1 ) );
ins_pipe(br_reg);
%}
instruct branchConU(cmpOpU cmp, flagsRegU icc, label labl) %{ instruct branchConU(cmpOpU cmp, flagsRegU icc, label labl) %{
match(If cmp icc); match(If cmp icc);
effect(USE labl); effect(USE labl);
ins_cost(BRANCH_COST);
format %{ "BP$cmp $icc,$labl" %} format %{ "BP$cmp $icc,$labl" %}
// Prim = bits 24-22, Secnd = bits 31-30 // Prim = bits 24-22, Secnd = bits 31-30
ins_encode( enc_bp( labl, cmp, icc ) ); ins_encode( enc_bp( labl, cmp, icc ) );
@ -9321,6 +9358,506 @@ instruct branchLoopEndU(cmpOpU cmp, flagsRegU icc, label labl) %{
ins_pipe(br_cc); ins_pipe(br_cc);
%} %}
// Compare and branch instructions
instruct cmpI_reg_branch(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{
match(If cmp (CmpI op1 op2));
effect(USE labl, KILL icc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! int\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::icc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_reg);
%}
instruct cmpI_imm_branch(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{
match(If cmp (CmpI op1 op2));
effect(USE labl, KILL icc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! int\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::icc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_imm);
%}
instruct cmpU_reg_branch(cmpOpU cmp, iRegI op1, iRegI op2, label labl, flagsRegU icc) %{
match(If cmp (CmpU op1 op2));
effect(USE labl, KILL icc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! unsigned\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::icc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_reg);
%}
instruct cmpU_imm_branch(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU icc) %{
match(If cmp (CmpU op1 op2));
effect(USE labl, KILL icc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! unsigned\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::icc, 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);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! 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 cmpL_imm_branch(cmpOp cmp, iRegL op1, immL5 op2, label labl, flagsRegL xcc) %{
match(If cmp (CmpL op1 op2));
effect(USE labl, KILL xcc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! 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);
%}
// Compare Pointers and branch
instruct cmpP_reg_branch(cmpOpP cmp, iRegP op1, iRegP op2, label labl, flagsRegP pcc) %{
match(If cmp (CmpP op1 op2));
effect(USE labl, KILL pcc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! ptr\n\t"
"B$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::ptr_cc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_reg);
%}
instruct cmpP_null_branch(cmpOpP cmp, iRegP op1, immP0 null, label labl, flagsRegP pcc) %{
match(If cmp (CmpP op1 null));
effect(USE labl, KILL pcc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,0\t! ptr\n\t"
"B$cmp $labl" %}
ins_encode %{
Label* L = $labl$$label;
Assembler::Predict predict_taken =
cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
__ cmp($op1$$Register, G0);
// bpr() is not used here since it has shorter distance.
__ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::ptr_cc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_reg);
%}
instruct cmpN_reg_branch(cmpOp cmp, iRegN op1, iRegN op2, label labl, flagsReg icc) %{
match(If cmp (CmpN op1 op2));
effect(USE labl, KILL icc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! compressed ptr\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::icc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_reg);
%}
instruct cmpN_null_branch(cmpOp cmp, iRegN op1, immN0 null, label labl, flagsReg icc) %{
match(If cmp (CmpN op1 null));
effect(USE labl, KILL icc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,0\t! compressed ptr\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, G0);
__ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_reg);
%}
// Loop back branch
instruct cmpI_reg_branchLoopEnd(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{
match(CountedLoopEnd cmp (CmpI op1 op2));
effect(USE labl, KILL icc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! int\n\t"
"BP$cmp $labl\t! Loop end" %}
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::icc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_reg);
%}
instruct cmpI_imm_branchLoopEnd(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{
match(CountedLoopEnd cmp (CmpI op1 op2));
effect(USE labl, KILL icc);
size(12);
ins_cost(BRANCH_COST);
format %{ "CMP $op1,$op2\t! int\n\t"
"BP$cmp $labl\t! Loop end" %}
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::icc, predict_taken, *L);
__ delayed()->nop();
%}
ins_pipe(cmp_br_reg_imm);
%}
// Short compare and branch instructions
instruct cmpI_reg_branch_short(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{
match(If cmp (CmpI op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL icc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CWB$cmp $op1,$op2,$labl\t! int" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_reg);
%}
instruct cmpI_imm_branch_short(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{
match(If cmp (CmpI op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL icc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CWB$cmp $op1,$op2,$labl\t! int" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_imm);
%}
instruct cmpU_reg_branch_short(cmpOpU cmp, iRegI op1, iRegI op2, label labl, flagsRegU icc) %{
match(If cmp (CmpU op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL icc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CWB$cmp $op1,$op2,$labl\t! unsigned" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_reg);
%}
instruct cmpU_imm_branch_short(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU icc) %{
match(If cmp (CmpU op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL icc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CWB$cmp $op1,$op2,$labl\t! unsigned" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
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);
effect(USE labl, KILL xcc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CXB$cmp $op1,$op2,$labl\t! 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(1);
ins_pipe(cbcond_reg_reg);
%}
instruct cmpL_imm_branch_short(cmpOp cmp, iRegL op1, immL5 op2, label labl, flagsRegL xcc) %{
match(If cmp (CmpL op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL xcc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CXB$cmp $op1,$op2,$labl\t! 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(1);
ins_pipe(cbcond_reg_imm);
%}
// Compare Pointers and branch
instruct cmpP_reg_branch_short(cmpOpP cmp, iRegP op1, iRegP op2, label labl, flagsRegP pcc) %{
match(If cmp (CmpP op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL pcc);
size(4);
ins_cost(BRANCH_COST);
#ifdef _LP64
format %{ "CXB$cmp $op1,$op2,$labl\t! ptr" %}
#else
format %{ "CWB$cmp $op1,$op2,$labl\t! ptr" %}
#endif
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::ptr_cc, $op1$$Register, $op2$$Register, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_reg);
%}
instruct cmpP_null_branch_short(cmpOpP cmp, iRegP op1, immP0 null, label labl, flagsRegP pcc) %{
match(If cmp (CmpP op1 null));
predicate(UseCBCond);
effect(USE labl, KILL pcc);
size(4);
ins_cost(BRANCH_COST);
#ifdef _LP64
format %{ "CXB$cmp $op1,0,$labl\t! ptr" %}
#else
format %{ "CWB$cmp $op1,0,$labl\t! ptr" %}
#endif
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::ptr_cc, $op1$$Register, G0, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_reg);
%}
instruct cmpN_reg_branch_short(cmpOp cmp, iRegN op1, iRegN op2, label labl, flagsReg icc) %{
match(If cmp (CmpN op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL icc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CWB$cmp $op1,op2,$labl\t! compressed ptr" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_reg);
%}
instruct cmpN_null_branch_short(cmpOp cmp, iRegN op1, immN0 null, label labl, flagsReg icc) %{
match(If cmp (CmpN op1 null));
predicate(UseCBCond);
effect(USE labl, KILL icc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CWB$cmp $op1,0,$labl\t! compressed ptr" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, G0, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_reg);
%}
// Loop back branch
instruct cmpI_reg_branchLoopEnd_short(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{
match(CountedLoopEnd cmp (CmpI op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL icc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CWB$cmp $op1,$op2,$labl\t! Loop end" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_reg);
%}
instruct cmpI_imm_branchLoopEnd_short(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{
match(CountedLoopEnd cmp (CmpI op1 op2));
predicate(UseCBCond);
effect(USE labl, KILL icc);
size(4);
ins_cost(BRANCH_COST);
format %{ "CWB$cmp $op1,$op2,$labl\t! Loop end" %}
ins_encode %{
Label* L = $labl$$label;
assert(__ use_cbcond(*L), "back to back cbcond");
__ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L);
%}
ins_short_branch(1);
ins_avoid_back_to_back(1);
ins_pipe(cbcond_reg_imm);
%}
// Branch-on-register tests all 64 bits. We assume that values
// in 64-bit registers always remains zero or sign extended
// unless our code munges the high bits. Interrupts can chop
// the high order bits to zero or sign at any time.
instruct branchCon_regI(cmpOp_reg cmp, iRegI op1, immI0 zero, label labl) %{
match(If cmp (CmpI op1 zero));
predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
effect(USE labl);
size(8);
ins_cost(BRANCH_COST);
format %{ "BR$cmp $op1,$labl" %}
ins_encode( enc_bpr( labl, cmp, op1 ) );
ins_pipe(br_reg);
%}
instruct branchCon_regP(cmpOp_reg cmp, iRegP op1, immP0 null, label labl) %{
match(If cmp (CmpP op1 null));
predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
effect(USE labl);
size(8);
ins_cost(BRANCH_COST);
format %{ "BR$cmp $op1,$labl" %}
ins_encode( enc_bpr( labl, cmp, op1 ) );
ins_pipe(br_reg);
%}
instruct branchCon_regL(cmpOp_reg cmp, iRegL op1, immL0 zero, label labl) %{
match(If cmp (CmpL op1 zero));
predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
effect(USE labl);
size(8);
ins_cost(BRANCH_COST);
format %{ "BR$cmp $op1,$labl" %}
ins_encode( enc_bpr( labl, cmp, op1 ) );
ins_pipe(br_reg);
%}
// ============================================================================ // ============================================================================
// Long Compare // Long Compare
// //

View file

@ -144,8 +144,13 @@ void VM_Version::initialize() {
// Currently not supported anywhere. // Currently not supported anywhere.
FLAG_SET_DEFAULT(UseFPUForSpilling, false); FLAG_SET_DEFAULT(UseFPUForSpilling, false);
assert((InteriorEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
#endif #endif
assert((CodeEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
assert((OptoLoopAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
char buf[512]; char buf[512];
jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(has_v9() ? ", v9" : (has_v8() ? ", v8" : "")), (has_v9() ? ", v9" : (has_v8() ? ", v8" : "")),

View file

@ -1339,9 +1339,8 @@ void Assembler::incl(Address dst) {
emit_operand(rax, dst); emit_operand(rax, dst);
} }
void Assembler::jcc(Condition cc, Label& L, relocInfo::relocType rtype) { void Assembler::jcc(Condition cc, Label& L, bool maybe_short) {
InstructionMark im(this); InstructionMark im(this);
relocate(rtype);
assert((0 <= cc) && (cc < 16), "illegal cc"); assert((0 <= cc) && (cc < 16), "illegal cc");
if (L.is_bound()) { if (L.is_bound()) {
address dst = target(L); address dst = target(L);
@ -1350,7 +1349,7 @@ void Assembler::jcc(Condition cc, Label& L, relocInfo::relocType rtype) {
const int short_size = 2; const int short_size = 2;
const int long_size = 6; const int long_size = 6;
intptr_t offs = (intptr_t)dst - (intptr_t)_code_pos; intptr_t offs = (intptr_t)dst - (intptr_t)_code_pos;
if (rtype == relocInfo::none && is8bit(offs - short_size)) { if (maybe_short && is8bit(offs - short_size)) {
// 0111 tttn #8-bit disp // 0111 tttn #8-bit disp
emit_byte(0x70 | cc); emit_byte(0x70 | cc);
emit_byte((offs - short_size) & 0xFF); emit_byte((offs - short_size) & 0xFF);
@ -1399,7 +1398,7 @@ void Assembler::jmp(Address adr) {
emit_operand(rsp, adr); emit_operand(rsp, adr);
} }
void Assembler::jmp(Label& L, relocInfo::relocType rtype) { void Assembler::jmp(Label& L, bool maybe_short) {
if (L.is_bound()) { if (L.is_bound()) {
address entry = target(L); address entry = target(L);
assert(entry != NULL, "jmp most probably wrong"); assert(entry != NULL, "jmp most probably wrong");
@ -1407,7 +1406,7 @@ void Assembler::jmp(Label& L, relocInfo::relocType rtype) {
const int short_size = 2; const int short_size = 2;
const int long_size = 5; const int long_size = 5;
intptr_t offs = entry - _code_pos; intptr_t offs = entry - _code_pos;
if (rtype == relocInfo::none && is8bit(offs - short_size)) { if (maybe_short && is8bit(offs - short_size)) {
emit_byte(0xEB); emit_byte(0xEB);
emit_byte((offs - short_size) & 0xFF); emit_byte((offs - short_size) & 0xFF);
} else { } else {
@ -1420,7 +1419,6 @@ void Assembler::jmp(Label& L, relocInfo::relocType rtype) {
// the forward jump will not run beyond 256 bytes, use jmpb to // the forward jump will not run beyond 256 bytes, use jmpb to
// force an 8-bit displacement. // force an 8-bit displacement.
InstructionMark im(this); InstructionMark im(this);
relocate(rtype);
L.add_patch_at(code(), locator()); L.add_patch_at(code(), locator());
emit_byte(0xE9); emit_byte(0xE9);
emit_long(0); emit_long(0);

View file

@ -1065,8 +1065,7 @@ private:
// Note: The same Label can be used for forward and backward branches // Note: The same Label can be used for forward and backward branches
// but it may be bound only once. // but it may be bound only once.
void jcc(Condition cc, Label& L, void jcc(Condition cc, Label& L, bool maybe_short = true);
relocInfo::relocType rtype = relocInfo::none);
// Conditional jump to a 8-bit offset to L. // Conditional jump to a 8-bit offset to L.
// WARNING: be very careful using this for forward jumps. If the label is // WARNING: be very careful using this for forward jumps. If the label is
@ -1077,7 +1076,7 @@ private:
void jmp(Address entry); // pc <- entry void jmp(Address entry); // pc <- entry
// Label operations & relative jumps (PPUM Appendix D) // Label operations & relative jumps (PPUM Appendix D)
void jmp(Label& L, relocInfo::relocType rtype = relocInfo::none); // unconditional jump to L void jmp(Label& L, bool maybe_short = true); // unconditional jump to L
void jmp(Register entry); // pc <- entry void jmp(Register entry); // pc <- entry

View file

@ -1369,7 +1369,12 @@ const uint Matcher::vector_ideal_reg(void) {
// //
// NOTE: If the platform does not provide any short branch variants, then // NOTE: If the platform does not provide any short branch variants, then
// this method should return false for offset 0. // this method should return false for offset 0.
bool Matcher::is_short_branch_offset(int rule, int offset) { bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
// The passed offset is relative to address of the branch.
// On 86 a branch displacement is calculated relative to address
// of a next instruction.
offset -= br_size;
// the short version of jmpConUCF2 contains multiple branches, // the short version of jmpConUCF2 contains multiple branches,
// making the reach slightly less // making the reach slightly less
if (rule == jmpConUCF2_rule) if (rule == jmpConUCF2_rule)
@ -1713,18 +1718,6 @@ encode %{
else emit_d32(cbuf,con); else emit_d32(cbuf,con);
%} %}
enc_class Lbl (label labl) %{ // GOTO
Label *l = $labl$$label;
emit_d32(cbuf, (l->loc_pos() - (cbuf.insts_size()+4)));
%}
enc_class LblShort (label labl) %{ // GOTO
Label *l = $labl$$label;
int disp = l->loc_pos() - (cbuf.insts_size()+1);
assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp");
emit_d8(cbuf, disp);
%}
enc_class OpcSReg (eRegI dst) %{ // BSWAP enc_class OpcSReg (eRegI dst) %{ // BSWAP
emit_cc(cbuf, $secondary, $dst$$reg ); emit_cc(cbuf, $secondary, $dst$$reg );
%} %}
@ -1747,21 +1740,6 @@ encode %{
emit_rm(cbuf, 0x3, $secondary, $div$$reg ); emit_rm(cbuf, 0x3, $secondary, $div$$reg );
%} %}
enc_class Jcc (cmpOp cop, label labl) %{ // JCC
Label *l = $labl$$label;
$$$emit8$primary;
emit_cc(cbuf, $secondary, $cop$$cmpcode);
emit_d32(cbuf, (l->loc_pos() - (cbuf.insts_size()+4)));
%}
enc_class JccShort (cmpOp cop, label labl) %{ // JCC
Label *l = $labl$$label;
emit_cc(cbuf, $primary, $cop$$cmpcode);
int disp = l->loc_pos() - (cbuf.insts_size()+1);
assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp");
emit_d8(cbuf, disp);
%}
enc_class enc_cmov(cmpOp cop ) %{ // CMOV enc_class enc_cmov(cmpOp cop ) %{ // CMOV
$$$emit8$primary; $$$emit8$primary;
emit_cc(cbuf, $secondary, $cop$$cmpcode); emit_cc(cbuf, $secondary, $cop$$cmpcode);
@ -13055,8 +13033,10 @@ instruct jmpDir(label labl) %{
ins_cost(300); ins_cost(300);
format %{ "JMP $labl" %} format %{ "JMP $labl" %}
size(5); size(5);
opcode(0xE9); ins_encode %{
ins_encode( OpcP, Lbl( labl ) ); Label* L = $labl$$label;
__ jmp(*L, false); // Always long jump
%}
ins_pipe( pipe_jmp ); ins_pipe( pipe_jmp );
%} %}
@ -13068,8 +13048,10 @@ instruct jmpCon(cmpOp cop, eFlagsReg cr, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop $labl" %} format %{ "J$cop $labl" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode( Jcc( cop, labl) ); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
%} %}
@ -13081,8 +13063,10 @@ instruct jmpLoopEnd(cmpOp cop, eFlagsReg cr, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop $labl\t# Loop end" %} format %{ "J$cop $labl\t# Loop end" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode( Jcc( cop, labl) ); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
%} %}
@ -13094,8 +13078,10 @@ instruct jmpLoopEndU(cmpOpU cop, eFlagsRegU cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop,u $labl\t# Loop end" %} format %{ "J$cop,u $labl\t# Loop end" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode( Jcc( cop, labl) ); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
%} %}
@ -13106,8 +13092,10 @@ instruct jmpLoopEndUCF(cmpOpUCF cop, eFlagsRegUCF cmp, label labl) %{
ins_cost(200); ins_cost(200);
format %{ "J$cop,u $labl\t# Loop end" %} format %{ "J$cop,u $labl\t# Loop end" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode( Jcc( cop, labl) ); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
%} %}
@ -13119,8 +13107,10 @@ instruct jmpConU(cmpOpU cop, eFlagsRegU cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop,u $labl" %} format %{ "J$cop,u $labl" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode(Jcc(cop, labl)); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -13131,8 +13121,10 @@ instruct jmpConUCF(cmpOpUCF cop, eFlagsRegUCF cmp, label labl) %{
ins_cost(200); ins_cost(200);
format %{ "J$cop,u $labl" %} format %{ "J$cop,u $labl" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode(Jcc(cop, labl)); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -13151,28 +13143,19 @@ instruct jmpConUCF2(cmpOpUCF2 cop, eFlagsRegUCF cmp, label labl) %{
$$emit$$"done:" $$emit$$"done:"
} }
%} %}
size(12);
opcode(0x0F, 0x80);
ins_encode %{ ins_encode %{
Label* l = $labl$$label; Label* l = $labl$$label;
$$$emit8$primary;
emit_cc(cbuf, $secondary, Assembler::parity);
int parity_disp = -1;
bool ok = false;
if ($cop$$cmpcode == Assembler::notEqual) { if ($cop$$cmpcode == Assembler::notEqual) {
// the two jumps 6 bytes apart so the jump distances are too __ jcc(Assembler::parity, *l, false);
parity_disp = l->loc_pos() - (cbuf.insts_size() + 4); __ jcc(Assembler::notEqual, *l, false);
} else if ($cop$$cmpcode == Assembler::equal) { } else if ($cop$$cmpcode == Assembler::equal) {
parity_disp = 6; Label done;
ok = true; __ jccb(Assembler::parity, done);
__ jcc(Assembler::equal, *l, false);
__ bind(done);
} else { } else {
ShouldNotReachHere(); ShouldNotReachHere();
} }
emit_d32(cbuf, parity_disp);
$$$emit8$primary;
emit_cc(cbuf, $secondary, $cop$$cmpcode);
int disp = l->loc_pos() - (cbuf.insts_size() + 4);
emit_d32(cbuf, disp);
%} %}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -13239,8 +13222,10 @@ instruct jmpDir_short(label labl) %{
ins_cost(300); ins_cost(300);
format %{ "JMP,s $labl" %} format %{ "JMP,s $labl" %}
size(2); size(2);
opcode(0xEB); ins_encode %{
ins_encode( OpcP, LblShort( labl ) ); Label* L = $labl$$label;
__ jmpb(*L);
%}
ins_pipe( pipe_jmp ); ins_pipe( pipe_jmp );
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -13253,8 +13238,10 @@ instruct jmpCon_short(cmpOp cop, eFlagsReg cr, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop,s $labl" %} format %{ "J$cop,s $labl" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode( JccShort( cop, labl) ); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -13267,8 +13254,10 @@ instruct jmpLoopEnd_short(cmpOp cop, eFlagsReg cr, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop,s $labl\t# Loop end" %} format %{ "J$cop,s $labl\t# Loop end" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode( JccShort( cop, labl) ); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -13281,8 +13270,10 @@ instruct jmpLoopEndU_short(cmpOpU cop, eFlagsRegU cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop,us $labl\t# Loop end" %} format %{ "J$cop,us $labl\t# Loop end" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode( JccShort( cop, labl) ); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -13294,8 +13285,10 @@ instruct jmpLoopEndUCF_short(cmpOpUCF cop, eFlagsRegUCF cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop,us $labl\t# Loop end" %} format %{ "J$cop,us $labl\t# Loop end" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode( JccShort( cop, labl) ); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -13308,8 +13301,10 @@ instruct jmpConU_short(cmpOpU cop, eFlagsRegU cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop,us $labl" %} format %{ "J$cop,us $labl" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode( JccShort( cop, labl) ); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -13321,8 +13316,10 @@ instruct jmpConUCF_short(cmpOpUCF cop, eFlagsRegUCF cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "J$cop,us $labl" %} format %{ "J$cop,us $labl" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode( JccShort( cop, labl) ); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe( pipe_jcc ); ins_pipe( pipe_jcc );
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -13343,24 +13340,19 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, eFlagsRegUCF cmp, label labl) %{
} }
%} %}
size(4); size(4);
opcode(0x70);
ins_encode %{ ins_encode %{
Label* l = $labl$$label; Label* l = $labl$$label;
emit_cc(cbuf, $primary, Assembler::parity);
int parity_disp = -1;
if ($cop$$cmpcode == Assembler::notEqual) { if ($cop$$cmpcode == Assembler::notEqual) {
parity_disp = l->loc_pos() - (cbuf.insts_size() + 1); __ jccb(Assembler::parity, *l);
__ jccb(Assembler::notEqual, *l);
} else if ($cop$$cmpcode == Assembler::equal) { } else if ($cop$$cmpcode == Assembler::equal) {
parity_disp = 2; Label done;
__ jccb(Assembler::parity, done);
__ jccb(Assembler::equal, *l);
__ bind(done);
} else { } else {
ShouldNotReachHere(); ShouldNotReachHere();
} }
emit_d8(cbuf, parity_disp);
emit_cc(cbuf, $primary, $cop$$cmpcode);
int disp = l->loc_pos() - (cbuf.insts_size() + 1);
emit_d8(cbuf, disp);
assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp");
assert(-128 <= parity_disp && parity_disp <= 127, "Displacement too large for short jmp");
%} %}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
ins_short_branch(1); ins_short_branch(1);

View file

@ -1966,7 +1966,12 @@ const uint Matcher::vector_ideal_reg(void) {
// //
// NOTE: If the platform does not provide any short branch variants, then // NOTE: If the platform does not provide any short branch variants, then
// this method should return false for offset 0. // this method should return false for offset 0.
bool Matcher::is_short_branch_offset(int rule, int offset) { bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
// The passed offset is relative to address of the branch.
// On 86 a branch displacement is calculated relative to address
// of a next instruction.
offset -= br_size;
// the short version of jmpConUCF2 contains multiple branches, // the short version of jmpConUCF2 contains multiple branches,
// making the reach slightly less // making the reach slightly less
if (rule == jmpConUCF2_rule) if (rule == jmpConUCF2_rule)
@ -2426,22 +2431,6 @@ encode %{
} }
%} %}
enc_class Lbl(label labl)
%{
// GOTO
Label* l = $labl$$label;
emit_d32(cbuf, (l->loc_pos() - (cbuf.insts_size() + 4)));
%}
enc_class LblShort(label labl)
%{
// GOTO
Label* l = $labl$$label;
int disp = l->loc_pos() - (cbuf.insts_size() + 1);
assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp");
emit_d8(cbuf, disp);
%}
enc_class opc2_reg(rRegI dst) enc_class opc2_reg(rRegI dst)
%{ %{
// BSWAP // BSWAP
@ -2460,25 +2449,6 @@ encode %{
emit_rm(cbuf, 0x3, $secondary, $div$$reg & 7); emit_rm(cbuf, 0x3, $secondary, $div$$reg & 7);
%} %}
enc_class Jcc(cmpOp cop, label labl)
%{
// JCC
Label* l = $labl$$label;
$$$emit8$primary;
emit_cc(cbuf, $secondary, $cop$$cmpcode);
emit_d32(cbuf, (l->loc_pos() - (cbuf.insts_size() + 4)));
%}
enc_class JccShort (cmpOp cop, label labl)
%{
// JCC
Label *l = $labl$$label;
emit_cc(cbuf, $primary, $cop$$cmpcode);
int disp = l->loc_pos() - (cbuf.insts_size() + 1);
assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp");
emit_d8(cbuf, disp);
%}
enc_class enc_cmov(cmpOp cop) enc_class enc_cmov(cmpOp cop)
%{ %{
// CMOV // CMOV
@ -12011,8 +11981,10 @@ instruct jmpDir(label labl)
ins_cost(300); ins_cost(300);
format %{ "jmp $labl" %} format %{ "jmp $labl" %}
size(5); size(5);
opcode(0xE9); ins_encode %{
ins_encode(OpcP, Lbl(labl)); Label* L = $labl$$label;
__ jmp(*L, false); // Always long jump
%}
ins_pipe(pipe_jmp); ins_pipe(pipe_jmp);
%} %}
@ -12025,8 +11997,10 @@ instruct jmpCon(cmpOp cop, rFlagsReg cr, label labl)
ins_cost(300); ins_cost(300);
format %{ "j$cop $labl" %} format %{ "j$cop $labl" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode(Jcc(cop, labl)); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -12039,8 +12013,10 @@ instruct jmpLoopEnd(cmpOp cop, rFlagsReg cr, label labl)
ins_cost(300); ins_cost(300);
format %{ "j$cop $labl\t# loop end" %} format %{ "j$cop $labl\t# loop end" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode(Jcc(cop, labl)); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -12052,8 +12028,10 @@ instruct jmpLoopEndU(cmpOpU cop, rFlagsRegU cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "j$cop,u $labl\t# loop end" %} format %{ "j$cop,u $labl\t# loop end" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode(Jcc(cop, labl)); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -12064,8 +12042,10 @@ instruct jmpLoopEndUCF(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{
ins_cost(200); ins_cost(200);
format %{ "j$cop,u $labl\t# loop end" %} format %{ "j$cop,u $labl\t# loop end" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode(Jcc(cop, labl)); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -12077,8 +12057,10 @@ instruct jmpConU(cmpOpU cop, rFlagsRegU cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "j$cop,u $labl" %} format %{ "j$cop,u $labl" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode(Jcc(cop, labl)); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -12089,8 +12071,10 @@ instruct jmpConUCF(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{
ins_cost(200); ins_cost(200);
format %{ "j$cop,u $labl" %} format %{ "j$cop,u $labl" %}
size(6); size(6);
opcode(0x0F, 0x80); ins_encode %{
ins_encode(Jcc(cop, labl)); Label* L = $labl$$label;
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -12109,26 +12093,19 @@ instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{
$$emit$$"done:" $$emit$$"done:"
} }
%} %}
size(12);
opcode(0x0F, 0x80);
ins_encode %{ ins_encode %{
Label* l = $labl$$label; Label* l = $labl$$label;
$$$emit8$primary;
emit_cc(cbuf, $secondary, Assembler::parity);
int parity_disp = -1;
if ($cop$$cmpcode == Assembler::notEqual) { if ($cop$$cmpcode == Assembler::notEqual) {
// the two jumps 6 bytes apart so the jump distances are too __ jcc(Assembler::parity, *l, false);
parity_disp = l->loc_pos() - (cbuf.insts_size() + 4); __ jcc(Assembler::notEqual, *l, false);
} else if ($cop$$cmpcode == Assembler::equal) { } else if ($cop$$cmpcode == Assembler::equal) {
parity_disp = 6; Label done;
__ jccb(Assembler::parity, done);
__ jcc(Assembler::equal, *l, false);
__ bind(done);
} else { } else {
ShouldNotReachHere(); ShouldNotReachHere();
} }
emit_d32(cbuf, parity_disp);
$$$emit8$primary;
emit_cc(cbuf, $secondary, $cop$$cmpcode);
int disp = l->loc_pos() - (cbuf.insts_size() + 4);
emit_d32(cbuf, disp);
%} %}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
%} %}
@ -12204,8 +12181,10 @@ instruct jmpDir_short(label labl) %{
ins_cost(300); ins_cost(300);
format %{ "jmp,s $labl" %} format %{ "jmp,s $labl" %}
size(2); size(2);
opcode(0xEB); ins_encode %{
ins_encode(OpcP, LblShort(labl)); Label* L = $labl$$label;
__ jmpb(*L);
%}
ins_pipe(pipe_jmp); ins_pipe(pipe_jmp);
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -12218,8 +12197,10 @@ instruct jmpCon_short(cmpOp cop, rFlagsReg cr, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "j$cop,s $labl" %} format %{ "j$cop,s $labl" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode(JccShort(cop, labl)); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -12232,8 +12213,10 @@ instruct jmpLoopEnd_short(cmpOp cop, rFlagsReg cr, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "j$cop,s $labl\t# loop end" %} format %{ "j$cop,s $labl\t# loop end" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode(JccShort(cop, labl)); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -12246,8 +12229,10 @@ instruct jmpLoopEndU_short(cmpOpU cop, rFlagsRegU cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "j$cop,us $labl\t# loop end" %} format %{ "j$cop,us $labl\t# loop end" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode(JccShort(cop, labl)); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -12259,8 +12244,10 @@ instruct jmpLoopEndUCF_short(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "j$cop,us $labl\t# loop end" %} format %{ "j$cop,us $labl\t# loop end" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode(JccShort(cop, labl)); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -12273,8 +12260,10 @@ instruct jmpConU_short(cmpOpU cop, rFlagsRegU cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "j$cop,us $labl" %} format %{ "j$cop,us $labl" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode(JccShort(cop, labl)); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -12286,8 +12275,10 @@ instruct jmpConUCF_short(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{
ins_cost(300); ins_cost(300);
format %{ "j$cop,us $labl" %} format %{ "j$cop,us $labl" %}
size(2); size(2);
opcode(0x70); ins_encode %{
ins_encode(JccShort(cop, labl)); Label* L = $labl$$label;
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
%}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
ins_short_branch(1); ins_short_branch(1);
%} %}
@ -12308,24 +12299,19 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{
} }
%} %}
size(4); size(4);
opcode(0x70);
ins_encode %{ ins_encode %{
Label* l = $labl$$label; Label* l = $labl$$label;
emit_cc(cbuf, $primary, Assembler::parity);
int parity_disp = -1;
if ($cop$$cmpcode == Assembler::notEqual) { if ($cop$$cmpcode == Assembler::notEqual) {
parity_disp = l->loc_pos() - (cbuf.insts_size() + 1); __ jccb(Assembler::parity, *l);
__ jccb(Assembler::notEqual, *l);
} else if ($cop$$cmpcode == Assembler::equal) { } else if ($cop$$cmpcode == Assembler::equal) {
parity_disp = 2; Label done;
__ jccb(Assembler::parity, done);
__ jccb(Assembler::equal, *l);
__ bind(done);
} else { } else {
ShouldNotReachHere(); ShouldNotReachHere();
} }
emit_d8(cbuf, parity_disp);
emit_cc(cbuf, $primary, $cop$$cmpcode);
int disp = l->loc_pos() - (cbuf.insts_size() + 1);
emit_d8(cbuf, disp);
assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp");
assert(-128 <= parity_disp && parity_disp <= 127, "Displacement too large for short jmp");
%} %}
ins_pipe(pipe_jcc); ins_pipe(pipe_jcc);
ins_short_branch(1); ins_short_branch(1);

View file

@ -154,7 +154,7 @@ void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
return 5; return MachNode::size(ra_);
} }
%} %}

View file

@ -167,7 +167,8 @@ void MachBreakpointNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
} }
uint MachBreakpointNode::size(PhaseRegAlloc* ra_) const { uint MachBreakpointNode::size(PhaseRegAlloc* ra_) const {
return 5; // distance could be far and requires load and call through register
return MachNode::size(ra_);
} }
%} %}

View file

@ -161,7 +161,7 @@ void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
return 5; return MachNode::size(ra_);
} }
%} %}

View file

@ -180,7 +180,8 @@ void MachBreakpointNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
uint MachBreakpointNode::size(PhaseRegAlloc* ra_) const uint MachBreakpointNode::size(PhaseRegAlloc* ra_) const
{ {
return 5; // distance could be far and requires load and call through register
return MachNode::size(ra_);
} }
%} %}

View file

@ -1181,6 +1181,34 @@ bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch
strcmp(reduce_result(), short_branch->reduce_result()) == 0 && strcmp(reduce_result(), short_branch->reduce_result()) == 0 &&
_matrule->equivalent(AD.globalNames(), short_branch->_matrule)) { _matrule->equivalent(AD.globalNames(), short_branch->_matrule)) {
// The instructions are equivalent. // The instructions are equivalent.
// Now verify that both instructions have the same parameters and
// the same effects. Both branch forms should have the same inputs
// and resulting projections to correctly replace a long branch node
// with corresponding short branch node during code generation.
bool different = false;
if (short_branch->_components.count() != _components.count()) {
different = true;
} else if (_components.count() > 0) {
short_branch->_components.reset();
_components.reset();
Component *comp;
while ((comp = _components.iter()) != NULL) {
Component *short_comp = short_branch->_components.iter();
if (short_comp == NULL ||
short_comp->_type != comp->_type ||
short_comp->_usedef != comp->_usedef) {
different = true;
break;
}
}
if (short_branch->_components.iter() != NULL)
different = true;
}
if (different) {
globalAD->syntax_err(short_branch->_linenum, "Instruction %s and its short form %s have different parameters\n", _ident, short_branch->_ident);
}
if (AD._short_branch_debug) { if (AD._short_branch_debug) {
fprintf(stderr, "Instruction %s has short form %s\n", _ident, short_branch->_ident); fprintf(stderr, "Instruction %s has short form %s\n", _ident, short_branch->_ident);
} }

View file

@ -1536,12 +1536,16 @@ void ArchDesc::declareClasses(FILE *fp) {
// Each instruction attribute results in a virtual call of same name. // Each instruction attribute results in a virtual call of same name.
// The ins_cost is not handled here. // The ins_cost is not handled here.
Attribute *attr = instr->_attribs; Attribute *attr = instr->_attribs;
bool avoid_back_to_back = false;
while (attr != NULL) { while (attr != NULL) {
if (strcmp(attr->_ident,"ins_cost") && if (strcmp(attr->_ident,"ins_cost") &&
strcmp(attr->_ident,"ins_short_branch")) { strcmp(attr->_ident,"ins_short_branch")) {
fprintf(fp," int %s() const { return %s; }\n", fprintf(fp," int %s() const { return %s; }\n",
attr->_ident, attr->_val); attr->_ident, attr->_val);
} }
// Check value for ins_avoid_back_to_back, and if it is true (1), set the flag
if (!strcmp(attr->_ident,"ins_avoid_back_to_back") && attr->int_val(*this) != 0)
avoid_back_to_back = true;
attr = (Attribute *)attr->_next; attr = (Attribute *)attr->_next;
} }
@ -1704,6 +1708,16 @@ void ArchDesc::declareClasses(FILE *fp) {
} }
} }
// flag: if this instruction should not be generated back to back.
if ( avoid_back_to_back ) {
if ( node_flags_set ) {
fprintf(fp," | Flag_avoid_back_to_back");
} else {
fprintf(fp,"init_flags(Flag_avoid_back_to_back");
node_flags_set = true;
}
}
// Check if machine instructions that USE memory, but do not DEF memory, // Check if machine instructions that USE memory, but do not DEF memory,
// depend upon a node that defines memory in machine-independent graph. // depend upon a node that defines memory in machine-independent graph.
if ( instr->needs_anti_dependence_check(_globalNames) ) { if ( instr->needs_anti_dependence_check(_globalNames) ) {

View file

@ -80,35 +80,37 @@ void Block_List::print() {
uint Block::code_alignment() { uint Block::code_alignment() {
// Check for Root block // Check for Root block
if( _pre_order == 0 ) return CodeEntryAlignment; if (_pre_order == 0) return CodeEntryAlignment;
// Check for Start block // Check for Start block
if( _pre_order == 1 ) return InteriorEntryAlignment; if (_pre_order == 1) return InteriorEntryAlignment;
// Check for loop alignment // Check for loop alignment
if (has_loop_alignment()) return loop_alignment(); if (has_loop_alignment()) return loop_alignment();
return 1; // no particular alignment return relocInfo::addr_unit(); // no particular alignment
} }
uint Block::compute_loop_alignment() { uint Block::compute_loop_alignment() {
Node *h = head(); Node *h = head();
if( h->is_Loop() && h->as_Loop()->is_inner_loop() ) { int unit_sz = relocInfo::addr_unit();
if (h->is_Loop() && h->as_Loop()->is_inner_loop()) {
// Pre- and post-loops have low trip count so do not bother with // Pre- and post-loops have low trip count so do not bother with
// NOPs for align loop head. The constants are hidden from tuning // NOPs for align loop head. The constants are hidden from tuning
// but only because my "divide by 4" heuristic surely gets nearly // but only because my "divide by 4" heuristic surely gets nearly
// all possible gain (a "do not align at all" heuristic has a // all possible gain (a "do not align at all" heuristic has a
// chance of getting a really tiny gain). // chance of getting a really tiny gain).
if( h->is_CountedLoop() && (h->as_CountedLoop()->is_pre_loop() || if (h->is_CountedLoop() && (h->as_CountedLoop()->is_pre_loop() ||
h->as_CountedLoop()->is_post_loop()) ) h->as_CountedLoop()->is_post_loop())) {
return (OptoLoopAlignment > 4) ? (OptoLoopAlignment>>2) : 1; return (OptoLoopAlignment > 4*unit_sz) ? (OptoLoopAlignment>>2) : unit_sz;
}
// Loops with low backedge frequency should not be aligned. // Loops with low backedge frequency should not be aligned.
Node *n = h->in(LoopNode::LoopBackControl)->in(0); Node *n = h->in(LoopNode::LoopBackControl)->in(0);
if( n->is_MachIf() && n->as_MachIf()->_prob < 0.01 ) { if (n->is_MachIf() && n->as_MachIf()->_prob < 0.01) {
return 1; // Loop does not loop, more often than not! return unit_sz; // Loop does not loop, more often than not!
} }
return OptoLoopAlignment; // Otherwise align loop head return OptoLoopAlignment; // Otherwise align loop head
} }
return 1; // no particular alignment return unit_sz; // no particular alignment
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -271,55 +273,55 @@ bool Block::is_uncommon( Block_Array &bbs ) const {
//------------------------------dump------------------------------------------- //------------------------------dump-------------------------------------------
#ifndef PRODUCT #ifndef PRODUCT
void Block::dump_bidx(const Block* orig) const { void Block::dump_bidx(const Block* orig, outputStream* st) const {
if (_pre_order) tty->print("B%d",_pre_order); if (_pre_order) st->print("B%d",_pre_order);
else tty->print("N%d", head()->_idx); else st->print("N%d", head()->_idx);
if (Verbose && orig != this) { if (Verbose && orig != this) {
// Dump the original block's idx // Dump the original block's idx
tty->print(" ("); st->print(" (");
orig->dump_bidx(orig); orig->dump_bidx(orig, st);
tty->print(")"); st->print(")");
} }
} }
void Block::dump_pred(const Block_Array *bbs, Block* orig) const { void Block::dump_pred(const Block_Array *bbs, Block* orig, outputStream* st) const {
if (is_connector()) { if (is_connector()) {
for (uint i=1; i<num_preds(); i++) { for (uint i=1; i<num_preds(); i++) {
Block *p = ((*bbs)[pred(i)->_idx]); Block *p = ((*bbs)[pred(i)->_idx]);
p->dump_pred(bbs, orig); p->dump_pred(bbs, orig, st);
} }
} else { } else {
dump_bidx(orig); dump_bidx(orig, st);
tty->print(" "); st->print(" ");
} }
} }
void Block::dump_head( const Block_Array *bbs ) const { void Block::dump_head( const Block_Array *bbs, outputStream* st ) const {
// Print the basic block // Print the basic block
dump_bidx(this); dump_bidx(this, st);
tty->print(": #\t"); st->print(": #\t");
// Print the incoming CFG edges and the outgoing CFG edges // Print the incoming CFG edges and the outgoing CFG edges
for( uint i=0; i<_num_succs; i++ ) { for( uint i=0; i<_num_succs; i++ ) {
non_connector_successor(i)->dump_bidx(_succs[i]); non_connector_successor(i)->dump_bidx(_succs[i], st);
tty->print(" "); st->print(" ");
} }
tty->print("<- "); st->print("<- ");
if( head()->is_block_start() ) { if( head()->is_block_start() ) {
for (uint i=1; i<num_preds(); i++) { for (uint i=1; i<num_preds(); i++) {
Node *s = pred(i); Node *s = pred(i);
if (bbs) { if (bbs) {
Block *p = (*bbs)[s->_idx]; Block *p = (*bbs)[s->_idx];
p->dump_pred(bbs, p); p->dump_pred(bbs, p, st);
} else { } else {
while (!s->is_block_start()) while (!s->is_block_start())
s = s->in(0); s = s->in(0);
tty->print("N%d ", s->_idx ); st->print("N%d ", s->_idx );
} }
} }
} else } else
tty->print("BLOCK HEAD IS JUNK "); st->print("BLOCK HEAD IS JUNK ");
// Print loop, if any // Print loop, if any
const Block *bhead = this; // Head of self-loop const Block *bhead = this; // Head of self-loop
@ -330,24 +332,24 @@ void Block::dump_head( const Block_Array *bbs ) const {
while (bx->is_connector()) { while (bx->is_connector()) {
bx = (*bbs)[bx->pred(1)->_idx]; bx = (*bbs)[bx->pred(1)->_idx];
} }
tty->print("\tLoop: B%d-B%d ", bhead->_pre_order, bx->_pre_order); st->print("\tLoop: B%d-B%d ", bhead->_pre_order, bx->_pre_order);
// Dump any loop-specific bits, especially for CountedLoops. // Dump any loop-specific bits, especially for CountedLoops.
loop->dump_spec(tty); loop->dump_spec(st);
} else if (has_loop_alignment()) { } else if (has_loop_alignment()) {
tty->print(" top-of-loop"); st->print(" top-of-loop");
} }
tty->print(" Freq: %g",_freq); st->print(" Freq: %g",_freq);
if( Verbose || WizardMode ) { if( Verbose || WizardMode ) {
tty->print(" IDom: %d/#%d", _idom ? _idom->_pre_order : 0, _dom_depth); st->print(" IDom: %d/#%d", _idom ? _idom->_pre_order : 0, _dom_depth);
tty->print(" RegPressure: %d",_reg_pressure); st->print(" RegPressure: %d",_reg_pressure);
tty->print(" IHRP Index: %d",_ihrp_index); st->print(" IHRP Index: %d",_ihrp_index);
tty->print(" FRegPressure: %d",_freg_pressure); st->print(" FRegPressure: %d",_freg_pressure);
tty->print(" FHRP Index: %d",_fhrp_index); st->print(" FHRP Index: %d",_fhrp_index);
} }
tty->print_cr(""); st->print_cr("");
} }
void Block::dump() const { dump(0); } void Block::dump() const { dump(NULL); }
void Block::dump( const Block_Array *bbs ) const { void Block::dump( const Block_Array *bbs ) const {
dump_head(bbs); dump_head(bbs);
@ -441,9 +443,9 @@ uint PhaseCFG::build_cfg() {
Block *bb = new (_bbs._arena) Block(_bbs._arena,p); Block *bb = new (_bbs._arena) Block(_bbs._arena,p);
_bbs.map(p->_idx,bb); _bbs.map(p->_idx,bb);
_bbs.map(x->_idx,bb); _bbs.map(x->_idx,bb);
if( x != p ) // Only for root is x == p if( x != p ) { // Only for root is x == p
bb->_nodes.push((Node*)x); bb->_nodes.push((Node*)x);
}
// Now handle predecessors // Now handle predecessors
++sum; // Count 1 for self block ++sum; // Count 1 for self block
uint cnt = bb->num_preds(); uint cnt = bb->num_preds();

View file

@ -329,10 +329,10 @@ class Block : public CFGElement {
#ifndef PRODUCT #ifndef PRODUCT
// Debugging print of basic block // Debugging print of basic block
void dump_bidx(const Block* orig) const; void dump_bidx(const Block* orig, outputStream* st = tty) const;
void dump_pred(const Block_Array *bbs, Block* orig) const; void dump_pred(const Block_Array *bbs, Block* orig, outputStream* st = tty) const;
void dump_head( const Block_Array *bbs ) const; void dump_head( const Block_Array *bbs, outputStream* st = tty ) const;
void dump( ) const; void dump() const;
void dump( const Block_Array *bbs ) const; void dump( const Block_Array *bbs ) const;
#endif #endif
}; };

View file

@ -785,11 +785,17 @@ class Compile : public Phase {
// Process an OopMap Element while emitting nodes // Process an OopMap Element while emitting nodes
void Process_OopMap_Node(MachNode *mach, int code_offset); void Process_OopMap_Node(MachNode *mach, int code_offset);
// Initialize code buffer
CodeBuffer* init_buffer(uint* blk_starts);
// Write out basic block data to code buffer // Write out basic block data to code buffer
void Fill_buffer(); void fill_buffer(CodeBuffer* cb, uint* blk_starts);
// Determine which variable sized branches can be shortened // Determine which variable sized branches can be shortened
void Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size); void shorten_branches(uint* blk_starts, int& code_size, int& reloc_size, int& stub_size);
// Inserts nops where needed and final shorten branches.
void finalize_offsets_and_shorten(uint* blk_starts);
// Compute the size of first NumberOfLoopInstrToAlign instructions // Compute the size of first NumberOfLoopInstrToAlign instructions
// at the head of a loop. // at the head of a loop.

View file

@ -188,6 +188,9 @@ public:
virtual MachNode *short_branch_version(Compile* C) { return NULL; } virtual MachNode *short_branch_version(Compile* C) { return NULL; }
bool may_be_short_branch() const { return (flags() & Flag_may_be_short_branch) != 0; } bool may_be_short_branch() const { return (flags() & Flag_may_be_short_branch) != 0; }
// Avoid back to back some instructions on some CPUs.
bool avoid_back_to_back() const { return (flags() & Flag_avoid_back_to_back) != 0; }
// First index in _in[] corresponding to operand, or -1 if there is none // First index in _in[] corresponding to operand, or -1 if there is none
int operand_index(uint operand) const; int operand_index(uint operand) const;

View file

@ -351,7 +351,7 @@ public:
virtual int regnum_to_fpu_offset(int regnum); virtual int regnum_to_fpu_offset(int regnum);
// Is this branch offset small enough to be addressed by a short branch? // Is this branch offset small enough to be addressed by a short branch?
bool is_short_branch_offset(int rule, int offset); bool is_short_branch_offset(int rule, int br_size, int offset);
// Optional scaling for the parameter to the ClearArray/CopyArray node. // Optional scaling for the parameter to the ClearArray/CopyArray node.
static const bool init_array_count_is_in_bytes; static const bool init_array_count_is_in_bytes;

View file

@ -637,7 +637,8 @@ public:
Flag_is_Branch = Flag_is_cisc_alternate << 1, Flag_is_Branch = Flag_is_cisc_alternate << 1,
Flag_is_dead_loop_safe = Flag_is_Branch << 1, Flag_is_dead_loop_safe = Flag_is_Branch << 1,
Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1, Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1,
_max_flags = (Flag_may_be_short_branch << 1) - 1 // allow flags combination Flag_avoid_back_to_back = Flag_may_be_short_branch << 1,
_max_flags = (Flag_avoid_back_to_back << 1) - 1 // allow flags combination
}; };
private: private:

View file

@ -128,6 +128,14 @@ void Compile::Output() {
if ( ZapDeadCompiledLocals ) Insert_zap_nodes(); if ( ZapDeadCompiledLocals ) Insert_zap_nodes();
# endif # endif
uint* blk_starts = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks+1);
blk_starts[0] = 0;
// Initialize code buffer and process short branches.
CodeBuffer* cb = init_buffer(blk_starts);
if (cb == NULL || failing()) return;
ScheduleAndBundle(); ScheduleAndBundle();
#ifndef PRODUCT #ifndef PRODUCT
@ -148,11 +156,13 @@ void Compile::Output() {
if (failing()) return; if (failing()) return;
finalize_offsets_and_shorten(blk_starts);
BuildOopMaps(); BuildOopMaps();
if (failing()) return; if (failing()) return;
Fill_buffer(); fill_buffer(cb, blk_starts);
} }
bool Compile::need_stack_bang(int frame_size_in_bytes) const { bool Compile::need_stack_bang(int frame_size_in_bytes) const {
@ -325,22 +335,22 @@ void Compile::compute_loop_first_inst_sizes() {
} // if( MaxLoopPad < OptoLoopAlignment-1 ) } // if( MaxLoopPad < OptoLoopAlignment-1 )
} }
//----------------------Shorten_branches--------------------------------------- //----------------------shorten_branches---------------------------------------
// The architecture description provides short branch variants for some long // The architecture description provides short branch variants for some long
// branch instructions. Replace eligible long branches with short branches. // branch instructions. Replace eligible long branches with short branches.
void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size) { void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size, int& stub_size) {
// fill in the nop array for bundling computations
MachNode *_nop_list[Bundle::_nop_count];
Bundle::initialize_nops(_nop_list, this);
// ------------------ // ------------------
// Compute size of each block, method size, and relocation information size // Compute size of each block, method size, and relocation information size
uint *jmp_end = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks); uint nblocks = _cfg->_num_blocks;
uint *blk_starts = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks+1);
DEBUG_ONLY( uint *jmp_target = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks); ) uint* jmp_offset = NEW_RESOURCE_ARRAY(uint,nblocks);
DEBUG_ONLY( uint *jmp_rule = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks); ) uint* jmp_size = NEW_RESOURCE_ARRAY(uint,nblocks);
blk_starts[0] = 0; int* jmp_nidx = NEW_RESOURCE_ARRAY(int ,nblocks);
DEBUG_ONLY( uint *jmp_target = NEW_RESOURCE_ARRAY(uint,nblocks); )
DEBUG_ONLY( uint *jmp_rule = NEW_RESOURCE_ARRAY(uint,nblocks); )
bool has_short_branch_candidate = false;
// Initialize the sizes to 0 // Initialize the sizes to 0
code_size = 0; // Size in bytes of generated code code_size = 0; // Size in bytes of generated code
@ -350,28 +360,35 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
reloc_size = 1; // Number of relocation entries reloc_size = 1; // Number of relocation entries
// Make three passes. The first computes pessimistic blk_starts, // Make three passes. The first computes pessimistic blk_starts,
// relative jmp_end and reloc_size information. The second performs // relative jmp_offset and reloc_size information. The second performs
// short branch substitution using the pessimistic sizing. The // short branch substitution using the pessimistic sizing. The
// third inserts nops where needed. // third inserts nops where needed.
Node *nj; // tmp
// Step one, perform a pessimistic sizing pass. // Step one, perform a pessimistic sizing pass.
uint i; uint last_call_adr = max_uint;
uint min_offset_from_last_call = 1; // init to a positive value uint last_avoid_back_to_back_adr = max_uint;
uint nop_size = (new (this) MachNopNode())->size(_regalloc); uint nop_size = (new (this) MachNopNode())->size(_regalloc);
for( i=0; i<_cfg->_num_blocks; i++ ) { // For all blocks for (uint i = 0; i < nblocks; i++) { // For all blocks
Block *b = _cfg->_blocks[i]; Block *b = _cfg->_blocks[i];
// During short branch replacement, we store the relative (to blk_starts)
// offset of jump in jmp_offset, rather than the absolute offset of jump.
// This is so that we do not need to recompute sizes of all nodes when
// we compute correct blk_starts in our next sizing pass.
jmp_offset[i] = 0;
jmp_size[i] = 0;
jmp_nidx[i] = -1;
DEBUG_ONLY( jmp_target[i] = 0; )
DEBUG_ONLY( jmp_rule[i] = 0; )
// Sum all instruction sizes to compute block size // Sum all instruction sizes to compute block size
uint last_inst = b->_nodes.size(); uint last_inst = b->_nodes.size();
uint blk_size = 0; uint blk_size = 0;
for( uint j = 0; j<last_inst; j++ ) { for (uint j = 0; j < last_inst; j++) {
nj = b->_nodes[j]; Node* nj = b->_nodes[j];
uint inst_size = nj->size(_regalloc); uint inst_size = nj->size(_regalloc);
blk_size += inst_size;
// Handle machine instruction nodes // Handle machine instruction nodes
if( nj->is_Mach() ) { if (nj->is_Mach()) {
MachNode *mach = nj->as_Mach(); MachNode *mach = nj->as_Mach();
blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding
reloc_size += mach->reloc(); reloc_size += mach->reloc();
@ -388,32 +405,52 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
} else if (mach->is_MachSafePoint()) { } else if (mach->is_MachSafePoint()) {
// If call/safepoint are adjacent, account for possible // If call/safepoint are adjacent, account for possible
// nop to disambiguate the two safepoints. // nop to disambiguate the two safepoints.
if (min_offset_from_last_call == 0) { // ScheduleAndBundle() can rearrange nodes in a block,
// check for all offsets inside this block.
if (last_call_adr >= blk_starts[i]) {
blk_size += nop_size; blk_size += nop_size;
} }
} }
if (mach->avoid_back_to_back()) {
// Nop is inserted between "avoid back to back" instructions.
// ScheduleAndBundle() can rearrange nodes in a block,
// check for all offsets inside this block.
if (last_avoid_back_to_back_adr >= blk_starts[i]) {
blk_size += nop_size;
} }
min_offset_from_last_call += inst_size; }
if (mach->may_be_short_branch()) {
if (!nj->is_Branch()) {
#ifndef PRODUCT
nj->dump(3);
#endif
Unimplemented();
}
assert(jmp_nidx[i] == -1, "block should have only one branch");
jmp_offset[i] = blk_size;
jmp_size[i] = inst_size;
jmp_nidx[i] = j;
has_short_branch_candidate = true;
}
}
blk_size += inst_size;
// Remember end of call offset // Remember end of call offset
if (nj->is_MachCall() && !nj->is_MachCallLeaf()) { if (nj->is_MachCall() && !nj->is_MachCallLeaf()) {
min_offset_from_last_call = 0; last_call_adr = blk_starts[i]+blk_size;
}
// Remember end of avoid_back_to_back offset
if (nj->is_Mach() && nj->as_Mach()->avoid_back_to_back()) {
last_avoid_back_to_back_adr = blk_starts[i]+blk_size;
} }
} }
// During short branch replacement, we store the relative (to blk_starts)
// end of jump in jmp_end, rather than the absolute end of jump. This
// is so that we do not need to recompute sizes of all nodes when we compute
// correct blk_starts in our next sizing pass.
jmp_end[i] = blk_size;
DEBUG_ONLY( jmp_target[i] = 0; )
// When the next block starts a loop, we may insert pad NOP // When the next block starts a loop, we may insert pad NOP
// instructions. Since we cannot know our future alignment, // instructions. Since we cannot know our future alignment,
// assume the worst. // assume the worst.
if( i<_cfg->_num_blocks-1 ) { if (i< nblocks-1) {
Block *nb = _cfg->_blocks[i+1]; Block *nb = _cfg->_blocks[i+1];
int max_loop_pad = nb->code_alignment()-relocInfo::addr_unit(); int max_loop_pad = nb->code_alignment()-relocInfo::addr_unit();
if( max_loop_pad > 0 ) { if (max_loop_pad > 0) {
assert(is_power_of_2(max_loop_pad+relocInfo::addr_unit()), ""); assert(is_power_of_2(max_loop_pad+relocInfo::addr_unit()), "");
blk_size += max_loop_pad; blk_size += max_loop_pad;
} }
@ -424,124 +461,100 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
} }
// Step two, replace eligible long jumps. // Step two, replace eligible long jumps.
bool progress = true;
// Note: this will only get the long branches within short branch uint last_may_be_short_branch_adr = max_uint;
// range. Another pass might detect more branches that became while (has_short_branch_candidate && progress) {
// candidates because the shortening in the first pass exposed progress = false;
// more opportunities. Unfortunately, this would require has_short_branch_candidate = false;
// recomputing the starting and ending positions for the blocks int adjust_block_start = 0;
for( i=0; i<_cfg->_num_blocks; i++ ) { for (uint i = 0; i < nblocks; i++) {
Block *b = _cfg->_blocks[i]; Block *b = _cfg->_blocks[i];
int idx = jmp_nidx[i];
MachNode* mach = (idx == -1) ? NULL: b->_nodes[idx]->as_Mach();
if (mach != NULL && mach->may_be_short_branch()) {
#ifdef ASSERT
assert(jmp_size[i] > 0 && mach->is_Branch(), "sanity");
int j; int j;
// Find the branch; ignore trailing NOPs. // Find the branch; ignore trailing NOPs.
for( j = b->_nodes.size()-1; j>=0; j-- ) { for (j = b->_nodes.size()-1; j>=0; j--) {
nj = b->_nodes[j]; Node* n = b->_nodes[j];
if( !nj->is_Mach() || nj->as_Mach()->ideal_Opcode() != Op_Con ) if (!n->is_Mach() || n->as_Mach()->ideal_Opcode() != Op_Con)
break; break;
} }
assert(j >= 0 && j == idx && b->_nodes[j] == (Node*)mach, "sanity");
#endif
int br_size = jmp_size[i];
int br_offs = blk_starts[i] + jmp_offset[i];
if (j >= 0) {
if( nj->is_Mach() && nj->as_Mach()->may_be_short_branch() ) {
MachNode *mach = nj->as_Mach();
// This requires the TRUE branch target be in succs[0] // This requires the TRUE branch target be in succs[0]
uint bnum = b->non_connector_successor(0)->_pre_order; uint bnum = b->non_connector_successor(0)->_pre_order;
uintptr_t target = blk_starts[bnum]; int offset = blk_starts[bnum] - br_offs;
if( mach->is_Branch() ) { if (bnum > i) { // adjust following block's offset
int offset = target-(blk_starts[i] + jmp_end[i]); offset -= adjust_block_start;
if (_matcher->is_short_branch_offset(mach->rule(), offset)) { }
// In the following code a nop could be inserted before
// the branch which will increase the backward distance.
bool needs_padding = ((uint)br_offs == last_may_be_short_branch_adr);
if (needs_padding && offset <= 0)
offset -= nop_size;
if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) {
// We've got a winner. Replace this branch. // We've got a winner. Replace this branch.
MachNode* replacement = mach->short_branch_version(this); MachNode* replacement = mach->short_branch_version(this);
b->_nodes.map(j, replacement);
mach->subsume_by(replacement);
// Update the jmp_end size to save time in our // Update the jmp_size.
// next pass. int new_size = replacement->size(_regalloc);
jmp_end[i] -= (mach->size(_regalloc) - replacement->size(_regalloc)); int diff = br_size - new_size;
assert(diff >= (int)nop_size, "short_branch size should be smaller");
// Conservatively take into accound padding between
// avoid_back_to_back branches. Previous branch could be
// converted into avoid_back_to_back branch during next
// rounds.
if (needs_padding && replacement->avoid_back_to_back()) {
jmp_offset[i] += nop_size;
diff -= nop_size;
}
adjust_block_start += diff;
b->_nodes.map(idx, replacement);
mach->subsume_by(replacement);
mach = replacement;
progress = true;
jmp_size[i] = new_size;
DEBUG_ONLY( jmp_target[i] = bnum; ); DEBUG_ONLY( jmp_target[i] = bnum; );
DEBUG_ONLY( jmp_rule[i] = mach->rule(); ); DEBUG_ONLY( jmp_rule[i] = mach->rule(); );
}
} else { } else {
#ifndef PRODUCT // The jump distance is not short, try again during next iteration.
mach->dump(3); has_short_branch_candidate = true;
#endif
Unimplemented();
} }
} // (mach->may_be_short_branch())
if (mach != NULL && (mach->may_be_short_branch() ||
mach->avoid_back_to_back())) {
last_may_be_short_branch_adr = blk_starts[i] + jmp_offset[i] + jmp_size[i];
} }
} blk_starts[i+1] -= adjust_block_start;
}
// Compute the size of first NumberOfLoopInstrToAlign instructions at head
// of a loop. It is used to determine the padding for loop alignment.
compute_loop_first_inst_sizes();
// Step 3, compute the offsets of all the labels
uint last_call_adr = max_uint;
for( i=0; i<_cfg->_num_blocks; i++ ) { // For all blocks
// copy the offset of the beginning to the corresponding label
assert(labels[i].is_unused(), "cannot patch at this point");
labels[i].bind_loc(blk_starts[i], CodeBuffer::SECT_INSTS);
// insert padding for any instructions that need it
Block *b = _cfg->_blocks[i];
uint last_inst = b->_nodes.size();
uint adr = blk_starts[i];
for( uint j = 0; j<last_inst; j++ ) {
nj = b->_nodes[j];
if( nj->is_Mach() ) {
int padding = nj->as_Mach()->compute_padding(adr);
// If call/safepoint are adjacent insert a nop (5010568)
if (padding == 0 && nj->is_MachSafePoint() && !nj->is_MachCall() &&
adr == last_call_adr ) {
padding = nop_size;
}
if(padding > 0) {
assert((padding % nop_size) == 0, "padding is not a multiple of NOP size");
int nops_cnt = padding / nop_size;
MachNode *nop = new (this) MachNopNode(nops_cnt);
b->_nodes.insert(j++, nop);
_cfg->_bbs.map( nop->_idx, b );
adr += padding;
last_inst++;
}
}
adr += nj->size(_regalloc);
// Remember end of call offset
if (nj->is_MachCall() && !nj->is_MachCallLeaf()) {
last_call_adr = adr;
}
}
if ( i != _cfg->_num_blocks-1) {
// Get the size of the block
uint blk_size = adr - blk_starts[i];
// When the next block is the top of a loop, we may insert pad NOP
// instructions.
Block *nb = _cfg->_blocks[i+1];
int current_offset = blk_starts[i] + blk_size;
current_offset += nb->alignment_padding(current_offset);
// Save block size; update total method size
blk_starts[i+1] = current_offset;
} }
} }
#ifdef ASSERT #ifdef ASSERT
for( i=0; i<_cfg->_num_blocks; i++ ) { // For all blocks for (uint i = 0; i < nblocks; i++) { // For all blocks
if( jmp_target[i] != 0 ) { if (jmp_target[i] != 0) {
int offset = blk_starts[jmp_target[i]]-(blk_starts[i] + jmp_end[i]); int br_size = jmp_size[i];
if (!_matcher->is_short_branch_offset(jmp_rule[i], offset)) { int offset = blk_starts[jmp_target[i]]-(blk_starts[i] + jmp_offset[i]);
tty->print_cr("target (%d) - jmp_end(%d) = offset (%d), jmp_block B%d, target_block B%d", blk_starts[jmp_target[i]], blk_starts[i] + jmp_end[i], offset, i, jmp_target[i]); if (!_matcher->is_short_branch_offset(jmp_rule[i], br_size, offset)) {
tty->print_cr("target (%d) - jmp_offset(%d) = offset (%d), jump_size(%d), jmp_block B%d, target_block B%d", blk_starts[jmp_target[i]], blk_starts[i] + jmp_offset[i], offset, br_size, i, jmp_target[i]);
} }
assert(_matcher->is_short_branch_offset(jmp_rule[i], offset), "Displacement too large for short jmp"); assert(_matcher->is_short_branch_offset(jmp_rule[i], br_size, offset), "Displacement too large for short jmp");
} }
} }
#endif #endif
// Step 3, compute the offsets of all blocks, will be done in finalize_offsets_and_shorten()
// after ScheduleAndBundle().
// ------------------ // ------------------
// Compute size for code buffer // Compute size for code buffer
code_size = blk_starts[i-1] + jmp_end[i-1]; code_size = blk_starts[nblocks];
// Relocation records // Relocation records
reloc_size += 1; // Relo entry for exception handler reloc_size += 1; // Relo entry for exception handler
@ -553,6 +566,188 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
reloc_size *= 10 / sizeof(relocInfo); reloc_size *= 10 / sizeof(relocInfo);
} }
//----------------------finalize_offsets_and_shorten-------------------------
void Compile::finalize_offsets_and_shorten(uint* blk_starts) {
// blk_starts[] contains offsets calculated during short branches processing,
// offsets should not be increased during following steps.
// Compute the size of first NumberOfLoopInstrToAlign instructions at head
// of a loop. It is used to determine the padding for loop alignment.
compute_loop_first_inst_sizes();
uint nblocks = _cfg->_num_blocks;
#ifdef ASSERT
uint* jmp_target = NEW_RESOURCE_ARRAY(uint,nblocks);
uint* jmp_offset = NEW_RESOURCE_ARRAY(uint,nblocks);
uint* jmp_size = NEW_RESOURCE_ARRAY(uint,nblocks);
uint* jmp_rule = NEW_RESOURCE_ARRAY(uint,nblocks);
#endif
// Inserts nops where needed and do final short branches replacement.
uint nop_size = (new (this) MachNopNode())->size(_regalloc);
uint last_call_adr = max_uint;
uint last_avoid_back_to_back_adr = max_uint;
assert(blk_starts[0] == 0, "sanity");
uint current_offset = 0;
uint block_alignment_padding = 0;
for (uint i=0; i < nblocks; i++) { // For all blocks
Block *b = _cfg->_blocks[i];
#ifdef ASSERT
jmp_target[i] = 0;
jmp_offset[i] = 0;
jmp_size[i] = 0;
jmp_rule[i] = 0;
#endif
// Maximum alignment was added before loop block during
// Step One, as result padding for nodes was not added.
// Take this into account for block's size change check
// and allow increase block's size by the difference
// of maximum and actual alignment paddings.
DEBUG_ONLY( uint orig_blk_size = blk_starts[i+1] - blk_starts[i] + block_alignment_padding; )
uint blk_offset = current_offset;
uint last_inst = b->_nodes.size();
for (uint j = 0; j<last_inst; j++) {
Node* nj = b->_nodes[j];
if (valid_bundle_info(nj) &&
node_bundling(nj)->used_in_unconditional_delay()) {
continue; // Skip instruction in delay slot
}
uint inst_size = nj->size(_regalloc);
if (nj->is_Mach()) {
MachNode *mach = nj->as_Mach();
int padding = mach->compute_padding(current_offset);
// If call/safepoint are adjacent insert a nop (5010568)
if (padding == 0 && nj->is_MachSafePoint() && !nj->is_MachCall() &&
current_offset == last_call_adr) {
padding = nop_size;
}
// Inserted a nop between "avoid back to back" instructions.
if (padding == 0 && mach->avoid_back_to_back() &&
current_offset == last_avoid_back_to_back_adr) {
padding = nop_size;
}
if (padding > 0) {
assert((padding % nop_size) == 0, "padding is not a multiple of NOP size");
int nops_cnt = padding / nop_size;
MachNode *nop = new (this) MachNopNode(nops_cnt);
b->_nodes.insert(j++, nop);
_cfg->_bbs.map(nop->_idx, b);
last_inst++;
current_offset += padding;
}
// Try to replace long branch if delay slot is not used,
// it is mostly for back branches since forward branch's
// distance is not updated yet.
bool delay_slot_is_used = valid_bundle_info(nj) &&
node_bundling(nj)->use_unconditional_delay();
if (!delay_slot_is_used && mach->may_be_short_branch()) {
int br_size = inst_size;
// This requires the TRUE branch target be in succs[0]
uint bnum = b->non_connector_successor(0)->_pre_order;
int offset = blk_starts[bnum] - current_offset;
if (bnum >= i) {
// Current and following block's offset are not
// finilized yet, adjust distance.
offset -= (blk_starts[i] - blk_offset);
}
// In the following code a nop could be inserted before
// the branch which will increase the backward distance.
bool needs_padding = (current_offset == last_avoid_back_to_back_adr);
if (needs_padding && offset <= 0)
offset -= nop_size;
if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) {
// We've got a winner. Replace this branch.
MachNode* replacement = mach->short_branch_version(this);
// Update the jmp_size.
int new_size = replacement->size(_regalloc);
assert((br_size - new_size) >= (int)nop_size, "short_branch size should be smaller");
// Conservatively take into accound padding between
// avoid_back_to_back branches. Previous branch could be
// converted into avoid_back_to_back branch during next
// rounds.
if (needs_padding && replacement->avoid_back_to_back()) {
MachNode *nop = new (this) MachNopNode();
b->_nodes.insert(j++, nop);
_cfg->_bbs.map(nop->_idx, b);
last_inst++;
current_offset += nop_size;
}
inst_size = new_size;
b->_nodes.map(j, replacement);
mach->subsume_by(replacement);
nj = replacement;
#ifdef ASSERT
jmp_target[i] = bnum;
jmp_offset[i] = current_offset - blk_offset;
jmp_size[i] = new_size;
jmp_rule[i] = mach->rule();
#endif
}
}
}
current_offset += inst_size;
// Remember end of call offset
if (nj->is_MachCall() && !nj->is_MachCallLeaf()) {
last_call_adr = current_offset;
}
// Remember end of avoid_back_to_back offset
if (nj->is_Mach() && nj->as_Mach()->avoid_back_to_back()) {
last_avoid_back_to_back_adr = current_offset;
}
}
assert(blk_offset <= blk_starts[i], "shouldn't increase distance");
blk_starts[i] = blk_offset;
// When the next block is the top of a loop, we may insert pad NOP
// instructions.
if (i < nblocks-1) {
Block *nb = _cfg->_blocks[i+1];
int padding = nb->alignment_padding(current_offset);
if (padding > 0) {
assert((padding % nop_size) == 0, "padding is not a multiple of NOP size");
int nops_cnt = padding / nop_size;
MachNode *nop = new (this) MachNopNode(nops_cnt);
b->_nodes.insert(b->_nodes.size(), nop);
_cfg->_bbs.map(nop->_idx, b);
current_offset += padding;
}
int max_loop_pad = nb->code_alignment()-relocInfo::addr_unit();
assert(max_loop_pad >= padding, "sanity");
block_alignment_padding = max_loop_pad - padding;
}
assert(orig_blk_size >= (current_offset - blk_offset), "shouldn't increase block size");
}
blk_starts[nblocks] = current_offset;
#ifdef ASSERT
for (uint i = 0; i < nblocks; i++) { // For all blocks
if (jmp_target[i] != 0) {
int br_size = jmp_size[i];
int offset = blk_starts[jmp_target[i]]-(blk_starts[i] + jmp_offset[i]);
if (!_matcher->is_short_branch_offset(jmp_rule[i], br_size, offset)) {
tty->print_cr("target (%d) - jmp_offset(%d) = offset (%d), jump_size(%d), jmp_block B%d, target_block B%d", blk_starts[jmp_target[i]], blk_starts[i] + jmp_offset[i], offset, br_size, i, jmp_target[i]);
}
assert(_matcher->is_short_branch_offset(jmp_rule[i], br_size, offset), "Displacement too large for short jmp");
}
}
#endif
}
//------------------------------FillLocArray----------------------------------- //------------------------------FillLocArray-----------------------------------
// Create a bit of debug info and append it to the array. The mapping is from // Create a bit of debug info and append it to the array. The mapping is from
// Java local or expression stack to constant, register or stack-slot. For // Java local or expression stack to constant, register or stack-slot. For
@ -1026,7 +1221,7 @@ void NonSafepointEmitter::emit_non_safepoint() {
// helper for Fill_buffer bailout logic // helper for fill_buffer bailout logic
static void turn_off_compiler(Compile* C) { static void turn_off_compiler(Compile* C) {
if (CodeCache::largest_free_block() >= CodeCacheMinimumFreeSpace*10) { if (CodeCache::largest_free_block() >= CodeCacheMinimumFreeSpace*10) {
// Do not turn off compilation if a single giant method has // Do not turn off compilation if a single giant method has
@ -1039,22 +1234,20 @@ static void turn_off_compiler(Compile* C) {
} }
//------------------------------Fill_buffer------------------------------------ //------------------------------init_buffer------------------------------------
void Compile::Fill_buffer() { CodeBuffer* Compile::init_buffer(uint* blk_starts) {
// Set the initially allocated size // Set the initially allocated size
int code_req = initial_code_capacity; int code_req = initial_code_capacity;
int locs_req = initial_locs_capacity; int locs_req = initial_locs_capacity;
int stub_req = TraceJumps ? initial_stub_capacity * 10 : initial_stub_capacity; int stub_req = TraceJumps ? initial_stub_capacity * 10 : initial_stub_capacity;
int const_req = initial_const_capacity; int const_req = initial_const_capacity;
bool labels_not_set = true;
int pad_req = NativeCall::instruction_size; int pad_req = NativeCall::instruction_size;
// The extra spacing after the code is necessary on some platforms. // The extra spacing after the code is necessary on some platforms.
// Sometimes we need to patch in a jump after the last instruction, // Sometimes we need to patch in a jump after the last instruction,
// if the nmethod has been deoptimized. (See 4932387, 4894843.) // if the nmethod has been deoptimized. (See 4932387, 4894843.)
uint i;
// Compute the byte offset where we can store the deopt pc. // Compute the byte offset where we can store the deopt pc.
if (fixed_slots() != 0) { if (fixed_slots() != 0) {
_orig_pc_slot_offset_in_bytes = _regalloc->reg2offset(OptoReg::stack2reg(_orig_pc_slot)); _orig_pc_slot_offset_in_bytes = _regalloc->reg2offset(OptoReg::stack2reg(_orig_pc_slot));
@ -1078,19 +1271,12 @@ void Compile::Fill_buffer() {
_frame_slots += 8*(16/BytesPerInt); _frame_slots += 8*(16/BytesPerInt);
} }
#endif #endif
assert( _frame_slots >= 0 && _frame_slots < 1000000, "sanity check" ); assert(_frame_slots >= 0 && _frame_slots < 1000000, "sanity check");
// Create an array of unused labels, one for each basic block
Label *blk_labels = NEW_RESOURCE_ARRAY(Label, _cfg->_num_blocks+1);
for( i=0; i <= _cfg->_num_blocks; i++ ) {
blk_labels[i].init();
}
if (has_mach_constant_base_node()) { if (has_mach_constant_base_node()) {
// Fill the constant table. // Fill the constant table.
// Note: This must happen before Shorten_branches. // Note: This must happen before shorten_branches.
for (i = 0; i < _cfg->_num_blocks; i++) { for (uint i = 0; i < _cfg->_num_blocks; i++) {
Block* b = _cfg->_blocks[i]; Block* b = _cfg->_blocks[i];
for (uint j = 0; j < b->_nodes.size(); j++) { for (uint j = 0; j < b->_nodes.size(); j++) {
@ -1114,14 +1300,11 @@ void Compile::Fill_buffer() {
// Initialize the space for the BufferBlob used to find and verify // Initialize the space for the BufferBlob used to find and verify
// instruction size in MachNode::emit_size() // instruction size in MachNode::emit_size()
init_scratch_buffer_blob(const_req); init_scratch_buffer_blob(const_req);
if (failing()) return; // Out of memory if (failing()) return NULL; // Out of memory
// If this machine supports different size branch offsets, then pre-compute // Pre-compute the length of blocks and replace
// the length of the blocks // long branches with short if machine supports it.
if( _matcher->is_short_branch_offset(-1, 0) ) { shorten_branches(blk_starts, code_req, locs_req, stub_req);
Shorten_branches(blk_labels, code_req, locs_req, stub_req);
labels_not_set = false;
}
// nmethod and CodeBuffer count stubs & constants as part of method's code. // nmethod and CodeBuffer count stubs & constants as part of method's code.
int exception_handler_req = size_exception_handler(); int exception_handler_req = size_exception_handler();
@ -1151,7 +1334,7 @@ void Compile::Fill_buffer() {
// Have we run out of code space? // Have we run out of code space?
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) { if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
turn_off_compiler(this); turn_off_compiler(this);
return; return NULL;
} }
// Configure the code buffer. // Configure the code buffer.
cb->initialize_consts_size(const_req); cb->initialize_consts_size(const_req);
@ -1162,6 +1345,12 @@ void Compile::Fill_buffer() {
MachNode *_nop_list[Bundle::_nop_count]; MachNode *_nop_list[Bundle::_nop_count];
Bundle::initialize_nops(_nop_list, this); Bundle::initialize_nops(_nop_list, this);
return cb;
}
//------------------------------fill_buffer------------------------------------
void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
// Create oopmap set. // Create oopmap set.
_oop_map_set = new OopMapSet(); _oop_map_set = new OopMapSet();
@ -1180,15 +1369,16 @@ void Compile::Fill_buffer() {
int previous_offset = 0; int previous_offset = 0;
int current_offset = 0; int current_offset = 0;
#ifdef ASSERT
int last_call_offset = -1; int last_call_offset = -1;
int last_avoid_back_to_back_offset = -1;
#endif
// Create an array of unused labels, one for each basic block, if printing is enabled // Create an array of unused labels, one for each basic block, if printing is enabled
#ifndef PRODUCT #ifndef PRODUCT
int *node_offsets = NULL; int *node_offsets = NULL;
uint node_offset_limit = unique(); uint node_offset_limit = unique();
if (print_assembly())
if ( print_assembly() )
node_offsets = NEW_RESOURCE_ARRAY(int, node_offset_limit); node_offsets = NEW_RESOURCE_ARRAY(int, node_offset_limit);
#endif #endif
@ -1199,11 +1389,19 @@ void Compile::Fill_buffer() {
constant_table().emit(*cb); constant_table().emit(*cb);
} }
// Create an array of labels, one for each basic block
Label *blk_labels = NEW_RESOURCE_ARRAY(Label, _cfg->_num_blocks+1);
for (uint i=0; i <= _cfg->_num_blocks; i++) {
blk_labels[i].init();
}
// ------------------ // ------------------
// Now fill in the code buffer // Now fill in the code buffer
Node *delay_slot = NULL; Node *delay_slot = NULL;
for( i=0; i < _cfg->_num_blocks; i++ ) { for (uint i=0; i < _cfg->_num_blocks; i++) {
guarantee(blk_starts[i] == (uint)cb->insts_size(),"should not change size");
Block *b = _cfg->_blocks[i]; Block *b = _cfg->_blocks[i];
Node *head = b->head(); Node *head = b->head();
@ -1211,23 +1409,25 @@ void Compile::Fill_buffer() {
// If this block needs to start aligned (i.e, can be reached other // If this block needs to start aligned (i.e, can be reached other
// than by falling-thru from the previous block), then force the // than by falling-thru from the previous block), then force the
// start of a new bundle. // start of a new bundle.
if( Pipeline::requires_bundling() && starts_bundle(head) ) if (Pipeline::requires_bundling() && starts_bundle(head))
cb->flush_bundle(true); cb->flush_bundle(true);
// Define the label at the beginning of the basic block #ifdef ASSERT
if (labels_not_set) { if (!b->is_connector()) {
MacroAssembler(cb).bind(blk_labels[b->_pre_order]); stringStream st;
} else { b->dump_head(&_cfg->_bbs, &st);
assert(blk_labels[b->_pre_order].loc_pos() == cb->insts_size(), MacroAssembler(cb).block_comment(st.as_string());
err_msg("label position does not match code offset: %d != %d",
blk_labels[b->_pre_order].loc_pos(), cb->insts_size()));
} }
#endif
// Define the label at the beginning of the basic block
MacroAssembler(cb).bind(blk_labels[b->_pre_order]);
uint last_inst = b->_nodes.size(); uint last_inst = b->_nodes.size();
// Emit block normally, except for last instruction. // Emit block normally, except for last instruction.
// Emit means "dump code bits into code buffer". // Emit means "dump code bits into code buffer".
for( uint j = 0; j<last_inst; j++ ) { for (uint j = 0; j<last_inst; j++) {
// Get the node // Get the node
Node* n = b->_nodes[j]; Node* n = b->_nodes[j];
@ -1244,7 +1444,7 @@ void Compile::Fill_buffer() {
// If this starts a new instruction group, then flush the current one // If this starts a new instruction group, then flush the current one
// (but allow split bundles) // (but allow split bundles)
if( Pipeline::requires_bundling() && starts_bundle(n) ) if (Pipeline::requires_bundling() && starts_bundle(n))
cb->flush_bundle(false); cb->flush_bundle(false);
// The following logic is duplicated in the code ifdeffed for // The following logic is duplicated in the code ifdeffed for
@ -1253,38 +1453,35 @@ void Compile::Fill_buffer() {
// Special handling for SafePoint/Call Nodes // Special handling for SafePoint/Call Nodes
bool is_mcall = false; bool is_mcall = false;
if( n->is_Mach() ) { if (n->is_Mach()) {
MachNode *mach = n->as_Mach(); MachNode *mach = n->as_Mach();
is_mcall = n->is_MachCall(); is_mcall = n->is_MachCall();
bool is_sfn = n->is_MachSafePoint(); bool is_sfn = n->is_MachSafePoint();
// If this requires all previous instructions be flushed, then do so // If this requires all previous instructions be flushed, then do so
if( is_sfn || is_mcall || mach->alignment_required() != 1) { if (is_sfn || is_mcall || mach->alignment_required() != 1) {
cb->flush_bundle(true); cb->flush_bundle(true);
current_offset = cb->insts_size(); current_offset = cb->insts_size();
} }
#ifdef ASSERT
// A padding may be needed again since a previous instruction
// could be moved to delay slot.
// align the instruction if necessary // align the instruction if necessary
int padding = mach->compute_padding(current_offset); int padding = mach->compute_padding(current_offset);
// Make sure safepoint node for polling is distinct from a call's // Make sure safepoint node for polling is distinct from a call's
// return by adding a nop if needed. // return by adding a nop if needed.
if (is_sfn && !is_mcall && padding == 0 && current_offset == last_call_offset ) { if (is_sfn && !is_mcall && padding == 0 && current_offset == last_call_offset) {
padding = nop_size; padding = nop_size;
} }
assert( labels_not_set || padding == 0, "instruction should already be aligned"); if (padding == 0 && mach->avoid_back_to_back() &&
current_offset == last_avoid_back_to_back_offset) {
if(padding > 0) { // Avoid back to back some instructions.
assert((padding % nop_size) == 0, "padding is not a multiple of NOP size"); padding = nop_size;
int nops_cnt = padding / nop_size;
MachNode *nop = new (this) MachNopNode(nops_cnt);
b->_nodes.insert(j++, nop);
last_inst++;
_cfg->_bbs.map( nop->_idx, b );
nop->emit(*cb, _regalloc);
cb->flush_bundle(true);
current_offset = cb->insts_size();
} }
assert(padding == 0, "padding should be added already");
#endif
// Remember the start of the last call in a basic block // Remember the start of the last call in a basic block
if (is_mcall) { if (is_mcall) {
MachCallNode *mcall = mach->as_MachCall(); MachCallNode *mcall = mach->as_MachCall();
@ -1302,13 +1499,13 @@ void Compile::Fill_buffer() {
} }
// sfn will be valid whenever mcall is valid now because of inheritance // sfn will be valid whenever mcall is valid now because of inheritance
if( is_sfn || is_mcall ) { if (is_sfn || is_mcall) {
// Handle special safepoint nodes for synchronization // Handle special safepoint nodes for synchronization
if( !is_mcall ) { if (!is_mcall) {
MachSafePointNode *sfn = mach->as_MachSafePoint(); MachSafePointNode *sfn = mach->as_MachSafePoint();
// !!!!! Stubs only need an oopmap right now, so bail out // !!!!! Stubs only need an oopmap right now, so bail out
if( sfn->jvms()->method() == NULL) { if (sfn->jvms()->method() == NULL) {
// Write the oopmap directly to the code blob??!! // Write the oopmap directly to the code blob??!!
# ifdef ENABLE_ZAP_DEAD_LOCALS # ifdef ENABLE_ZAP_DEAD_LOCALS
assert( !is_node_getting_a_safepoint(sfn), "logic does not match; false positive"); assert( !is_node_getting_a_safepoint(sfn), "logic does not match; false positive");
@ -1328,14 +1525,14 @@ void Compile::Fill_buffer() {
} }
// If this is a branch, then fill in the label with the target BB's label // If this is a branch, then fill in the label with the target BB's label
else if ( mach->is_Branch() ) { else if (mach->is_Branch()) {
if ( mach->ideal_Opcode() == Op_Jump ) { if (mach->ideal_Opcode() == Op_Jump) {
for (uint h = 0; h < b->_num_succs; h++ ) { for (uint h = 0; h < b->_num_succs; h++) {
Block* succs_block = b->_succs[h]; Block* succs_block = b->_succs[h];
for (uint j = 1; j < succs_block->num_preds(); j++) { for (uint j = 1; j < succs_block->num_preds(); j++) {
Node* jpn = succs_block->pred(j); Node* jpn = succs_block->pred(j);
if ( jpn->is_JumpProj() && jpn->in(0) == mach ) { if (jpn->is_JumpProj() && jpn->in(0) == mach) {
uint block_num = succs_block->non_connector()->_pre_order; uint block_num = succs_block->non_connector()->_pre_order;
Label *blkLabel = &blk_labels[block_num]; Label *blkLabel = &blk_labels[block_num];
mach->add_case_label(jpn->as_JumpProj()->proj_no(), blkLabel); mach->add_case_label(jpn->as_JumpProj()->proj_no(), blkLabel);
@ -1352,7 +1549,7 @@ void Compile::Fill_buffer() {
#ifdef ASSERT #ifdef ASSERT
// Check that oop-store precedes the card-mark // Check that oop-store precedes the card-mark
else if( mach->ideal_Opcode() == Op_StoreCM ) { else if (mach->ideal_Opcode() == Op_StoreCM) {
uint storeCM_idx = j; uint storeCM_idx = j;
int count = 0; int count = 0;
for (uint prec = mach->req(); prec < mach->len(); prec++) { for (uint prec = mach->req(); prec < mach->len(); prec++) {
@ -1371,7 +1568,7 @@ void Compile::Fill_buffer() {
} }
#endif #endif
else if( !n->is_Proj() ) { else if (!n->is_Proj()) {
// Remember the beginning of the previous instruction, in case // Remember the beginning of the previous instruction, in case
// it's followed by a flag-kill and a null-check. Happens on // it's followed by a flag-kill and a null-check. Happens on
// Intel all the time, with add-to-memory kind of opcodes. // Intel all the time, with add-to-memory kind of opcodes.
@ -1388,15 +1585,24 @@ void Compile::Fill_buffer() {
// Save the offset for the listing // Save the offset for the listing
#ifndef PRODUCT #ifndef PRODUCT
if( node_offsets && n->_idx < node_offset_limit ) if (node_offsets && n->_idx < node_offset_limit)
node_offsets[n->_idx] = cb->insts_size(); node_offsets[n->_idx] = cb->insts_size();
#endif #endif
// "Normal" instruction case // "Normal" instruction case
DEBUG_ONLY( uint instr_offset = cb->insts_size(); )
n->emit(*cb, _regalloc); n->emit(*cb, _regalloc);
current_offset = cb->insts_size(); current_offset = cb->insts_size();
#ifdef ASSERT
if (n->size(_regalloc) != (current_offset-instr_offset)) {
n->dump();
assert(n->size(_regalloc) == (current_offset-instr_offset), "wrong size of mach node");
}
#endif
non_safepoints.observe_instruction(n, current_offset); non_safepoints.observe_instruction(n, current_offset);
#ifdef ASSERT
// mcall is last "call" that can be a safepoint // mcall is last "call" that can be a safepoint
// record it so we can see if a poll will directly follow it // record it so we can see if a poll will directly follow it
// in which case we'll need a pad to make the PcDesc sites unique // in which case we'll need a pad to make the PcDesc sites unique
@ -1408,8 +1614,14 @@ void Compile::Fill_buffer() {
last_call_offset = current_offset; last_call_offset = current_offset;
} }
if (n->is_Mach() && n->as_Mach()->avoid_back_to_back()) {
// Avoid back to back some instructions.
last_avoid_back_to_back_offset = current_offset;
}
#endif
// See if this instruction has a delay slot // See if this instruction has a delay slot
if ( valid_bundle_info(n) && node_bundling(n)->use_unconditional_delay()) { if (valid_bundle_info(n) && node_bundling(n)->use_unconditional_delay()) {
assert(delay_slot != NULL, "expecting delay slot node"); assert(delay_slot != NULL, "expecting delay slot node");
// Back up 1 instruction // Back up 1 instruction
@ -1417,15 +1629,15 @@ void Compile::Fill_buffer() {
// Save the offset for the listing // Save the offset for the listing
#ifndef PRODUCT #ifndef PRODUCT
if( node_offsets && delay_slot->_idx < node_offset_limit ) if (node_offsets && delay_slot->_idx < node_offset_limit)
node_offsets[delay_slot->_idx] = cb->insts_size(); node_offsets[delay_slot->_idx] = cb->insts_size();
#endif #endif
// Support a SafePoint in the delay slot // Support a SafePoint in the delay slot
if( delay_slot->is_MachSafePoint() ) { if (delay_slot->is_MachSafePoint()) {
MachNode *mach = delay_slot->as_Mach(); MachNode *mach = delay_slot->as_Mach();
// !!!!! Stubs only need an oopmap right now, so bail out // !!!!! Stubs only need an oopmap right now, so bail out
if( !mach->is_MachCall() && mach->as_MachSafePoint()->jvms()->method() == NULL ) { if (!mach->is_MachCall() && mach->as_MachSafePoint()->jvms()->method() == NULL) {
// Write the oopmap directly to the code blob??!! // Write the oopmap directly to the code blob??!!
# ifdef ENABLE_ZAP_DEAD_LOCALS # ifdef ENABLE_ZAP_DEAD_LOCALS
assert( !is_node_getting_a_safepoint(mach), "logic does not match; false positive"); assert( !is_node_getting_a_safepoint(mach), "logic does not match; false positive");
@ -1449,21 +1661,15 @@ void Compile::Fill_buffer() {
} }
} // End for all instructions in block } // End for all instructions in block
#ifdef ASSERT
// If the next block is the top of a loop, pad this block out to align // If the next block is the top of a loop, pad this block out to align
// the loop top a little. Helps prevent pipe stalls at loop back branches. // the loop top a little. Helps prevent pipe stalls at loop back branches.
if( i<_cfg->_num_blocks-1 ) { if (i < _cfg->_num_blocks-1) {
Block *nb = _cfg->_blocks[i+1]; Block *nb = _cfg->_blocks[i+1];
uint padding = nb->alignment_padding(current_offset); uint padding = nb->alignment_padding(current_offset);
if( padding > 0 ) { assert(padding == 0, "alignment should be added already");
MachNode *nop = new (this) MachNopNode(padding / nop_size);
b->_nodes.insert( b->_nodes.size(), nop );
_cfg->_bbs.map( nop->_idx, b );
nop->emit(*cb, _regalloc);
current_offset = cb->insts_size();
} }
} #endif
} // End of for all blocks } // End of for all blocks
non_safepoints.flush_at_end(); non_safepoints.flush_at_end();
@ -1743,11 +1949,6 @@ void Compile::ScheduleAndBundle() {
// Create a data structure for all the scheduling information // Create a data structure for all the scheduling information
Scheduling scheduling(Thread::current()->resource_area(), *this); Scheduling scheduling(Thread::current()->resource_area(), *this);
// Initialize the space for the BufferBlob used to find and verify
// instruction size in MachNode::emit_size()
init_scratch_buffer_blob(MAX_const_size);
if (failing()) return; // Out of memory
// Walk backwards over each basic block, computing the needed alignment // Walk backwards over each basic block, computing the needed alignment
// Walk over all the basic blocks // Walk over all the basic blocks
scheduling.DoScheduling(); scheduling.DoScheduling();
@ -2346,6 +2547,12 @@ void Scheduling::DoScheduling() {
// have their delay slots filled in the template expansions, so we don't // have their delay slots filled in the template expansions, so we don't
// bother scheduling them. // bother scheduling them.
Node *last = bb->_nodes[_bb_end]; Node *last = bb->_nodes[_bb_end];
// Ignore trailing NOPs.
while (_bb_end > 0 && last->is_Mach() &&
last->as_Mach()->ideal_Opcode() == Op_Con) {
last = bb->_nodes[--_bb_end];
}
assert(!last->is_Mach() || last->as_Mach()->ideal_Opcode() != Op_Con, "");
if( last->is_Catch() || if( last->is_Catch() ||
// Exclude unreachable path case when Halt node is in a separate block. // Exclude unreachable path case when Halt node is in a separate block.
(_bb_end > 1 && last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) { (_bb_end > 1 && last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) {
@ -2680,6 +2887,23 @@ void Scheduling::ComputeRegisterAntidependencies(Block *b) {
anti_do_def( b, n, _regalloc->get_reg_second(n), is_def ); anti_do_def( b, n, _regalloc->get_reg_second(n), is_def );
} }
// Kill projections on a branch should appear to occur on the
// branch, not afterwards, so grab the masks from the projections
// and process them.
if (n->is_Branch()) {
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* use = n->fast_out(i);
if (use->is_Proj()) {
RegMask rm = use->out_RegMask();// Make local copy
while( rm.is_NotEmpty() ) {
OptoReg::Name kill = rm.find_first_elem();
rm.Remove(kill);
anti_do_def( b, n, kill, false );
}
}
}
}
// Check each register used by this instruction for a following DEF/KILL // Check each register used by this instruction for a following DEF/KILL
// that must occur afterward and requires an anti-dependence edge. // that must occur afterward and requires an anti-dependence edge.
for( uint j=0; j<n->req(); j++ ) { for( uint j=0; j<n->req(); j++ ) {