8136820: Generate better code for some Unsafe addressing patterns
Summary: reshape address computation to move invariant part out of loops
Reviewed-by: kvn
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Thu Sep 24 20:13:04 2015 +0300
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Thu Sep 17 16:53:42 2015 +0200
@@ -3767,6 +3767,22 @@
%}
%}
+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
operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale)
%{
@@ -4159,7 +4175,7 @@
// case of this is memory operands.
opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex,
- indIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset,
+ indIndexScale, indPosIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset,
indCompressedOopOffset,
indirectNarrow, indOffset8Narrow, indOffset32Narrow,
indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow,
@@ -5186,6 +5202,17 @@
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)
%{
match(Set dst mem);
--- a/hotspot/src/share/vm/opto/loopopts.cpp Thu Sep 24 20:13:04 2015 +0300
+++ b/hotspot/src/share/vm/opto/loopopts.cpp Thu Sep 17 16:53:42 2015 +0200
@@ -447,21 +447,21 @@
}
// Replace (I1 +p (I2 + V)) with ((I1 +p I2) +p V)
- if( n2_loop != n_loop && n3_loop == n_loop ) {
- if( n->in(3)->Opcode() == Op_AddI ) {
+ if (n2_loop != n_loop && n3_loop == n_loop) {
+ if (n->in(3)->Opcode() == Op_AddX) {
Node *V = n->in(3)->in(1);
Node *I = n->in(3)->in(2);
- if( is_member(n_loop,get_ctrl(V)) ) {
+ if (is_member(n_loop,get_ctrl(V))) {
} else {
Node *tmp = V; V = I; I = tmp;
}
- if( !is_member(n_loop,get_ctrl(I)) ) {
- Node *add1 = new AddPNode( n->in(1), n->in(2), I );
+ if (!is_member(n_loop,get_ctrl(I))) {
+ Node *add1 = new AddPNode(n->in(1), n->in(2), I);
// Stuff new AddP in the loop preheader
- register_new_node( add1, n_loop->_head->in(LoopNode::EntryControl) );
- Node *add2 = new AddPNode( n->in(1), add1, V );
- register_new_node( add2, n_ctrl );
- _igvn.replace_node( n, add2 );
+ register_new_node(add1, n_loop->_head->in(LoopNode::EntryControl));
+ Node *add2 = new AddPNode(n->in(1), add1, V);
+ register_new_node(add2, n_ctrl);
+ _igvn.replace_node(n, add2);
return add2;
}
}
--- a/hotspot/src/share/vm/opto/matcher.cpp Thu Sep 24 20:13:04 2015 +0300
+++ b/hotspot/src/share/vm/opto/matcher.cpp Thu Sep 17 16:53:42 2015 +0200
@@ -2045,6 +2045,33 @@
// and then expanded into the inline_cache_reg and a method_oop register
// 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------------------------------------
// Set bits if Node is shared or otherwise a root
@@ -2205,7 +2232,10 @@
#endif
// 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
// to avoid marking them as shared and forcing them into register
// if they are used only in address expressions.
@@ -2213,10 +2243,7 @@
// besides address expressions.
Node *off = m->in(AddPNode::Offset);
- if( off->is_Con() &&
- // When there are other uses besides address expressions
- // put it on stack and mark as shared.
- !is_visited(m) ) {
+ if (off->is_Con()) {
address_visited.test_set(m->_idx); // Flag as address_visited
Node *adr = m->in(AddPNode::Address);
@@ -2229,28 +2256,7 @@
!is_visited(adr) ) {
address_visited.set(adr->_idx); // Flag as address_visited
Node *shift = adr->in(AddPNode::Offset);
- // Check for shift by small constant as well
- 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 {
+ if (!clone_shift(shift, this, mstack, address_visited)) {
mstack.push(shift, Pre_Visit);
}
mstack.push(adr->in(AddPNode::Address), Pre_Visit);
@@ -2263,6 +2269,12 @@
mstack.push(off, Visit);
mstack.push(m->in(AddPNode::Base), Pre_Visit);
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( mem_op &&
mstack.push(m, Pre_Visit);
--- a/hotspot/src/share/vm/opto/superword.cpp Thu Sep 24 20:13:04 2015 +0300
+++ b/hotspot/src/share/vm/opto/superword.cpp Thu Sep 17 16:53:42 2015 +0200
@@ -3055,6 +3055,9 @@
}
}
if (invariant(n)) {
+ if (opc == Op_ConvI2L) {
+ n = n->in(1);
+ }
_negate_invar = negate;
_invar = n;
NOT_PRODUCT(_tracer.offset_plus_k_10(n, _invar, _negate_invar, _offset);)