# HG changeset patch # User roland # Date 1431433591 -7200 # Node ID 3e7542b42a61fb2cd58954268aca56ac666d8e1c # Parent 328ac96a30d6af7167858b0475c38a66b052b9a5 8085832: Optimize main and post loop out when pre loop is found empty Summary: Eliminate main loop and post loop if pre loop becomes empty Reviewed-by: kvn, mcberg diff -r 328ac96a30d6 -r 3e7542b42a61 hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Mon Jun 08 18:35:17 2015 +0200 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Tue May 12 14:26:31 2015 +0200 @@ -475,7 +475,7 @@ C->set_major_progress(); // Peeling a 'main' loop in a pre/main/post situation obfuscates the - // 'pre' loop from the main and the 'pre' can no longer have it's + // 'pre' loop from the main and the 'pre' can no longer have its // iterations adjusted. Therefore, we need to declare this loop as // no longer a 'main' loop; it will need new pre and post loops before // we can do further RCE. @@ -1911,7 +1911,7 @@ return; assert(opqzm->in(1) == main_limit, "do not understand situation"); - // Find the pre-loop limit; we will expand it's iterations to + // Find the pre-loop limit; we will expand its iterations to // not ever trip low tests. Node *p_f = iffm->in(0); // pre loop may have been optimized out @@ -2218,6 +2218,56 @@ } } +#ifdef ASSERT +static CountedLoopNode* locate_pre_from_main(CountedLoopNode *cl) { + Node *ctrl = cl->in(LoopNode::EntryControl); + assert(ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, ""); + Node *iffm = ctrl->in(0); + assert(iffm->Opcode() == Op_If, ""); + Node *p_f = iffm->in(0); + assert(p_f->Opcode() == Op_IfFalse, ""); + CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd(); + assert(pre_end->loopnode()->is_pre_loop(), ""); + return pre_end->loopnode(); +} +#endif + +// Remove the main and post loops and make the pre loop execute all +// iterations. Useful when the pre loop is found empty. +void IdealLoopTree::remove_main_post_loops(CountedLoopNode *cl, PhaseIdealLoop *phase) { + CountedLoopEndNode* pre_end = cl->loopexit(); + Node* pre_cmp = pre_end->cmp_node(); + if (pre_cmp->in(2)->Opcode() != Op_Opaque1) { + // Only safe to remove the main loop if the compiler optimized it + // out based on an unknown number of iterations + return; + } + + // Can we find the main loop? + if (_next == NULL) { + return; + } + + Node* next_head = _next->_head; + if (!next_head->is_CountedLoop()) { + return; + } + + CountedLoopNode* main_head = next_head->as_CountedLoop(); + if (!main_head->is_main_loop()) { + return; + } + + assert(locate_pre_from_main(main_head) == cl, "bad main loop"); + Node* main_iff = main_head->in(LoopNode::EntryControl)->in(0); + + // Remove the Opaque1Node of the pre loop and make it execute all iterations + phase->_igvn.replace_input_of(pre_cmp, 2, pre_cmp->in(2)->in(2)); + // Remove the Opaque1Node of the main loop so it can be optimized out + Node* main_cmp = main_iff->in(1)->in(1); + assert(main_cmp->in(2)->Opcode() == Op_Opaque1, "main loop has no opaque node?"); + phase->_igvn.replace_input_of(main_cmp, 2, main_cmp->in(2)->in(1)); +} //------------------------------policy_do_remove_empty_loop-------------------- // Micro-benchmark spamming. Policy is to always remove empty loops. @@ -2236,6 +2286,12 @@ if (!phase->is_member(this, phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue)))) return false; // Infinite loop + if (cl->is_pre_loop()) { + // If the loop we are removing is a pre-loop then the main and + // post loop can be removed as well + remove_main_post_loops(cl, phase); + } + #ifdef ASSERT // Ensure only one phi which is the iv. Node* iv = NULL; diff -r 328ac96a30d6 -r 3e7542b42a61 hotspot/src/share/vm/opto/loopnode.hpp --- a/hotspot/src/share/vm/opto/loopnode.hpp Mon Jun 08 18:35:17 2015 +0200 +++ b/hotspot/src/share/vm/opto/loopnode.hpp Tue May 12 14:26:31 2015 +0200 @@ -485,6 +485,8 @@ bool is_inner() { return is_loop() && _child == NULL; } bool is_counted() { return is_loop() && _head != NULL && _head->is_CountedLoop(); } + void remove_main_post_loops(CountedLoopNode *cl, PhaseIdealLoop *phase); + #ifndef PRODUCT void dump_head( ) const; // Dump loop head only void dump() const; // Dump this loop recursively