mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-21 12:20:29 +00:00
8231291: C2: loop opts before EA should maximally unroll loops
Reviewed-by: kvn, vlivanov
This commit is contained in:
parent
1745ae28b9
commit
1af059d4cb
@ -1990,34 +1990,53 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
|
||||
if (in(1) != NULL && in(1)->Opcode() == Op_AddP && can_reshape) {
|
||||
// Try to undo Phi of AddP:
|
||||
// (Phi (AddP base base y) (AddP base2 base2 y))
|
||||
// (Phi (AddP base address offset) (AddP base2 address2 offset2))
|
||||
// becomes:
|
||||
// newbase := (Phi base base2)
|
||||
// (AddP newbase newbase y)
|
||||
// newaddress := (Phi address address2)
|
||||
// newoffset := (Phi offset offset2)
|
||||
// (AddP newbase newaddress newoffset)
|
||||
//
|
||||
// This occurs as a result of unsuccessful split_thru_phi and
|
||||
// interferes with taking advantage of addressing modes. See the
|
||||
// clone_shift_expressions code in matcher.cpp
|
||||
Node* addp = in(1);
|
||||
const Type* type = addp->in(AddPNode::Base)->bottom_type();
|
||||
Node* y = addp->in(AddPNode::Offset);
|
||||
if (y != NULL && addp->in(AddPNode::Base) == addp->in(AddPNode::Address)) {
|
||||
Node* base = addp->in(AddPNode::Base);
|
||||
Node* address = addp->in(AddPNode::Address);
|
||||
Node* offset = addp->in(AddPNode::Offset);
|
||||
if (base != NULL && address != NULL && offset != NULL &&
|
||||
!base->is_top() && !address->is_top() && !offset->is_top()) {
|
||||
const Type* base_type = base->bottom_type();
|
||||
const Type* address_type = address->bottom_type();
|
||||
// make sure that all the inputs are similar to the first one,
|
||||
// i.e. AddP with base == address and same offset as first AddP
|
||||
bool doit = true;
|
||||
for (uint i = 2; i < req(); i++) {
|
||||
if (in(i) == NULL ||
|
||||
in(i)->Opcode() != Op_AddP ||
|
||||
in(i)->in(AddPNode::Base) != in(i)->in(AddPNode::Address) ||
|
||||
in(i)->in(AddPNode::Offset) != y) {
|
||||
in(i)->in(AddPNode::Base) == NULL ||
|
||||
in(i)->in(AddPNode::Address) == NULL ||
|
||||
in(i)->in(AddPNode::Offset) == NULL ||
|
||||
in(i)->in(AddPNode::Base)->is_top() ||
|
||||
in(i)->in(AddPNode::Address)->is_top() ||
|
||||
in(i)->in(AddPNode::Offset)->is_top()) {
|
||||
doit = false;
|
||||
break;
|
||||
}
|
||||
if (in(i)->in(AddPNode::Offset) != base) {
|
||||
base = NULL;
|
||||
}
|
||||
if (in(i)->in(AddPNode::Offset) != offset) {
|
||||
offset = NULL;
|
||||
}
|
||||
if (in(i)->in(AddPNode::Address) != address) {
|
||||
address = NULL;
|
||||
}
|
||||
// Accumulate type for resulting Phi
|
||||
type = type->meet_speculative(in(i)->in(AddPNode::Base)->bottom_type());
|
||||
base_type = base_type->meet_speculative(in(i)->in(AddPNode::Base)->bottom_type());
|
||||
address_type = address_type->meet_speculative(in(i)->in(AddPNode::Base)->bottom_type());
|
||||
}
|
||||
Node* base = NULL;
|
||||
if (doit) {
|
||||
if (doit && base == NULL) {
|
||||
// Check for neighboring AddP nodes in a tree.
|
||||
// If they have a base, use that it.
|
||||
for (DUIterator_Fast kmax, k = this->fast_outs(kmax); k < kmax; k++) {
|
||||
@ -2035,13 +2054,27 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
}
|
||||
if (doit) {
|
||||
if (base == NULL) {
|
||||
base = new PhiNode(in(0), type, NULL);
|
||||
base = new PhiNode(in(0), base_type, NULL);
|
||||
for (uint i = 1; i < req(); i++) {
|
||||
base->init_req(i, in(i)->in(AddPNode::Base));
|
||||
}
|
||||
phase->is_IterGVN()->register_new_node_with_optimizer(base);
|
||||
}
|
||||
return new AddPNode(base, base, y);
|
||||
if (address == NULL) {
|
||||
address = new PhiNode(in(0), address_type, NULL);
|
||||
for (uint i = 1; i < req(); i++) {
|
||||
address->init_req(i, in(i)->in(AddPNode::Address));
|
||||
}
|
||||
phase->is_IterGVN()->register_new_node_with_optimizer(address);
|
||||
}
|
||||
if (offset == NULL) {
|
||||
offset = new PhiNode(in(0), TypeX_X, NULL);
|
||||
for (uint i = 1; i < req(); i++) {
|
||||
offset->init_req(i, in(i)->in(AddPNode::Offset));
|
||||
}
|
||||
phase->is_IterGVN()->register_new_node_with_optimizer(offset);
|
||||
}
|
||||
return new AddPNode(base, address, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2292,7 +2292,7 @@ void Compile::Optimize() {
|
||||
if (has_loops()) {
|
||||
// Cleanup graph (remove dead nodes).
|
||||
TracePhase tp("idealLoop", &timers[_t_idealLoop]);
|
||||
PhaseIdealLoop::optimize(igvn, LoopOptsNone);
|
||||
PhaseIdealLoop::optimize(igvn, LoopOptsMaxUnroll);
|
||||
if (major_progress()) print_method(PHASE_PHASEIDEAL_BEFORE_EA, 2);
|
||||
if (failing()) return;
|
||||
}
|
||||
|
||||
@ -93,6 +93,7 @@ struct Final_Reshape_Counts;
|
||||
enum LoopOptsMode {
|
||||
LoopOptsDefault,
|
||||
LoopOptsNone,
|
||||
LoopOptsMaxUnroll,
|
||||
LoopOptsShenandoahExpand,
|
||||
LoopOptsShenandoahPostExpand,
|
||||
LoopOptsSkipSplitIf,
|
||||
|
||||
@ -3014,6 +3014,33 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == LoopOptsMaxUnroll) {
|
||||
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
|
||||
IdealLoopTree* lpt = iter.current();
|
||||
if (lpt->is_innermost() && lpt->_allow_optimizations && !lpt->_has_call && lpt->is_counted()) {
|
||||
lpt->compute_trip_count(this);
|
||||
if (!lpt->do_one_iteration_loop(this) &&
|
||||
!lpt->do_remove_empty_loop(this)) {
|
||||
AutoNodeBudget node_budget(this);
|
||||
if (lpt->_head->as_CountedLoop()->is_normal_loop() &&
|
||||
lpt->policy_maximally_unroll(this)) {
|
||||
memset( worklist.adr(), 0, worklist.Size()*sizeof(Node*) );
|
||||
do_maximally_unroll(lpt, worklist);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
C->restore_major_progress(old_progress);
|
||||
|
||||
_igvn.optimize();
|
||||
|
||||
if (C->log() != NULL) {
|
||||
log_loop_tree(_ltree_root, _ltree_root, C->log());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bs->optimize_loops(this, mode, visited, nstack, worklist)) {
|
||||
_igvn.optimize();
|
||||
if (C->log() != NULL) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user