Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8252372: Check if cloning is required to move loads out of loops in PhaseIdealLoop::split_if_with_blocks_post() #3689

Closed
wants to merge 6 commits into from
Closed
Changes from 2 commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
@@ -8880,6 +8880,28 @@ instruct castLL(iRegL dst)
ins_pipe(pipe_class_empty);
%}

instruct castFF(vRegF dst)
%{
match(Set dst (CastFF dst));

size(0);
format %{ "# castFF of $dst" %}
ins_encode(/* empty encoding */);
ins_cost(0);
ins_pipe(pipe_class_empty);
%}

instruct castDD(vRegD dst)
%{
match(Set dst (CastDD dst));

size(0);
format %{ "# castDD of $dst" %}
ins_encode(/* empty encoding */);
ins_cost(0);
ins_pipe(pipe_class_empty);
%}

// ============================================================================
// Atomic operation instructions
//
@@ -5291,6 +5291,23 @@ instruct castLL( iRegL dst ) %{
ins_pipe(empty);
%}

instruct castFF( regF dst ) %{
match(Set dst (CastFF dst));
format %{ "! castFF of $dst" %}
ins_encode( /*empty encoding*/ );
ins_cost(0);
ins_pipe(empty);
%}

instruct castDD( regD dst ) %{
match(Set dst (CastDD dst));
format %{ "! castDD of $dst" %}
ins_encode( /*empty encoding*/ );
ins_cost(0);
ins_pipe(empty);
%}


//----------Arithmetic Instructions--------------------------------------------
// Addition Instructions
// Register Addition
@@ -10452,6 +10452,22 @@ instruct castLL(iRegLdst dst) %{
ins_pipe(pipe_class_default);
%}

instruct castFF(regF dst) %{
match(Set dst (CastFF dst));
format %{ " -- \t// castFF of $dst" %}
size(0);
ins_encode( /*empty*/ );
ins_pipe(pipe_class_default);
%}

instruct castDD(regD dst) %{
match(Set dst (CastDD dst));
format %{ " -- \t// castDD of $dst" %}
size(0);
ins_encode( /*empty*/ );
ins_pipe(pipe_class_default);
%}

instruct checkCastPP(iRegPdst dst) %{
match(Set dst (CheckCastPP dst));
format %{ " -- \t// checkcastPP of $dst" %}
@@ -5366,6 +5366,22 @@ instruct castLL(iRegL dst) %{
ins_pipe(pipe_class_dummy);
%}

instruct castFF(regF dst) %{
match(Set dst (CastFF dst));
size(0);
format %{ "# castFF of $dst" %}
ins_encode(/*empty*/);
ins_pipe(pipe_class_dummy);
%}

instruct castDD(regD dst) %{
match(Set dst (CastDD dst));
size(0);
format %{ "# castDD of $dst" %}
ins_encode(/*empty*/);
ins_pipe(pipe_class_dummy);
%}

//----------Conditional_store--------------------------------------------------
// Conditional-store of the updated heap-top.
// Used during allocation of the shared heap.
@@ -7246,6 +7246,22 @@ instruct castLL( eRegL dst ) %{
ins_pipe( empty );
%}

instruct castFF( regF dst ) %{
match(Set dst (CastFF dst));
format %{ "#castFF of $dst" %}
ins_encode( /*empty encoding*/ );
ins_cost(0);
ins_pipe( empty );
%}

instruct castDD( regD dst ) %{
match(Set dst (CastDD dst));
format %{ "#castDD of $dst" %}
ins_encode( /*empty encoding*/ );
ins_cost(0);
ins_pipe( empty );
%}

// Load-locked - same as a regular pointer load when used with compare-swap
instruct loadPLocked(eRegP dst, memory mem) %{
match(Set dst (LoadPLocked mem));
@@ -7645,6 +7645,28 @@ instruct castLL(rRegL dst)
ins_pipe(empty);
%}

instruct castFF(regF dst)
%{
match(Set dst (CastFF dst));

size(0);
format %{ "# castFF of $dst" %}
ins_encode(/* empty encoding */);
ins_cost(0);
ins_pipe(empty);
%}

instruct castDD(regD dst)
%{
match(Set dst (CastDD dst));

size(0);
format %{ "# castDD of $dst" %}
ins_encode(/* empty encoding */);
ins_cost(0);
ins_pipe(empty);
%}

// LoadP-locked same as a regular LoadP when used with compare-swap
instruct loadPLocked(rRegP dst, memory mem)
%{
@@ -115,6 +115,26 @@ class CastLLNode: public ConstraintCastNode {
virtual uint ideal_reg() const { return Op_RegL; }
};

class CastFFNode: public ConstraintCastNode {
public:
CastFFNode(Node* n, const Type* t, bool carry_dependency = false)
: ConstraintCastNode(n, t, carry_dependency){
init_class_id(Class_CastFF);
}
virtual int Opcode() const;
virtual uint ideal_reg() const { return Op_RegF; }
};

class CastDDNode: public ConstraintCastNode {
public:
CastDDNode(Node* n, const Type* t, bool carry_dependency = false)
: ConstraintCastNode(n, t, carry_dependency){
init_class_id(Class_CastDD);
}
virtual int Opcode() const;
virtual uint ideal_reg() const { return Op_RegD; }
};

//------------------------------CastPPNode-------------------------------------
// cast pointer to pointer (different type)
class CastPPNode: public ConstraintCastNode {
@@ -61,6 +61,8 @@ macro(CallLeafNoFP)
macro(CallRuntime)
macro(CallNative)
macro(CallStaticJava)
macro(CastDD)
macro(CastFF)
macro(CastII)
macro(CastLL)
macro(CastX2P)
@@ -4991,52 +4991,64 @@ Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
}
#endif

// if this is a load, check for anti-dependent stores
// We use a conservative algorithm to identify potential interfering
// instructions and for rescheduling the load. The users of the memory
// input of this load are examined. Any use which is not a load and is
// dominated by early is considered a potentially interfering store.
// This can produce false positives.
if (n->is_Load() && LCA != early) {
int load_alias_idx = C->get_alias_index(n->adr_type());
if (C->alias_type(load_alias_idx)->is_rewritable()) {
Unique_Node_List worklist;

Node* mem = n->in(MemNode::Memory);
for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
Node* s = mem->fast_out(i);
worklist.push(s);
}
for (uint i = 0; i < worklist.size() && LCA != early; i++) {
Node* s = worklist.at(i);
if (s->is_Load() || s->Opcode() == Op_SafePoint ||
(s->is_CallStaticJava() && s->as_CallStaticJava()->uncommon_trap_request() != 0) ||
s->is_Phi()) {
continue;
} else if (s->is_MergeMem()) {
for (DUIterator_Fast imax, i = s->fast_outs(imax); i < imax; i++) {
Node* s1 = s->fast_out(i);
worklist.push(s1);
}
} else {
Node* sctrl = has_ctrl(s) ? get_ctrl(s) : s->in(0);
assert(sctrl != NULL || !s->is_reachable_from_root(), "must have control");
if (sctrl != NULL && !sctrl->is_top() && is_dominator(early, sctrl)) {
const TypePtr* adr_type = s->adr_type();
if (s->is_ArrayCopy()) {
// Copy to known instance needs destination type to test for aliasing
const TypePtr* dest_type = s->as_ArrayCopy()->_dest_type;
if (dest_type != TypeOopPtr::BOTTOM) {
adr_type = dest_type;
}
LCA = get_late_ctrl_with_anti_dep(n->as_Load(), early, LCA);
}

assert(LCA == find_non_split_ctrl(LCA), "unexpected late control");
return LCA;
}

// if this is a load, check for anti-dependent stores
// We use a conservative algorithm to identify potential interfering
// instructions and for rescheduling the load. The users of the memory
// input of this load are examined. Any use which is not a load and is
// dominated by early is considered a potentially interfering store.
// This can produce false positives.
Node* PhaseIdealLoop::get_late_ctrl_with_anti_dep(LoadNode* n, Node* early, Node* LCA) {
int load_alias_idx = C->get_alias_index(n->adr_type());
if (C->alias_type(load_alias_idx)->is_rewritable()) {
Unique_Node_List worklist;

Node* mem = n->in(MemNode::Memory);
for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
Node* s = mem->fast_out(i);
worklist.push(s);
}
for (uint i = 0; i < worklist.size() && LCA != early; i++) {
Node* s = worklist.at(i);
if (s->is_Load() || s->Opcode() == Op_SafePoint ||
(s->is_CallStaticJava() && s->as_CallStaticJava()->uncommon_trap_request() != 0) ||
s->is_Phi()) {
continue;
} else if (s->is_MergeMem()) {
for (DUIterator_Fast imax, i = s->fast_outs(imax); i < imax; i++) {
Node* s1 = s->fast_out(i);
worklist.push(s1);
}
} else {
Node* sctrl = has_ctrl(s) ? get_ctrl(s) : s->in(0);
assert(sctrl != NULL || !s->is_reachable_from_root(), "must have control");
if (sctrl != NULL && !sctrl->is_top() && is_dominator(early, sctrl)) {
const TypePtr* adr_type = s->adr_type();
if (s->is_ArrayCopy()) {
// Copy to known instance needs destination type to test for aliasing
const TypePtr* dest_type = s->as_ArrayCopy()->_dest_type;
if (dest_type != TypeOopPtr::BOTTOM) {
adr_type = dest_type;
}
if (C->can_alias(adr_type, load_alias_idx)) {
LCA = dom_lca_for_get_late_ctrl(LCA, sctrl, n);
} else if (s->is_CFG()) {
for (DUIterator_Fast imax, i = s->fast_outs(imax); i < imax; i++) {
Node* s1 = s->fast_out(i);
if (_igvn.type(s1) == Type::MEMORY) {
worklist.push(s1);
}
if (C->can_alias(adr_type, load_alias_idx)) {
LCA = dom_lca_for_get_late_ctrl(LCA, sctrl, n);
} else if (s->is_CFG() && s->is_Multi()) {
// Look for the memory use of s (that is the use of its memory projection)
for (DUIterator_Fast imax, i = s->fast_outs(imax); i < imax; i++) {
Node* s1 = s->fast_out(i);
assert(s1->is_Proj(), "projection expected");
if (_igvn.type(s1) == Type::MEMORY) {
for (DUIterator_Fast jmax, j = s1->fast_outs(jmax); j < jmax; j++) {
Node* s2 = s1->fast_out(j);
worklist.push(s2);
}
}
}
@@ -5062,8 +5074,6 @@ Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
}
}
}

assert(LCA == find_non_split_ctrl(LCA), "unexpected late control");
return LCA;
}

@@ -5091,23 +5101,24 @@ bool PhaseIdealLoop::is_dominator(Node *d, Node *n) {
// does not need to be cleared between calls to get_late_ctrl().
// Algorithm trades a larger constant factor for better asymptotic behavior
//
Node *PhaseIdealLoop::dom_lca_for_get_late_ctrl_internal( Node *n1, Node *n2, Node *tag ) {
Node *PhaseIdealLoop::dom_lca_for_get_late_ctrl_internal(Node *n1, Node *n2, Node *tag_node) {
uint d1 = dom_depth(n1);
uint d2 = dom_depth(n2);
jlong tag = tag_node->_idx | (((jlong)_dom_lca_tags_round) << 32);

do {
if (d1 > d2) {
// current lca is deeper than n2
_dom_lca_tags.map(n1->_idx, tag);
_dom_lca_tags.at_put_grow(n1->_idx, tag);
n1 = idom(n1);
d1 = dom_depth(n1);
} else if (d1 < d2) {
// n2 is deeper than current lca
Node *memo = _dom_lca_tags[n2->_idx];
if( memo == tag ) {
jlong memo = _dom_lca_tags.at_grow(n2->_idx, 0);
if (memo == tag) {
return n1; // Return the current LCA
}
_dom_lca_tags.map(n2->_idx, tag);
_dom_lca_tags.at_put_grow(n2->_idx, tag);
n2 = idom(n2);
d2 = dom_depth(n2);
} else {
@@ -5116,19 +5127,19 @@ Node *PhaseIdealLoop::dom_lca_for_get_late_ctrl_internal( Node *n1, Node *n2, No
// to be searched more carefully.

// Scan up all the n1's with equal depth, looking for n2.
_dom_lca_tags.map(n1->_idx, tag);
_dom_lca_tags.at_put_grow(n1->_idx, tag);
Node *t1 = idom(n1);
while (dom_depth(t1) == d1) {
if (t1 == n2) return n2;
_dom_lca_tags.map(t1->_idx, tag);
_dom_lca_tags.at_put_grow(t1->_idx, tag);
t1 = idom(t1);
}
// Scan up all the n2's with equal depth, looking for n1.
_dom_lca_tags.map(n2->_idx, tag);
_dom_lca_tags.at_put_grow(n2->_idx, tag);
Node *t2 = idom(n2);
while (dom_depth(t2) == d2) {
if (t2 == n1) return n1;
_dom_lca_tags.map(t2->_idx, tag);
_dom_lca_tags.at_put_grow(t2->_idx, tag);
t2 = idom(t2);
}
// Move up to a new dominator-depth value as well as up the dom-tree.
@@ -5147,25 +5158,11 @@ Node *PhaseIdealLoop::dom_lca_for_get_late_ctrl_internal( Node *n1, Node *n2, No
// be of fixed size.
void PhaseIdealLoop::init_dom_lca_tags() {
uint limit = C->unique() + 1;
_dom_lca_tags.map( limit, NULL );
#ifdef ASSERT
for( uint i = 0; i < limit; ++i ) {
assert(_dom_lca_tags[i] == NULL, "Must be distinct from each node pointer");
}
#endif // ASSERT
}

//------------------------------clear_dom_lca_tags------------------------------
// Tag could be a node's integer index, 32bits instead of 64bits in some cases
// Intended use does not involve any growth for the array, so it could
// be of fixed size.
void PhaseIdealLoop::clear_dom_lca_tags() {
uint limit = C->unique() + 1;
_dom_lca_tags.map( limit, NULL );
_dom_lca_tags.clear();
_dom_lca_tags.at_grow(limit, 0);
_dom_lca_tags_round = 0;
#ifdef ASSERT
for( uint i = 0; i < limit; ++i ) {
assert(_dom_lca_tags[i] == NULL, "Must be distinct from each node pointer");
for (uint i = 0; i < limit; ++i) {
assert(_dom_lca_tags.at(i) == 0, "Must be distinct from each node pointer");
}
#endif // ASSERT
}
Loading