6890673: Eliminate allocations immediately after EA

Try to eliminate allocations and related locks immediately after escape analysis.

Reviewed-by: never
This commit is contained in:
Vladimir Kozlov 2011-11-16 09:13:57 -08:00
parent 81c085a1e2
commit 8d2ee23293
11 changed files with 148 additions and 71 deletions

View File

@ -898,45 +898,41 @@ void PhaseCFG::dump_headers() {
void PhaseCFG::verify( ) const { void PhaseCFG::verify( ) const {
#ifdef ASSERT #ifdef ASSERT
// Verify sane CFG // Verify sane CFG
for( uint i = 0; i < _num_blocks; i++ ) { for (uint i = 0; i < _num_blocks; i++) {
Block *b = _blocks[i]; Block *b = _blocks[i];
uint cnt = b->_nodes.size(); uint cnt = b->_nodes.size();
uint j; uint j;
for( j = 0; j < cnt; j++ ) { for (j = 0; j < cnt; j++) {
Node *n = b->_nodes[j]; Node *n = b->_nodes[j];
assert( _bbs[n->_idx] == b, "" ); assert( _bbs[n->_idx] == b, "" );
if( j >= 1 && n->is_Mach() && if (j >= 1 && n->is_Mach() &&
n->as_Mach()->ideal_Opcode() == Op_CreateEx ) { n->as_Mach()->ideal_Opcode() == Op_CreateEx) {
assert( j == 1 || b->_nodes[j-1]->is_Phi(), assert(j == 1 || b->_nodes[j-1]->is_Phi(),
"CreateEx must be first instruction in block" ); "CreateEx must be first instruction in block");
} }
for( uint k = 0; k < n->req(); k++ ) { for (uint k = 0; k < n->req(); k++) {
Node *def = n->in(k); Node *def = n->in(k);
if( def && def != n ) { if (def && def != n) {
assert( _bbs[def->_idx] || def->is_Con(), assert(_bbs[def->_idx] || def->is_Con(),
"must have block; constants for debug info ok" ); "must have block; constants for debug info ok");
// Verify that instructions in the block is in correct order. // Verify that instructions in the block is in correct order.
// Uses must follow their definition if they are at the same block. // Uses must follow their definition if they are at the same block.
// Mostly done to check that MachSpillCopy nodes are placed correctly // Mostly done to check that MachSpillCopy nodes are placed correctly
// when CreateEx node is moved in build_ifg_physical(). // when CreateEx node is moved in build_ifg_physical().
if( _bbs[def->_idx] == b && if (_bbs[def->_idx] == b &&
!(b->head()->is_Loop() && n->is_Phi()) && !(b->head()->is_Loop() && n->is_Phi()) &&
// See (+++) comment in reg_split.cpp // See (+++) comment in reg_split.cpp
!(n->jvms() != NULL && n->jvms()->is_monitor_use(k)) ) { !(n->jvms() != NULL && n->jvms()->is_monitor_use(k))) {
bool is_loop = false; bool is_loop = false;
if (n->is_Phi()) { if (n->is_Phi()) {
for( uint l = 1; l < def->req(); l++ ) { for (uint l = 1; l < def->req(); l++) {
if (n == def->in(l)) { if (n == def->in(l)) {
is_loop = true; is_loop = true;
break; // Some kind of loop break; // Some kind of loop
} }
} }
} }
assert( is_loop || b->find_node(def) < j, "uses must follow definitions" ); assert(is_loop || b->find_node(def) < j, "uses must follow definitions");
}
if( def->is_SafePointScalarObject() ) {
assert(_bbs[def->_idx] == b, "SafePointScalarObject Node should be at the same block as its SafePoint node");
assert(_bbs[def->_idx] == _bbs[def->in(0)->_idx], "SafePointScalarObject Node should be at the same block as its control edge");
} }
} }
} }
@ -946,12 +942,11 @@ void PhaseCFG::verify( ) const {
Node *bp = (Node*)b->_nodes[b->_nodes.size()-1]->is_block_proj(); Node *bp = (Node*)b->_nodes[b->_nodes.size()-1]->is_block_proj();
assert( bp, "last instruction must be a block proj" ); assert( bp, "last instruction must be a block proj" );
assert( bp == b->_nodes[j], "wrong number of successors for this block" ); assert( bp == b->_nodes[j], "wrong number of successors for this block" );
if( bp->is_Catch() ) { if (bp->is_Catch()) {
while( b->_nodes[--j]->is_MachProj() ) ; while (b->_nodes[--j]->is_MachProj()) ;
assert( b->_nodes[j]->is_MachCall(), "CatchProj must follow call" ); assert(b->_nodes[j]->is_MachCall(), "CatchProj must follow call");
} } else if (bp->is_Mach() && bp->as_Mach()->ideal_Opcode() == Op_If) {
else if( bp->is_Mach() && bp->as_Mach()->ideal_Opcode() == Op_If ) { assert(b->_num_succs == 2, "Conditional branch must have two targets");
assert( b->_num_succs == 2, "Conditional branch must have two targets");
} }
} }
#endif #endif

View File

@ -1071,8 +1071,11 @@ SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp,
init_class_id(Class_SafePointScalarObject); init_class_id(Class_SafePointScalarObject);
} }
bool SafePointScalarObjectNode::pinned() const { return true; } // Do not allow value-numbering for SafePointScalarObject node.
bool SafePointScalarObjectNode::depends_only_on_test() const { return false; } uint SafePointScalarObjectNode::hash() const { return NO_HASH; }
uint SafePointScalarObjectNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
uint SafePointScalarObjectNode::ideal_reg() const { uint SafePointScalarObjectNode::ideal_reg() const {
return 0; // No matching to machine instruction return 0; // No matching to machine instruction
@ -1096,7 +1099,6 @@ SafePointScalarObjectNode::clone(int jvms_adj, Dict* sosn_map) const {
if (cached != NULL) { if (cached != NULL) {
return (SafePointScalarObjectNode*)cached; return (SafePointScalarObjectNode*)cached;
} }
Compile* C = Compile::current();
SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone(); SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone();
res->_first_index += jvms_adj; res->_first_index += jvms_adj;
sosn_map->Insert((void*)this, (void*)res); sosn_map->Insert((void*)this, (void*)res);
@ -1142,6 +1144,8 @@ uint AllocateArrayNode::size_of() const { return sizeof(*this); }
Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this; if (remove_dead_region(phase, can_reshape)) return this;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
const Type* type = phase->type(Ideal_length()); const Type* type = phase->type(Ideal_length());
if (type->isa_int() && type->is_int()->_hi < 0) { if (type->isa_int() && type->is_int()->_hi < 0) {
@ -1522,13 +1526,16 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// perform any generic optimizations first (returns 'this' or NULL) // perform any generic optimizations first (returns 'this' or NULL)
Node *result = SafePointNode::Ideal(phase, can_reshape); Node *result = SafePointNode::Ideal(phase, can_reshape);
if (result != NULL) return result;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
// Now see if we can optimize away this lock. We don't actually // Now see if we can optimize away this lock. We don't actually
// remove the locking here, we simply set the _eliminate flag which // remove the locking here, we simply set the _eliminate flag which
// prevents macro expansion from expanding the lock. Since we don't // prevents macro expansion from expanding the lock. Since we don't
// modify the graph, the value returned from this function is the // modify the graph, the value returned from this function is the
// one computed above. // one computed above.
if (result == NULL && can_reshape && EliminateLocks && !is_eliminated()) { if (can_reshape && EliminateLocks && (!is_eliminated() || is_coarsened())) {
// //
// If we are locking an unescaped object, the lock/unlock is unnecessary // If we are locking an unescaped object, the lock/unlock is unnecessary
// //
@ -1537,8 +1544,16 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (cgr != NULL) if (cgr != NULL)
es = cgr->escape_state(obj_node()); es = cgr->escape_state(obj_node());
if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated to update any counters if (!is_eliminated()) {
this->set_eliminated(); // Mark it eliminated to update any counters
this->set_eliminated();
} else {
assert(is_coarsened(), "sanity");
// The lock could be marked eliminated by lock coarsening
// code during first IGVN before EA. Clear coarsened flag
// to eliminate all associated locks/unlocks.
this->clear_coarsened();
}
return result; return result;
} }
@ -1546,7 +1561,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Try lock coarsening // Try lock coarsening
// //
PhaseIterGVN* iter = phase->is_IterGVN(); PhaseIterGVN* iter = phase->is_IterGVN();
if (iter != NULL) { if (iter != NULL && !is_eliminated()) {
GrowableArray<AbstractLockNode*> lock_ops; GrowableArray<AbstractLockNode*> lock_ops;
@ -1602,7 +1617,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
lock->set_eliminated(); lock->set_eliminated();
lock->set_coarsened(); lock->set_coarsened();
} }
} else if (result != NULL && ctrl->is_Region() && } else if (ctrl->is_Region() &&
iter->_worklist.member(ctrl)) { iter->_worklist.member(ctrl)) {
// We weren't able to find any opportunities but the region this // We weren't able to find any opportunities but the region this
// lock is control dependent on hasn't been processed yet so put // lock is control dependent on hasn't been processed yet so put
@ -1623,7 +1638,10 @@ uint UnlockNode::size_of() const { return sizeof(*this); }
Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// perform any generic optimizations first (returns 'this' or NULL) // perform any generic optimizations first (returns 'this' or NULL)
Node * result = SafePointNode::Ideal(phase, can_reshape); Node *result = SafePointNode::Ideal(phase, can_reshape);
if (result != NULL) return result;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
// Now see if we can optimize away this unlock. We don't actually // Now see if we can optimize away this unlock. We don't actually
// remove the unlocking here, we simply set the _eliminate flag which // remove the unlocking here, we simply set the _eliminate flag which
@ -1631,7 +1649,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// modify the graph, the value returned from this function is the // modify the graph, the value returned from this function is the
// one computed above. // one computed above.
// Escape state is defined after Parse phase. // Escape state is defined after Parse phase.
if (result == NULL && can_reshape && EliminateLocks && !is_eliminated()) { if (can_reshape && EliminateLocks && (!is_eliminated() || is_coarsened())) {
// //
// If we are unlocking an unescaped object, the lock/unlock is unnecessary. // If we are unlocking an unescaped object, the lock/unlock is unnecessary.
// //
@ -1640,8 +1658,16 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (cgr != NULL) if (cgr != NULL)
es = cgr->escape_state(obj_node()); es = cgr->escape_state(obj_node());
if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated to update any counters if (!is_eliminated()) {
this->set_eliminated(); // Mark it eliminated to update any counters
this->set_eliminated();
} else {
assert(is_coarsened(), "sanity");
// The lock could be marked eliminated by lock coarsening
// code during first IGVN before EA. Clear coarsened flag
// to eliminate all associated locks/unlocks.
this->clear_coarsened();
}
} }
} }
return result; return result;

View File

@ -440,6 +440,10 @@ class SafePointScalarObjectNode: public TypeNode {
// states of the scalarized object fields are collected. // states of the scalarized object fields are collected.
uint _n_fields; // Number of non-static fields of the scalarized object. uint _n_fields; // Number of non-static fields of the scalarized object.
DEBUG_ONLY(AllocateNode* _alloc;) DEBUG_ONLY(AllocateNode* _alloc;)
virtual uint hash() const ; // { return NO_HASH; }
virtual uint cmp( const Node &n ) const;
public: public:
SafePointScalarObjectNode(const TypeOopPtr* tp, SafePointScalarObjectNode(const TypeOopPtr* tp,
#ifdef ASSERT #ifdef ASSERT
@ -454,15 +458,10 @@ public:
uint first_index() const { return _first_index; } uint first_index() const { return _first_index; }
uint n_fields() const { return _n_fields; } uint n_fields() const { return _n_fields; }
DEBUG_ONLY(AllocateNode* alloc() const { return _alloc; })
// SafePointScalarObject should be always pinned to the control edge #ifdef ASSERT
// of the SafePoint node for which it was generated. AllocateNode* alloc() const { return _alloc; }
virtual bool pinned() const; // { return true; } #endif
// SafePointScalarObject depends on the SafePoint node
// for which it was generated.
virtual bool depends_only_on_test() const; // { return false; }
virtual uint size_of() const { return sizeof(*this); } virtual uint size_of() const { return sizeof(*this); }
@ -880,6 +879,7 @@ public:
bool is_coarsened() { return _coarsened; } bool is_coarsened() { return _coarsened; }
void set_coarsened() { _coarsened = true; } void set_coarsened() { _coarsened = true; }
void clear_coarsened() { _coarsened = false; }
// locking does not modify its arguments // locking does not modify its arguments
virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase){ return false;} virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase){ return false;}

View File

@ -1711,11 +1711,22 @@ void Compile::Optimize() {
if (failing()) return; if (failing()) return;
// Optimize out fields loads from scalar replaceable allocations.
igvn.optimize(); igvn.optimize();
print_method("Iter GVN after EA", 2); print_method("Iter GVN after EA", 2);
if (failing()) return; if (failing()) return;
if (congraph() != NULL && macro_count() > 0) {
PhaseMacroExpand mexp(igvn);
mexp.eliminate_macro_nodes();
igvn.set_delay_transform(false);
igvn.optimize();
print_method("Iter GVN after eliminating allocations and locks", 2);
if (failing()) return;
}
} }
// Loop transforms on the ideal graph. Range Check Elimination, // Loop transforms on the ideal graph. Range Check Elimination,

View File

@ -1772,12 +1772,20 @@ bool ConnectionGraph::compute_escape() {
Node *n = C->macro_node(i); Node *n = C->macro_node(i);
if (n->is_AbstractLock()) { // Lock and Unlock nodes if (n->is_AbstractLock()) { // Lock and Unlock nodes
AbstractLockNode* alock = n->as_AbstractLock(); AbstractLockNode* alock = n->as_AbstractLock();
if (!alock->is_eliminated()) { if (!alock->is_eliminated() || alock->is_coarsened()) {
PointsToNode::EscapeState es = escape_state(alock->obj_node()); PointsToNode::EscapeState es = escape_state(alock->obj_node());
assert(es != PointsToNode::UnknownEscape, "should know"); assert(es != PointsToNode::UnknownEscape, "should know");
if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated if (!alock->is_eliminated()) {
alock->set_eliminated(); // Mark it eliminated to update any counters
alock->set_eliminated();
} else {
// The lock could be marked eliminated by lock coarsening
// code during first IGVN before EA. Clear coarsened flag
// to eliminate all associated locks/unlocks and relock
// during deoptimization.
alock->clear_coarsened();
}
} }
} }
} }

View File

@ -95,7 +95,7 @@ void PhaseCFG::replace_block_proj_ctrl( Node *n ) {
assert(in0 != NULL, "Only control-dependent"); assert(in0 != NULL, "Only control-dependent");
const Node *p = in0->is_block_proj(); const Node *p = in0->is_block_proj();
if (p != NULL && p != n) { // Control from a block projection? if (p != NULL && p != n) { // Control from a block projection?
assert(!n->pinned() || n->is_MachConstantBase() || n->is_SafePointScalarObject(), "only pinned MachConstantBase or SafePointScalarObject node is expected here"); assert(!n->pinned() || n->is_MachConstantBase(), "only pinned MachConstantBase node is expected here");
// Find trailing Region // Find trailing Region
Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block
uint j = 0; uint j = 0;

View File

@ -1946,7 +1946,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
} }
// Nothing to do, so get out // Nothing to do, so get out
if( !C->has_loops() && !do_split_ifs && !_verify_me && !_verify_only ) { if( !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only ) {
_igvn.optimize(); // Cleanup NeverBranches _igvn.optimize(); // Cleanup NeverBranches
return; return;
} }

View File

@ -81,7 +81,7 @@ void PhaseMacroExpand::copy_call_debug_info(CallNode *oldcall, CallNode * newcal
uint old_unique = C->unique(); uint old_unique = C->unique();
Node* new_in = old_sosn->clone(jvms_adj, sosn_map); Node* new_in = old_sosn->clone(jvms_adj, sosn_map);
if (old_unique != C->unique()) { if (old_unique != C->unique()) {
new_in->set_req(0, newcall->in(0)); // reset control edge new_in->set_req(0, C->root()); // reset control edge
new_in = transform_later(new_in); // Register new node. new_in = transform_later(new_in); // Register new node.
} }
old_in = new_in; old_in = new_in;
@ -565,7 +565,6 @@ bool PhaseMacroExpand::can_eliminate_allocation(AllocateNode *alloc, GrowableArr
if (res == NULL) { if (res == NULL) {
// All users were eliminated. // All users were eliminated.
} else if (!res->is_CheckCastPP()) { } else if (!res->is_CheckCastPP()) {
alloc->_is_scalar_replaceable = false; // don't try again
NOT_PRODUCT(fail_eliminate = "Allocation does not have unique CheckCastPP";) NOT_PRODUCT(fail_eliminate = "Allocation does not have unique CheckCastPP";)
can_eliminate = false; can_eliminate = false;
} else { } else {
@ -719,7 +718,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray <Sa
alloc, alloc,
#endif #endif
first_ind, nfields); first_ind, nfields);
sobj->init_req(0, sfpt->in(TypeFunc::Control)); sobj->init_req(0, C->root());
transform_later(sobj); transform_later(sobj);
// Scan object's fields adding an input to the safepoint for each field. // Scan object's fields adding an input to the safepoint for each field.
@ -762,10 +761,10 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray <Sa
Node *field_val = value_from_mem(mem, basic_elem_type, field_type, field_addr_type, alloc); Node *field_val = value_from_mem(mem, basic_elem_type, field_type, field_addr_type, alloc);
if (field_val == NULL) { if (field_val == NULL) {
// we weren't able to find a value for this field, // We weren't able to find a value for this field,
// give up on eliminating this allocation // give up on eliminating this allocation.
alloc->_is_scalar_replaceable = false; // don't try again
// remove any extra entries we added to the safepoint // Remove any extra entries we added to the safepoint.
uint last = sfpt->req() - 1; uint last = sfpt->req() - 1;
for (int k = 0; k < j; k++) { for (int k = 0; k < j; k++) {
sfpt->del_req(last--); sfpt->del_req(last--);
@ -1804,9 +1803,9 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
#ifndef PRODUCT #ifndef PRODUCT
if (PrintEliminateLocks) { if (PrintEliminateLocks) {
if (alock->is_Lock()) { if (alock->is_Lock()) {
tty->print_cr("++++ Eliminating: %d Lock", alock->_idx); tty->print_cr("++++ Eliminated: %d Lock", alock->_idx);
} else { } else {
tty->print_cr("++++ Eliminating: %d Unlock", alock->_idx); tty->print_cr("++++ Eliminated: %d Unlock", alock->_idx);
} }
} }
#endif #endif
@ -2165,11 +2164,12 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) {
_igvn.replace_node(_memproj_fallthrough, mem_phi); _igvn.replace_node(_memproj_fallthrough, mem_phi);
} }
//------------------------------expand_macro_nodes---------------------- //---------------------------eliminate_macro_nodes----------------------
// Returns true if a failure occurred. // Eliminate scalar replaced allocations and associated locks.
bool PhaseMacroExpand::expand_macro_nodes() { void PhaseMacroExpand::eliminate_macro_nodes() {
if (C->macro_count() == 0) if (C->macro_count() == 0)
return false; return;
// First, attempt to eliminate locks // First, attempt to eliminate locks
int cnt = C->macro_count(); int cnt = C->macro_count();
for (int i=0; i < cnt; i++) { for (int i=0; i < cnt; i++) {
@ -2189,14 +2189,6 @@ bool PhaseMacroExpand::expand_macro_nodes() {
debug_only(int old_macro_count = C->macro_count();); debug_only(int old_macro_count = C->macro_count(););
if (n->is_AbstractLock()) { if (n->is_AbstractLock()) {
success = eliminate_locking_node(n->as_AbstractLock()); success = eliminate_locking_node(n->as_AbstractLock());
} else if (n->Opcode() == Op_LoopLimit) {
// Remove it from macro list and put on IGVN worklist to optimize.
C->remove_macro_node(n);
_igvn._worklist.push(n);
success = true;
} else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
_igvn.replace_node(n, n->in(1));
success = true;
} }
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success; progress = progress || success;
@ -2220,18 +2212,50 @@ bool PhaseMacroExpand::expand_macro_nodes() {
assert(!n->as_AbstractLock()->is_eliminated(), "sanity"); assert(!n->as_AbstractLock()->is_eliminated(), "sanity");
break; break;
default: default:
assert(false, "unknown node type in macro list"); assert(n->Opcode() == Op_LoopLimit ||
n->Opcode() == Op_Opaque1 ||
n->Opcode() == Op_Opaque2, "unknown node type in macro list");
} }
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success; progress = progress || success;
} }
} }
}
//------------------------------expand_macro_nodes----------------------
// Returns true if a failure occurred.
bool PhaseMacroExpand::expand_macro_nodes() {
// Last attempt to eliminate macro nodes.
eliminate_macro_nodes();
// Make sure expansion will not cause node limit to be exceeded. // Make sure expansion will not cause node limit to be exceeded.
// Worst case is a macro node gets expanded into about 50 nodes. // Worst case is a macro node gets expanded into about 50 nodes.
// Allow 50% more for optimization. // Allow 50% more for optimization.
if (C->check_node_count(C->macro_count() * 75, "out of nodes before macro expansion" ) ) if (C->check_node_count(C->macro_count() * 75, "out of nodes before macro expansion" ) )
return true; return true;
// Eliminate Opaque and LoopLimit nodes. Do it after all loop optimizations.
bool progress = true;
while (progress) {
progress = false;
for (int i = C->macro_count(); i > 0; i--) {
Node * n = C->macro_node(i-1);
bool success = false;
debug_only(int old_macro_count = C->macro_count(););
if (n->Opcode() == Op_LoopLimit) {
// Remove it from macro list and put on IGVN worklist to optimize.
C->remove_macro_node(n);
_igvn._worklist.push(n);
success = true;
} else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
_igvn.replace_node(n, n->in(1));
success = true;
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
}
}
// expand "macro" nodes // expand "macro" nodes
// nodes are removed from the macro list as they are processed // nodes are removed from the macro list as they are processed
while (C->macro_count() > 0) { while (C->macro_count() > 0) {
@ -2265,5 +2289,6 @@ bool PhaseMacroExpand::expand_macro_nodes() {
_igvn.set_delay_transform(false); _igvn.set_delay_transform(false);
_igvn.optimize(); _igvn.optimize();
if (C->failing()) return true;
return false; return false;
} }

View File

@ -119,6 +119,7 @@ public:
PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn) { PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn) {
_igvn.set_delay_transform(true); _igvn.set_delay_transform(true);
} }
void eliminate_macro_nodes();
bool expand_macro_nodes(); bool expand_macro_nodes();
}; };

View File

@ -2661,6 +2661,8 @@ uint StrIntrinsicNode::match_edge(uint idx) const {
// control copies // control copies
Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this; if (remove_dead_region(phase, can_reshape)) return this;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
if (can_reshape) { if (can_reshape) {
Node* mem = phase->transform(in(MemNode::Memory)); Node* mem = phase->transform(in(MemNode::Memory));
@ -2675,6 +2677,12 @@ Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return NULL; return NULL;
} }
//------------------------------Value------------------------------------------
const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const {
if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP;
return bottom_type();
}
//============================================================================= //=============================================================================
MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent) MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent)
: MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)), : MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)),
@ -2715,6 +2723,8 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) {
// control copies // control copies
Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this; if (remove_dead_region(phase, can_reshape)) return this;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
// Eliminate volatile MemBars for scalar replaced objects. // Eliminate volatile MemBars for scalar replaced objects.
if (can_reshape && req() == (Precedent+1) && if (can_reshape && req() == (Precedent+1) &&

View File

@ -800,6 +800,7 @@ public:
virtual uint match_edge(uint idx) const; virtual uint match_edge(uint idx) const;
virtual uint ideal_reg() const { return Op_RegI; } virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
virtual const Type *Value(PhaseTransform *phase) const;
}; };
//------------------------------StrComp------------------------------------- //------------------------------StrComp-------------------------------------