8136820: Generate better code for some Unsafe addressing patterns

Reshape address computation to move invariant part out of loops

Reviewed-by: kvn
This commit is contained in:
Roland Westrelin 2015-09-17 16:53:42 +02:00
parent 4af470b866
commit f8abd0e843
4 changed files with 79 additions and 37 deletions

View file

@ -3767,6 +3767,22 @@ operand indIndexScale(any_RegP reg, rRegL lreg, immI2 scale)
%} %}
%} %}
operand indPosIndexScale(any_RegP reg, rRegI idx, immI2 scale)
%{
constraint(ALLOC_IN_RC(ptr_reg));
predicate(n->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0);
match(AddP reg (LShiftL (ConvI2L idx) scale));
op_cost(10);
format %{"[$reg + pos $idx << $scale]" %}
interface(MEMORY_INTER) %{
base($reg);
index($idx);
scale($scale);
disp(0x0);
%}
%}
// Indirect Memory Times Scale Plus Index Register Plus Offset Operand // Indirect Memory Times Scale Plus Index Register Plus Offset Operand
operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale) operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale)
%{ %{
@ -4159,7 +4175,7 @@ operand cmpOpUCF2() %{
// case of this is memory operands. // case of this is memory operands.
opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex,
indIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, indIndexScale, indPosIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset,
indCompressedOopOffset, indCompressedOopOffset,
indirectNarrow, indOffset8Narrow, indOffset32Narrow, indirectNarrow, indOffset8Narrow, indOffset32Narrow,
indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow,
@ -5186,6 +5202,17 @@ instruct leaPIdxScale(rRegP dst, indIndexScale mem)
ins_pipe(ialu_reg_reg_fat); ins_pipe(ialu_reg_reg_fat);
%} %}
instruct leaPPosIdxScale(rRegP dst, indPosIndexScale mem)
%{
match(Set dst mem);
ins_cost(110);
format %{ "leaq $dst, $mem\t# ptr idxscale" %}
opcode(0x8D);
ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem));
ins_pipe(ialu_reg_reg_fat);
%}
instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem) instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem)
%{ %{
match(Set dst mem); match(Set dst mem);

View file

@ -447,21 +447,21 @@ Node *PhaseIdealLoop::remix_address_expressions( Node *n ) {
} }
// Replace (I1 +p (I2 + V)) with ((I1 +p I2) +p V) // Replace (I1 +p (I2 + V)) with ((I1 +p I2) +p V)
if( n2_loop != n_loop && n3_loop == n_loop ) { if (n2_loop != n_loop && n3_loop == n_loop) {
if( n->in(3)->Opcode() == Op_AddI ) { if (n->in(3)->Opcode() == Op_AddX) {
Node *V = n->in(3)->in(1); Node *V = n->in(3)->in(1);
Node *I = n->in(3)->in(2); Node *I = n->in(3)->in(2);
if( is_member(n_loop,get_ctrl(V)) ) { if (is_member(n_loop,get_ctrl(V))) {
} else { } else {
Node *tmp = V; V = I; I = tmp; Node *tmp = V; V = I; I = tmp;
} }
if( !is_member(n_loop,get_ctrl(I)) ) { if (!is_member(n_loop,get_ctrl(I))) {
Node *add1 = new AddPNode( n->in(1), n->in(2), I ); Node *add1 = new AddPNode(n->in(1), n->in(2), I);
// Stuff new AddP in the loop preheader // Stuff new AddP in the loop preheader
register_new_node( add1, n_loop->_head->in(LoopNode::EntryControl) ); register_new_node(add1, n_loop->_head->in(LoopNode::EntryControl));
Node *add2 = new AddPNode( n->in(1), add1, V ); Node *add2 = new AddPNode(n->in(1), add1, V);
register_new_node( add2, n_ctrl ); register_new_node(add2, n_ctrl);
_igvn.replace_node( n, add2 ); _igvn.replace_node(n, add2);
return add2; return add2;
} }
} }

View file

@ -2045,6 +2045,33 @@ bool Matcher::is_bmi_pattern(Node *n, Node *m) {
// and then expanded into the inline_cache_reg and a method_oop register // and then expanded into the inline_cache_reg and a method_oop register
// defined in ad_<arch>.cpp // defined in ad_<arch>.cpp
// Check for shift by small constant as well
static bool clone_shift(Node* shift, Matcher* matcher, MStack& mstack, VectorSet& address_visited) {
if (shift->Opcode() == Op_LShiftX && shift->in(2)->is_Con() &&
shift->in(2)->get_int() <= 3 &&
// Are there other uses besides address expressions?
!matcher->is_visited(shift)) {
address_visited.set(shift->_idx); // Flag as address_visited
mstack.push(shift->in(2), Visit);
Node *conv = shift->in(1);
#ifdef _LP64
// Allow Matcher to match the rule which bypass
// ConvI2L operation for an array index on LP64
// if the index value is positive.
if (conv->Opcode() == Op_ConvI2L &&
conv->as_Type()->type()->is_long()->_lo >= 0 &&
// Are there other uses besides address expressions?
!matcher->is_visited(conv)) {
address_visited.set(conv->_idx); // Flag as address_visited
mstack.push(conv->in(1), Pre_Visit);
} else
#endif
mstack.push(conv, Pre_Visit);
return true;
}
return false;
}
//------------------------------find_shared------------------------------------ //------------------------------find_shared------------------------------------
// Set bits if Node is shared or otherwise a root // Set bits if Node is shared or otherwise a root
@ -2205,7 +2232,10 @@ void Matcher::find_shared( Node *n ) {
#endif #endif
// Clone addressing expressions as they are "free" in memory access instructions // Clone addressing expressions as they are "free" in memory access instructions
if( mem_op && i == MemNode::Address && mop == Op_AddP ) { if (mem_op && i == MemNode::Address && mop == Op_AddP &&
// When there are other uses besides address expressions
// put it on stack and mark as shared.
!is_visited(m)) {
// Some inputs for address expression are not put on stack // Some inputs for address expression are not put on stack
// to avoid marking them as shared and forcing them into register // to avoid marking them as shared and forcing them into register
// if they are used only in address expressions. // if they are used only in address expressions.
@ -2213,10 +2243,7 @@ void Matcher::find_shared( Node *n ) {
// besides address expressions. // besides address expressions.
Node *off = m->in(AddPNode::Offset); Node *off = m->in(AddPNode::Offset);
if( off->is_Con() && if (off->is_Con()) {
// When there are other uses besides address expressions
// put it on stack and mark as shared.
!is_visited(m) ) {
address_visited.test_set(m->_idx); // Flag as address_visited address_visited.test_set(m->_idx); // Flag as address_visited
Node *adr = m->in(AddPNode::Address); Node *adr = m->in(AddPNode::Address);
@ -2229,28 +2256,7 @@ void Matcher::find_shared( Node *n ) {
!is_visited(adr) ) { !is_visited(adr) ) {
address_visited.set(adr->_idx); // Flag as address_visited address_visited.set(adr->_idx); // Flag as address_visited
Node *shift = adr->in(AddPNode::Offset); Node *shift = adr->in(AddPNode::Offset);
// Check for shift by small constant as well if (!clone_shift(shift, this, mstack, address_visited)) {
if( shift->Opcode() == Op_LShiftX && shift->in(2)->is_Con() &&
shift->in(2)->get_int() <= 3 &&
// Are there other uses besides address expressions?
!is_visited(shift) ) {
address_visited.set(shift->_idx); // Flag as address_visited
mstack.push(shift->in(2), Visit);
Node *conv = shift->in(1);
#ifdef _LP64
// Allow Matcher to match the rule which bypass
// ConvI2L operation for an array index on LP64
// if the index value is positive.
if( conv->Opcode() == Op_ConvI2L &&
conv->as_Type()->type()->is_long()->_lo >= 0 &&
// Are there other uses besides address expressions?
!is_visited(conv) ) {
address_visited.set(conv->_idx); // Flag as address_visited
mstack.push(conv->in(1), Pre_Visit);
} else
#endif
mstack.push(conv, Pre_Visit);
} else {
mstack.push(shift, Pre_Visit); mstack.push(shift, Pre_Visit);
} }
mstack.push(adr->in(AddPNode::Address), Pre_Visit); mstack.push(adr->in(AddPNode::Address), Pre_Visit);
@ -2263,6 +2269,12 @@ void Matcher::find_shared( Node *n ) {
mstack.push(off, Visit); mstack.push(off, Visit);
mstack.push(m->in(AddPNode::Base), Pre_Visit); mstack.push(m->in(AddPNode::Base), Pre_Visit);
continue; // for(int i = ...) continue; // for(int i = ...)
} else if (clone_shift_expressions &&
clone_shift(off, this, mstack, address_visited)) {
address_visited.test_set(m->_idx); // Flag as address_visited
mstack.push(m->in(AddPNode::Address), Pre_Visit);
mstack.push(m->in(AddPNode::Base), Pre_Visit);
continue;
} // if( off->is_Con() ) } // if( off->is_Con() )
} // if( mem_op && } // if( mem_op &&
mstack.push(m, Pre_Visit); mstack.push(m, Pre_Visit);

View file

@ -3055,6 +3055,9 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) {
} }
} }
if (invariant(n)) { if (invariant(n)) {
if (opc == Op_ConvI2L) {
n = n->in(1);
}
_negate_invar = negate; _negate_invar = negate;
_invar = n; _invar = n;
NOT_PRODUCT(_tracer.offset_plus_k_10(n, _invar, _negate_invar, _offset);) NOT_PRODUCT(_tracer.offset_plus_k_10(n, _invar, _negate_invar, _offset);)