mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
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:
parent
52f678435a
commit
ac99f413d7
20 changed files with 1298 additions and 500 deletions
|
@ -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 );
|
||||||
|
|
|
@ -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
|
||||||
//
|
//
|
||||||
|
|
|
@ -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" : "")),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) ) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
min_offset_from_last_call += inst_size;
|
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;
|
||||||
|
uint last_may_be_short_branch_adr = max_uint;
|
||||||
|
while (has_short_branch_candidate && progress) {
|
||||||
|
progress = false;
|
||||||
|
has_short_branch_candidate = false;
|
||||||
|
int adjust_block_start = 0;
|
||||||
|
for (uint i = 0; i < nblocks; 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;
|
||||||
|
// Find the branch; ignore trailing NOPs.
|
||||||
|
for (j = b->_nodes.size()-1; j>=0; j--) {
|
||||||
|
Node* n = b->_nodes[j];
|
||||||
|
if (!n->is_Mach() || n->as_Mach()->ideal_Opcode() != Op_Con)
|
||||||
|
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];
|
||||||
|
|
||||||
// Note: this will only get the long branches within short branch
|
|
||||||
// range. Another pass might detect more branches that became
|
|
||||||
// candidates because the shortening in the first pass exposed
|
|
||||||
// more opportunities. Unfortunately, this would require
|
|
||||||
// recomputing the starting and ending positions for the blocks
|
|
||||||
for( i=0; i<_cfg->_num_blocks; i++ ) {
|
|
||||||
Block *b = _cfg->_blocks[i];
|
|
||||||
|
|
||||||
int j;
|
|
||||||
// Find the branch; ignore trailing NOPs.
|
|
||||||
for( j = b->_nodes.size()-1; j>=0; j-- ) {
|
|
||||||
nj = b->_nodes[j];
|
|
||||||
if( !nj->is_Mach() || nj->as_Mach()->ideal_Opcode() != Op_Con )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) {
|
}
|
||||||
// We've got a winner. Replace this branch.
|
// In the following code a nop could be inserted before
|
||||||
MachNode* replacement = mach->short_branch_version(this);
|
// the branch which will increase the backward distance.
|
||||||
b->_nodes.map(j, replacement);
|
bool needs_padding = ((uint)br_offs == last_may_be_short_branch_adr);
|
||||||
mach->subsume_by(replacement);
|
if (needs_padding && offset <= 0)
|
||||||
|
offset -= nop_size;
|
||||||
|
|
||||||
// Update the jmp_end size to save time in our
|
if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) {
|
||||||
// next pass.
|
// We've got a winner. Replace this branch.
|
||||||
jmp_end[i] -= (mach->size(_regalloc) - replacement->size(_regalloc));
|
MachNode* replacement = mach->short_branch_version(this);
|
||||||
DEBUG_ONLY( jmp_target[i] = bnum; );
|
|
||||||
DEBUG_ONLY( jmp_rule[i] = mach->rule(); );
|
// Update the jmp_size.
|
||||||
|
int new_size = 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_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
|
||||||
|
@ -550,7 +563,189 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
|
||||||
// Min is 2 bytes, max is probably 6 or 8, with a tax up to 25% for
|
// Min is 2 bytes, max is probably 6 or 8, with a tax up to 25% for
|
||||||
// a relocation index.
|
// a relocation index.
|
||||||
// The CodeBuffer will expand the locs array if this estimate is too low.
|
// The CodeBuffer will expand the locs array if this estimate is too low.
|
||||||
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-----------------------------------
|
||||||
|
@ -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++ ) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue