8223363: Bad node estimate assertion failure
8223502: Node estimate for loop unswitching is not correct: assert(delta <= 2 * required) failed: Bad node estimate 8224648: assert(!exceeding_node_budget()) failed: Too many NODES required! failure with ctw Tighten the node estimates. New est_loop_clone_sz() implementation that will compute a "fan-out" complexity estimate as part of the size estimate (to better estimate complex loop body size after cloning). New est_loop_unroll_sz() function, used to estimate the size of a loop body att full/maximal unrolling. Correction to node budget final tests and asserts. Reviewed-by: neliasso, kvn
This commit is contained in:
parent
d36c7bad82
commit
d222b01dee
@ -286,6 +286,9 @@ Node* IdealLoopTree::reassociate_add_sub(Node* n1, PhaseIdealLoop *phase) {
|
|||||||
Node* n2 = n1->in(3 - inv1_idx);
|
Node* n2 = n1->in(3 - inv1_idx);
|
||||||
int inv2_idx = is_invariant_addition(n2, phase);
|
int inv2_idx = is_invariant_addition(n2, phase);
|
||||||
if (!inv2_idx) return NULL;
|
if (!inv2_idx) return NULL;
|
||||||
|
|
||||||
|
if (!phase->may_require_nodes(10, 10)) return NULL;
|
||||||
|
|
||||||
Node* x = n2->in(3 - inv2_idx);
|
Node* x = n2->in(3 - inv2_idx);
|
||||||
Node* inv2 = n2->in(inv2_idx);
|
Node* inv2 = n2->in(inv2_idx);
|
||||||
|
|
||||||
@ -337,61 +340,72 @@ void IdealLoopTree::reassociate_invariants(PhaseIdealLoop *phase) {
|
|||||||
Node* nn = reassociate_add_sub(n, phase);
|
Node* nn = reassociate_add_sub(n, phase);
|
||||||
if (nn == NULL) break;
|
if (nn == NULL) break;
|
||||||
n = nn; // again
|
n = nn; // again
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------policy_peeling---------------------------------
|
//------------------------------policy_peeling---------------------------------
|
||||||
// Return TRUE or FALSE if the loop should be peeled or not. Peel if we can
|
// Return TRUE if the loop should be peeled, otherwise return FALSE. Peeling
|
||||||
// make some loop-invariant test (usually a null-check) happen before the loop.
|
// is applicable if we can make a loop-invariant test (usually a null-check)
|
||||||
bool IdealLoopTree::policy_peeling(PhaseIdealLoop *phase) const {
|
// execute before we enter the loop. When TRUE, the estimated node budget is
|
||||||
IdealLoopTree *loop = (IdealLoopTree*)this;
|
// also requested.
|
||||||
|
bool IdealLoopTree::policy_peeling(PhaseIdealLoop *phase) {
|
||||||
|
uint estimate = estimate_peeling(phase);
|
||||||
|
|
||||||
|
return estimate == 0 ? false : phase->may_require_nodes(estimate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform actual policy and size estimate for the loop peeling transform, and
|
||||||
|
// return the estimated loop size if peeling is applicable, otherwise return
|
||||||
|
// zero. No node budget is allocated.
|
||||||
|
uint IdealLoopTree::estimate_peeling(PhaseIdealLoop *phase) {
|
||||||
|
|
||||||
// If nodes are depleted, some transform has miscalculated its needs.
|
// If nodes are depleted, some transform has miscalculated its needs.
|
||||||
assert(!phase->exceeding_node_budget(), "sanity");
|
assert(!phase->exceeding_node_budget(), "sanity");
|
||||||
|
|
||||||
uint body_size = loop->_body.size();
|
// Peeling does loop cloning which can result in O(N^2) node construction.
|
||||||
// Peeling does loop cloning which can result in O(N^2) node construction
|
if (_body.size() > 255) {
|
||||||
if (body_size > 255) {
|
return 0; // Suppress too large body size.
|
||||||
return false; // Prevent overflow for large body size
|
|
||||||
}
|
}
|
||||||
uint estimate = body_size * body_size;
|
// Optimistic estimate that approximates loop body complexity via data and
|
||||||
|
// control flow fan-out (instead of using the more pessimistic: BodySize^2).
|
||||||
|
uint estimate = est_loop_clone_sz(2);
|
||||||
|
|
||||||
if (phase->exceeding_node_budget(estimate)) {
|
if (phase->exceeding_node_budget(estimate)) {
|
||||||
return false; // Too large to safely clone
|
return 0; // Too large to safely clone.
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for vectorized loops, any peeling done was already applied
|
// Check for vectorized loops, any peeling done was already applied.
|
||||||
if (_head->is_CountedLoop()) {
|
if (_head->is_CountedLoop()) {
|
||||||
CountedLoopNode* cl = _head->as_CountedLoop();
|
CountedLoopNode* cl = _head->as_CountedLoop();
|
||||||
if (cl->is_unroll_only() || cl->trip_count() == 1) {
|
if (cl->is_unroll_only() || cl->trip_count() == 1) {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* test = loop->tail();
|
Node* test = tail();
|
||||||
|
|
||||||
while (test != _head) { // Scan till run off top of loop
|
while (test != _head) { // Scan till run off top of loop
|
||||||
if (test->is_If()) { // Test?
|
if (test->is_If()) { // Test?
|
||||||
Node *ctrl = phase->get_ctrl(test->in(1));
|
Node *ctrl = phase->get_ctrl(test->in(1));
|
||||||
if (ctrl->is_top()) {
|
if (ctrl->is_top()) {
|
||||||
return false; // Found dead test on live IF? No peeling!
|
return 0; // Found dead test on live IF? No peeling!
|
||||||
}
|
}
|
||||||
// Standard IF only has one input value to check for loop invariance
|
// Standard IF only has one input value to check for loop invariance.
|
||||||
assert(test->Opcode() == Op_If ||
|
assert(test->Opcode() == Op_If ||
|
||||||
test->Opcode() == Op_CountedLoopEnd ||
|
test->Opcode() == Op_CountedLoopEnd ||
|
||||||
test->Opcode() == Op_RangeCheck,
|
test->Opcode() == Op_RangeCheck,
|
||||||
"Check this code when new subtype is added");
|
"Check this code when new subtype is added");
|
||||||
// Condition is not a member of this loop?
|
// Condition is not a member of this loop?
|
||||||
if (!is_member(phase->get_loop(ctrl)) && is_loop_exit(test)) {
|
if (!is_member(phase->get_loop(ctrl)) && is_loop_exit(test)) {
|
||||||
// Found reason to peel!
|
return estimate; // Found reason to peel!
|
||||||
return phase->may_require_nodes(estimate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Walk up dominators to loop _head looking for test which is
|
// Walk up dominators to loop _head looking for test which is executed on
|
||||||
// executed on every path thru loop.
|
// every path through the loop.
|
||||||
test = phase->idom(test);
|
test = phase->idom(test);
|
||||||
}
|
}
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------peeled_dom_test_elim---------------------------
|
//------------------------------peeled_dom_test_elim---------------------------
|
||||||
@ -638,8 +652,8 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Step 4: Correct dom-depth info. Set to loop-head depth.
|
// Step 4: Correct dom-depth info. Set to loop-head depth.
|
||||||
|
|
||||||
int dd = dom_depth(head);
|
int dd = dom_depth(head);
|
||||||
set_idom(head, head->in(1), dd);
|
set_idom(head, head->in(1), dd);
|
||||||
for (uint j3 = 0; j3 < loop->_body.size(); j3++) {
|
for (uint j3 = 0; j3 < loop->_body.size(); j3++) {
|
||||||
@ -657,11 +671,30 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) {
|
|||||||
loop->record_for_igvn();
|
loop->record_for_igvn();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EMPTY_LOOP_SIZE 7 // number of nodes in an empty loop
|
// The Estimated Loop Unroll Size: UnrollFactor * (106% * BodySize + BC) + CC,
|
||||||
|
// where BC and CC are (totally) ad-hoc/magic "body" and "clone" constants,
|
||||||
|
// respectively, used to ensure that node usage estimates made are on the safe
|
||||||
|
// side, for the most part. This is a simplified version of the loop clone
|
||||||
|
// size calculation in est_loop_clone_sz(), defined for unroll factors larger
|
||||||
|
// than one (>1), performing an overflow check and returning 'UINT_MAX' in
|
||||||
|
// case of an overflow.
|
||||||
|
static uint est_loop_unroll_sz(uint factor, uint size) {
|
||||||
|
precond(0 < factor);
|
||||||
|
|
||||||
|
uint const bc = 5;
|
||||||
|
uint const cc = 7;
|
||||||
|
uint const sz = size + (size + 15) / 16;
|
||||||
|
uint estimate = factor * (sz + bc) + cc;
|
||||||
|
|
||||||
|
return (estimate - cc) / factor == sz + bc ? estimate : UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EMPTY_LOOP_SIZE 7 // Number of nodes in an empty loop.
|
||||||
|
|
||||||
//------------------------------policy_maximally_unroll------------------------
|
//------------------------------policy_maximally_unroll------------------------
|
||||||
// Calculate exact loop trip count and return true if loop can be maximally
|
// Calculate the exact loop trip-count and return TRUE if loop can be fully,
|
||||||
// unrolled.
|
// i.e. maximally, unrolled, otherwise return FALSE. When TRUE, the estimated
|
||||||
|
// node budget is also requested.
|
||||||
bool IdealLoopTree::policy_maximally_unroll(PhaseIdealLoop *phase) const {
|
bool IdealLoopTree::policy_maximally_unroll(PhaseIdealLoop *phase) const {
|
||||||
CountedLoopNode *cl = _head->as_CountedLoop();
|
CountedLoopNode *cl = _head->as_CountedLoop();
|
||||||
assert(cl->is_normal_loop(), "");
|
assert(cl->is_normal_loop(), "");
|
||||||
@ -693,7 +726,7 @@ bool IdealLoopTree::policy_maximally_unroll(PhaseIdealLoop *phase) const {
|
|||||||
|
|
||||||
// Take into account that after unroll conjoined heads and tails will fold,
|
// Take into account that after unroll conjoined heads and tails will fold,
|
||||||
// otherwise policy_unroll() may allow more unrolling than max unrolling.
|
// otherwise policy_unroll() may allow more unrolling than max unrolling.
|
||||||
uint new_body_size = est_loop_clone_sz(trip_count, body_size - EMPTY_LOOP_SIZE);
|
uint new_body_size = est_loop_unroll_sz(trip_count, body_size - EMPTY_LOOP_SIZE);
|
||||||
|
|
||||||
if (new_body_size == UINT_MAX) { // Check for bad estimate (overflow).
|
if (new_body_size == UINT_MAX) { // Check for bad estimate (overflow).
|
||||||
return false;
|
return false;
|
||||||
@ -742,8 +775,9 @@ bool IdealLoopTree::policy_maximally_unroll(PhaseIdealLoop *phase) const {
|
|||||||
|
|
||||||
|
|
||||||
//------------------------------policy_unroll----------------------------------
|
//------------------------------policy_unroll----------------------------------
|
||||||
// Return TRUE or FALSE if the loop should be unrolled or not. Unroll if the
|
// Return TRUE or FALSE if the loop should be unrolled or not. Apply unroll if
|
||||||
// loop is a CountedLoop and the body is small enough.
|
// the loop is a counted loop and the loop body is small enough. When TRUE,
|
||||||
|
// the estimated node budget is also requested.
|
||||||
bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) {
|
bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) {
|
||||||
|
|
||||||
CountedLoopNode *cl = _head->as_CountedLoop();
|
CountedLoopNode *cl = _head->as_CountedLoop();
|
||||||
@ -887,7 +921,7 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) {
|
|||||||
LoopMaxUnroll = slp_max_unroll_factor;
|
LoopMaxUnroll = slp_max_unroll_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint estimate = est_loop_clone_sz(2, body_size);
|
uint estimate = est_loop_clone_sz(2);
|
||||||
|
|
||||||
if (cl->has_passed_slp()) {
|
if (cl->has_passed_slp()) {
|
||||||
if (slp_max_unroll_factor >= future_unroll_cnt) {
|
if (slp_max_unroll_factor >= future_unroll_cnt) {
|
||||||
@ -958,8 +992,10 @@ bool IdealLoopTree::policy_align(PhaseIdealLoop *phase) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------policy_range_check-----------------------------
|
//------------------------------policy_range_check-----------------------------
|
||||||
// Return TRUE or FALSE if the loop should be range-check-eliminated.
|
// Return TRUE or FALSE if the loop should be range-check-eliminated or not.
|
||||||
// Actually we do iteration-splitting, a more powerful form of RCE.
|
// When TRUE, the estimated node budget is also requested.
|
||||||
|
//
|
||||||
|
// We will actually perform iteration-splitting, a more powerful form of RCE.
|
||||||
bool IdealLoopTree::policy_range_check(PhaseIdealLoop *phase) const {
|
bool IdealLoopTree::policy_range_check(PhaseIdealLoop *phase) const {
|
||||||
if (!RangeCheckElimination) return false;
|
if (!RangeCheckElimination) return false;
|
||||||
|
|
||||||
@ -967,9 +1003,9 @@ bool IdealLoopTree::policy_range_check(PhaseIdealLoop *phase) const {
|
|||||||
assert(!phase->exceeding_node_budget(), "sanity");
|
assert(!phase->exceeding_node_budget(), "sanity");
|
||||||
|
|
||||||
CountedLoopNode *cl = _head->as_CountedLoop();
|
CountedLoopNode *cl = _head->as_CountedLoop();
|
||||||
// If we unrolled with no intention of doing RCE and we later
|
// If we unrolled with no intention of doing RCE and we later changed our
|
||||||
// changed our minds, we got no pre-loop. Either we need to
|
// minds, we got no pre-loop. Either we need to make a new pre-loop, or we
|
||||||
// make a new pre-loop, or we gotta disallow RCE.
|
// have to disallow RCE.
|
||||||
if (cl->is_main_no_pre_loop()) return false; // Disallowed for now.
|
if (cl->is_main_no_pre_loop()) return false; // Disallowed for now.
|
||||||
Node *trip_counter = cl->phi();
|
Node *trip_counter = cl->phi();
|
||||||
|
|
||||||
@ -1016,13 +1052,13 @@ bool IdealLoopTree::policy_range_check(PhaseIdealLoop *phase) const {
|
|||||||
if (!phase->is_scaled_iv_plus_offset(rc_exp, trip_counter, NULL, NULL)) {
|
if (!phase->is_scaled_iv_plus_offset(rc_exp, trip_counter, NULL, NULL)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Found a test like 'trip+off vs limit'. Test is an IfNode, has two
|
// Found a test like 'trip+off vs limit'. Test is an IfNode, has two (2)
|
||||||
// (2) projections. If BOTH are in the loop we need loop unswitching
|
// projections. If BOTH are in the loop we need loop unswitching instead
|
||||||
// instead of iteration splitting.
|
// of iteration splitting.
|
||||||
if (is_loop_exit(iff)) {
|
if (is_loop_exit(iff)) {
|
||||||
// Found valid reason to split iterations (if there is room).
|
// Found valid reason to split iterations (if there is room).
|
||||||
// NOTE: Usually a gross overestimate.
|
// NOTE: Usually a gross overestimate.
|
||||||
return phase->may_require_nodes(est_loop_clone_sz(2, _body.size()));
|
return phase->may_require_nodes(est_loop_clone_sz(2));
|
||||||
}
|
}
|
||||||
} // End of is IF
|
} // End of is IF
|
||||||
}
|
}
|
||||||
@ -1521,9 +1557,6 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old
|
|||||||
// only process vectorized main loops
|
// only process vectorized main loops
|
||||||
if (!cl->is_vectorized_loop() || !cl->is_main_loop()) return;
|
if (!cl->is_vectorized_loop() || !cl->is_main_loop()) return;
|
||||||
|
|
||||||
if (!may_require_nodes(est_loop_clone_sz(2, loop->_body.size()))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int slp_max_unroll_factor = cl->slp_max_unroll();
|
int slp_max_unroll_factor = cl->slp_max_unroll();
|
||||||
int cur_unroll = cl->unrolled_count();
|
int cur_unroll = cl->unrolled_count();
|
||||||
|
|
||||||
@ -1535,6 +1568,10 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old
|
|||||||
// we only ever process this one time
|
// we only ever process this one time
|
||||||
if (cl->has_atomic_post_loop()) return;
|
if (cl->has_atomic_post_loop()) return;
|
||||||
|
|
||||||
|
if (!may_require_nodes(loop->est_loop_clone_sz(2))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (TraceLoopOpts) {
|
if (TraceLoopOpts) {
|
||||||
tty->print("PostVector ");
|
tty->print("PostVector ");
|
||||||
@ -3178,9 +3215,6 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n
|
|||||||
|
|
||||||
AutoNodeBudget node_budget(phase);
|
AutoNodeBudget node_budget(phase);
|
||||||
|
|
||||||
bool should_peel = policy_peeling(phase);
|
|
||||||
bool should_unswitch = policy_unswitching(phase);
|
|
||||||
|
|
||||||
// Non-counted loops may be peeled; exactly 1 iteration is peeled.
|
// Non-counted loops may be peeled; exactly 1 iteration is peeled.
|
||||||
// This removes loop-invariant tests (usually null checks).
|
// This removes loop-invariant tests (usually null checks).
|
||||||
if (!_head->is_CountedLoop()) { // Non-counted loop
|
if (!_head->is_CountedLoop()) { // Non-counted loop
|
||||||
@ -3188,10 +3222,10 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n
|
|||||||
// Partial peel succeeded so terminate this round of loop opts
|
// Partial peel succeeded so terminate this round of loop opts
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (should_peel) { // Should we peel?
|
if (policy_peeling(phase)) { // Should we peel?
|
||||||
if (PrintOpto) { tty->print_cr("should_peel"); }
|
if (PrintOpto) { tty->print_cr("should_peel"); }
|
||||||
phase->do_peeling(this,old_new);
|
phase->do_peeling(this, old_new);
|
||||||
} else if (should_unswitch) {
|
} else if (policy_unswitching(phase)) {
|
||||||
phase->do_unswitching(this, old_new);
|
phase->do_unswitching(this, old_new);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -3209,12 +3243,11 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n
|
|||||||
// Before attempting fancy unrolling, RCE or alignment, see if we want
|
// Before attempting fancy unrolling, RCE or alignment, see if we want
|
||||||
// to completely unroll this loop or do loop unswitching.
|
// to completely unroll this loop or do loop unswitching.
|
||||||
if (cl->is_normal_loop()) {
|
if (cl->is_normal_loop()) {
|
||||||
if (should_unswitch) {
|
if (policy_unswitching(phase)) {
|
||||||
phase->do_unswitching(this, old_new);
|
phase->do_unswitching(this, old_new);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool should_maximally_unroll = policy_maximally_unroll(phase);
|
if (policy_maximally_unroll(phase)) {
|
||||||
if (should_maximally_unroll) {
|
|
||||||
// Here we did some unrolling and peeling. Eventually we will
|
// Here we did some unrolling and peeling. Eventually we will
|
||||||
// completely unroll this loop and it will no longer be a loop.
|
// completely unroll this loop and it will no longer be a loop.
|
||||||
phase->do_maximally_unroll(this, old_new);
|
phase->do_maximally_unroll(this, old_new);
|
||||||
@ -3222,6 +3255,9 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint est_peeling = estimate_peeling(phase);
|
||||||
|
bool should_peel = 0 < est_peeling;
|
||||||
|
|
||||||
// Counted loops may be peeled, may need some iterations run up
|
// Counted loops may be peeled, may need some iterations run up
|
||||||
// front for RCE, and may want to align loop refs to a cache
|
// front for RCE, and may want to align loop refs to a cache
|
||||||
// line. Thus we clone a full loop up front whose trip count is
|
// line. Thus we clone a full loop up front whose trip count is
|
||||||
@ -3252,14 +3288,15 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n
|
|||||||
// peeling.
|
// peeling.
|
||||||
if (should_rce || should_align || should_unroll) {
|
if (should_rce || should_align || should_unroll) {
|
||||||
if (cl->is_normal_loop()) { // Convert to 'pre/main/post' loops
|
if (cl->is_normal_loop()) { // Convert to 'pre/main/post' loops
|
||||||
if (!phase->may_require_nodes(est_loop_clone_sz(3, _body.size()))) {
|
uint estimate = est_loop_clone_sz(3);
|
||||||
|
if (!phase->may_require_nodes(estimate)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
phase->insert_pre_post_loops(this,old_new, !may_rce_align);
|
phase->insert_pre_post_loops(this, old_new, !may_rce_align);
|
||||||
}
|
}
|
||||||
// Adjust the pre- and main-loop limits to let the pre and post loops run
|
// Adjust the pre- and main-loop limits to let the pre and post loops run
|
||||||
// with full checks, but the main-loop with no checks. Remove said
|
// with full checks, but the main-loop with no checks. Remove said checks
|
||||||
// checks from the main body.
|
// from the main body.
|
||||||
if (should_rce) {
|
if (should_rce) {
|
||||||
if (phase->do_range_check(this, old_new) != 0) {
|
if (phase->do_range_check(this, old_new) != 0) {
|
||||||
cl->mark_has_range_checks();
|
cl->mark_has_range_checks();
|
||||||
@ -3293,7 +3330,9 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n
|
|||||||
}
|
}
|
||||||
} else { // Else we have an unchanged counted loop
|
} else { // Else we have an unchanged counted loop
|
||||||
if (should_peel) { // Might want to peel but do nothing else
|
if (should_peel) { // Might want to peel but do nothing else
|
||||||
phase->do_peeling(this,old_new);
|
if (phase->may_require_nodes(est_peeling)) {
|
||||||
|
phase->do_peeling(this, old_new);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -79,7 +79,7 @@ bool IdealLoopTree::policy_unswitching( PhaseIdealLoop *phase ) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Too speculative if running low on nodes.
|
// Too speculative if running low on nodes.
|
||||||
return phase->may_require_nodes(est_loop_clone_sz(3, _body.size()));
|
return phase->may_require_nodes(est_loop_clone_sz(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------find_unswitching_candidate-----------------------------
|
//------------------------------find_unswitching_candidate-----------------------------
|
||||||
@ -116,7 +116,7 @@ IfNode* PhaseIdealLoop::find_unswitching_candidate(const IdealLoopTree *loop) co
|
|||||||
// Clone loop with an invariant test (that does not exit) and
|
// Clone loop with an invariant test (that does not exit) and
|
||||||
// insert a clone of the test that selects which version to
|
// insert a clone of the test that selects which version to
|
||||||
// execute.
|
// execute.
|
||||||
void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) {
|
void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new) {
|
||||||
|
|
||||||
// Find first invariant test that doesn't exit the loop
|
// Find first invariant test that doesn't exit the loop
|
||||||
LoopNode *head = loop->_head->as_Loop();
|
LoopNode *head = loop->_head->as_Loop();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2439,12 +2439,63 @@ void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) {
|
|||||||
if (loop->_next) loop->_next ->counted_loop(phase);
|
if (loop->_next) loop->_next ->counted_loop(phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The Estimated Loop Clone Size:
|
||||||
|
// CloneFactor * (~112% * BodySize + BC) + CC + FanOutTerm,
|
||||||
|
// where BC and CC are totally ad-hoc/magic "body" and "clone" constants,
|
||||||
|
// respectively, used to ensure that the node usage estimates made are on the
|
||||||
|
// safe side, for the most part. The FanOutTerm is an attempt to estimate the
|
||||||
|
// possible additional/excessive nodes generated due to data and control flow
|
||||||
|
// merging, for edges reaching outside the loop.
|
||||||
|
uint IdealLoopTree::est_loop_clone_sz(uint factor) const {
|
||||||
|
|
||||||
|
precond(0 < factor && factor < 16);
|
||||||
|
|
||||||
|
uint const bc = 13;
|
||||||
|
uint const cc = 17;
|
||||||
|
uint const sz = _body.size() + (_body.size() + 7) / 8;
|
||||||
|
uint estimate = factor * (sz + bc) + cc;
|
||||||
|
|
||||||
|
assert((estimate - cc) / factor == sz + bc, "overflow");
|
||||||
|
|
||||||
|
uint ctrl_edge_out_cnt = 0;
|
||||||
|
uint data_edge_out_cnt = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < _body.size(); i++) {
|
||||||
|
Node* node = _body.at(i);
|
||||||
|
uint outcnt = node->outcnt();
|
||||||
|
|
||||||
|
for (uint k = 0; k < outcnt; k++) {
|
||||||
|
Node* out = node->raw_out(k);
|
||||||
|
|
||||||
|
if (out->is_CFG()) {
|
||||||
|
if (!is_member(_phase->get_loop(out))) {
|
||||||
|
ctrl_edge_out_cnt++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Node* ctrl = _phase->get_ctrl(out);
|
||||||
|
assert(ctrl->is_CFG(), "must be");
|
||||||
|
if (!is_member(_phase->get_loop(ctrl))) {
|
||||||
|
data_edge_out_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add data (x1.5) and control (x1.0) count to estimate iff both are > 0.
|
||||||
|
if (ctrl_edge_out_cnt > 0 && data_edge_out_cnt > 0) {
|
||||||
|
estimate += ctrl_edge_out_cnt + data_edge_out_cnt + data_edge_out_cnt / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return estimate;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
//------------------------------dump_head--------------------------------------
|
//------------------------------dump_head--------------------------------------
|
||||||
// Dump 1 liner for loop header info
|
// Dump 1 liner for loop header info
|
||||||
void IdealLoopTree::dump_head( ) const {
|
void IdealLoopTree::dump_head() const {
|
||||||
for (uint i=0; i<_nest; i++)
|
for (uint i = 0; i < _nest; i++) {
|
||||||
tty->print(" ");
|
tty->print(" ");
|
||||||
|
}
|
||||||
tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx);
|
tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx);
|
||||||
if (_irreducible) tty->print(" IRREDUCIBLE");
|
if (_irreducible) tty->print(" IRREDUCIBLE");
|
||||||
Node* entry = _head->is_Loop() ? _head->as_Loop()->skip_strip_mined(-1)->in(LoopNode::EntryControl) : _head->in(LoopNode::EntryControl);
|
Node* entry = _head->is_Loop() ? _head->as_Loop()->skip_strip_mined(-1)->in(LoopNode::EntryControl) : _head->in(LoopNode::EntryControl);
|
||||||
@ -2513,7 +2564,7 @@ void IdealLoopTree::dump_head( ) const {
|
|||||||
|
|
||||||
//------------------------------dump-------------------------------------------
|
//------------------------------dump-------------------------------------------
|
||||||
// Dump loops by loop tree
|
// Dump loops by loop tree
|
||||||
void IdealLoopTree::dump( ) const {
|
void IdealLoopTree::dump() const {
|
||||||
dump_head();
|
dump_head();
|
||||||
if (_child) _child->dump();
|
if (_child) _child->dump();
|
||||||
if (_next) _next ->dump();
|
if (_next) _next ->dump();
|
||||||
@ -2908,8 +2959,8 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
|||||||
assert(C->unique() == unique, "non-optimize mode made Nodes? ? ?");
|
assert(C->unique() == unique, "non-optimize mode made Nodes? ? ?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(VerifyLoopOptimizations) verify();
|
if (VerifyLoopOptimizations) verify();
|
||||||
if(TraceLoopOpts && C->has_loops()) {
|
if (TraceLoopOpts && C->has_loops()) {
|
||||||
_ltree_root->dump();
|
_ltree_root->dump();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2938,7 +2989,6 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ReassociateInvariants) {
|
if (ReassociateInvariants) {
|
||||||
AutoNodeBudget node_budget(this, AutoNodeBudget::NO_BUDGET_CHECK);
|
|
||||||
// Reassociate invariants and prep for split_thru_phi
|
// Reassociate invariants and prep for split_thru_phi
|
||||||
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
|
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
|
||||||
IdealLoopTree* lpt = iter.current();
|
IdealLoopTree* lpt = iter.current();
|
||||||
@ -2946,14 +2996,17 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
|||||||
if (!is_counted || !lpt->is_innermost()) continue;
|
if (!is_counted || !lpt->is_innermost()) continue;
|
||||||
|
|
||||||
// check for vectorized loops, any reassociation of invariants was already done
|
// check for vectorized loops, any reassociation of invariants was already done
|
||||||
if (is_counted && lpt->_head->as_CountedLoop()->is_unroll_only()) continue;
|
if (is_counted && lpt->_head->as_CountedLoop()->is_unroll_only()) {
|
||||||
|
continue;
|
||||||
lpt->reassociate_invariants(this);
|
} else {
|
||||||
|
AutoNodeBudget node_budget(this);
|
||||||
|
lpt->reassociate_invariants(this);
|
||||||
|
}
|
||||||
// Because RCE opportunities can be masked by split_thru_phi,
|
// Because RCE opportunities can be masked by split_thru_phi,
|
||||||
// look for RCE candidates and inhibit split_thru_phi
|
// look for RCE candidates and inhibit split_thru_phi
|
||||||
// on just their loop-phi's for this pass of loop opts
|
// on just their loop-phi's for this pass of loop opts
|
||||||
if (SplitIfBlocks && do_split_ifs) {
|
if (SplitIfBlocks && do_split_ifs) {
|
||||||
|
AutoNodeBudget node_budget(this, AutoNodeBudget::NO_BUDGET_CHECK);
|
||||||
if (lpt->policy_range_check(this)) {
|
if (lpt->policy_range_check(this)) {
|
||||||
lpt->_rce_candidate = 1; // = true
|
lpt->_rce_candidate = 1; // = true
|
||||||
}
|
}
|
||||||
|
@ -589,17 +589,18 @@ public:
|
|||||||
// Convert one iteration loop into normal code.
|
// Convert one iteration loop into normal code.
|
||||||
bool do_one_iteration_loop( PhaseIdealLoop *phase );
|
bool do_one_iteration_loop( PhaseIdealLoop *phase );
|
||||||
|
|
||||||
// Return TRUE or FALSE if the loop should be peeled or not. Peel if we can
|
// Return TRUE or FALSE if the loop should be peeled or not. Peel if we can
|
||||||
// make some loop-invariant test (usually a null-check) happen before the
|
// move some loop-invariant test (usually a null-check) before the loop.
|
||||||
// loop.
|
bool policy_peeling(PhaseIdealLoop *phase);
|
||||||
bool policy_peeling( PhaseIdealLoop *phase ) const;
|
|
||||||
|
uint estimate_peeling(PhaseIdealLoop *phase);
|
||||||
|
|
||||||
// Return TRUE or FALSE if the loop should be maximally unrolled. Stash any
|
// Return TRUE or FALSE if the loop should be maximally unrolled. Stash any
|
||||||
// known trip count in the counted loop node.
|
// known trip count in the counted loop node.
|
||||||
bool policy_maximally_unroll( PhaseIdealLoop *phase ) const;
|
bool policy_maximally_unroll(PhaseIdealLoop *phase) const;
|
||||||
|
|
||||||
// Return TRUE or FALSE if the loop should be unrolled or not. Unroll if
|
// Return TRUE or FALSE if the loop should be unrolled or not. Apply unroll
|
||||||
// the loop is a CountedLoop and the body is small enough.
|
// if the loop is a counted loop and the loop body is small enough.
|
||||||
bool policy_unroll(PhaseIdealLoop *phase);
|
bool policy_unroll(PhaseIdealLoop *phase);
|
||||||
|
|
||||||
// Loop analyses to map to a maximal superword unrolling for vectorization.
|
// Loop analyses to map to a maximal superword unrolling for vectorization.
|
||||||
@ -620,6 +621,9 @@ public:
|
|||||||
// Return TRUE if "iff" is a range check.
|
// Return TRUE if "iff" is a range check.
|
||||||
bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const;
|
bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const;
|
||||||
|
|
||||||
|
// Estimate the number of nodes required when cloning a loop (body).
|
||||||
|
uint est_loop_clone_sz(uint factor) const;
|
||||||
|
|
||||||
// Compute loop trip count if possible
|
// Compute loop trip count if possible
|
||||||
void compute_trip_count(PhaseIdealLoop* phase);
|
void compute_trip_count(PhaseIdealLoop* phase);
|
||||||
|
|
||||||
@ -1356,50 +1360,66 @@ private:
|
|||||||
// < UINT_MAX Nodes currently requested (estimate).
|
// < UINT_MAX Nodes currently requested (estimate).
|
||||||
uint _nodes_required;
|
uint _nodes_required;
|
||||||
|
|
||||||
|
enum { REQUIRE_MIN = 70 };
|
||||||
|
|
||||||
|
uint nodes_required() const { return _nodes_required; }
|
||||||
|
|
||||||
|
// Given the _currently_ available number of nodes, check whether there is
|
||||||
|
// "room" for an additional request or not, considering the already required
|
||||||
|
// number of nodes. Return TRUE if the new request is exceeding the node
|
||||||
|
// budget limit, otherwise return FALSE. Note that this interpretation will
|
||||||
|
// act pessimistic on additional requests when new nodes have already been
|
||||||
|
// generated since the 'begin'. This behaviour fits with the intention that
|
||||||
|
// node estimates/requests should be made upfront.
|
||||||
bool exceeding_node_budget(uint required = 0) {
|
bool exceeding_node_budget(uint required = 0) {
|
||||||
assert(C->live_nodes() < C->max_node_limit(), "sanity");
|
assert(C->live_nodes() < C->max_node_limit(), "sanity");
|
||||||
uint available = C->max_node_limit() - C->live_nodes();
|
uint available = C->max_node_limit() - C->live_nodes();
|
||||||
return available < required + _nodes_required;
|
return available < required + _nodes_required;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint require_nodes(uint require) {
|
uint require_nodes(uint require, uint minreq = REQUIRE_MIN) {
|
||||||
precond(require > 0);
|
precond(require > 0);
|
||||||
_nodes_required += MAX2(100u, require); // Keep requests at minimum 100.
|
_nodes_required += MAX2(require, minreq);
|
||||||
return _nodes_required;
|
return _nodes_required;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool may_require_nodes(uint require) {
|
bool may_require_nodes(uint require, uint minreq = REQUIRE_MIN) {
|
||||||
return !exceeding_node_budget(require) && require_nodes(require) > 0;
|
return !exceeding_node_budget(require) && require_nodes(require, minreq) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void require_nodes_begin() {
|
uint require_nodes_begin() {
|
||||||
assert(_nodes_required == UINT_MAX, "Bad state (begin).");
|
assert(_nodes_required == UINT_MAX, "Bad state (begin).");
|
||||||
_nodes_required = 0;
|
_nodes_required = 0;
|
||||||
|
return C->live_nodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final check that the requested nodes did not exceed the limit and that
|
// When a node request is final, optionally check that the requested number
|
||||||
// the request was reasonably correct with respect to the number of new
|
// of nodes was reasonably correct with respect to the number of new nodes
|
||||||
// nodes introduced by any transform since the last 'begin'.
|
// introduced since the last 'begin'. Always check that we have not exceeded
|
||||||
void require_nodes_final_check(uint live_at_begin) {
|
// the maximum node limit.
|
||||||
uint required = _nodes_required;
|
void require_nodes_final(uint live_at_begin, bool check_estimate) {
|
||||||
require_nodes_final();
|
|
||||||
uint delta = C->live_nodes() - live_at_begin;
|
|
||||||
// Assert is disabled, see JDK-8223911 and related issues.
|
|
||||||
assert(true || delta <= 2 * required, "Bad node estimate (actual: %d, request: %d)",
|
|
||||||
delta, required);
|
|
||||||
}
|
|
||||||
|
|
||||||
void require_nodes_final() {
|
|
||||||
assert(_nodes_required < UINT_MAX, "Bad state (final).");
|
assert(_nodes_required < UINT_MAX, "Bad state (final).");
|
||||||
assert(!exceeding_node_budget(), "Too many NODES required!");
|
|
||||||
|
if (check_estimate) {
|
||||||
|
// Assert that the node budget request was not off by too much (x2).
|
||||||
|
// Should this be the case we _surely_ need to improve the estimates
|
||||||
|
// used in our budget calculations.
|
||||||
|
assert(C->live_nodes() - live_at_begin <= 2 * _nodes_required,
|
||||||
|
"Bad node estimate: actual = %d >> request = %d",
|
||||||
|
C->live_nodes() - live_at_begin, _nodes_required);
|
||||||
|
}
|
||||||
|
// Assert that we have stayed within the node budget limit.
|
||||||
|
assert(C->live_nodes() < C->max_node_limit(),
|
||||||
|
"Exceeding node budget limit: %d + %d > %d (request = %d)",
|
||||||
|
C->live_nodes() - live_at_begin, live_at_begin,
|
||||||
|
C->max_node_limit(), _nodes_required);
|
||||||
|
|
||||||
_nodes_required = UINT_MAX;
|
_nodes_required = UINT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _created_loop_node;
|
bool _created_loop_node;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint nodes_required() const { return _nodes_required; }
|
|
||||||
|
|
||||||
void set_created_loop_node() { _created_loop_node = true; }
|
void set_created_loop_node() { _created_loop_node = true; }
|
||||||
bool created_loop_node() { return _created_loop_node; }
|
bool created_loop_node() { return _created_loop_node; }
|
||||||
void register_new_node( Node *n, Node *blk );
|
void register_new_node( Node *n, Node *blk );
|
||||||
@ -1438,29 +1458,30 @@ public:
|
|||||||
{
|
{
|
||||||
precond(_phase != NULL);
|
precond(_phase != NULL);
|
||||||
|
|
||||||
_nodes_at_begin = _phase->C->live_nodes();
|
_nodes_at_begin = _phase->require_nodes_begin();
|
||||||
_phase->require_nodes_begin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~AutoNodeBudget() {
|
~AutoNodeBudget() {
|
||||||
if (_check_at_final) {
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (TraceLoopOpts) {
|
if (TraceLoopOpts) {
|
||||||
uint request = _phase->nodes_required();
|
uint request = _phase->nodes_required();
|
||||||
|
uint delta = _phase->C->live_nodes() - _nodes_at_begin;
|
||||||
|
|
||||||
if (request > 0) {
|
if (request < delta) {
|
||||||
uint delta = _phase->C->live_nodes() - _nodes_at_begin;
|
tty->print_cr("Exceeding node budget: %d < %d", request, delta);
|
||||||
|
} else {
|
||||||
if (request < delta) {
|
uint const REQUIRE_MIN = PhaseIdealLoop::REQUIRE_MIN;
|
||||||
tty->print_cr("Exceeding node budget: %d < %d", request, delta);
|
// Identify the worst estimates as "poor" ones.
|
||||||
|
if (request > REQUIRE_MIN && delta > 0) {
|
||||||
|
if ((delta > REQUIRE_MIN && request > 3 * delta) ||
|
||||||
|
(delta <= REQUIRE_MIN && request > 10 * delta)) {
|
||||||
|
tty->print_cr("Poor node estimate: %d >> %d", request, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
_phase->require_nodes_final_check(_nodes_at_begin);
|
|
||||||
} else {
|
|
||||||
_phase->require_nodes_final();
|
|
||||||
}
|
}
|
||||||
|
#endif // PRODUCT
|
||||||
|
_phase->require_nodes_final(_nodes_at_begin, _check_at_final);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1469,17 +1490,6 @@ private:
|
|||||||
uint _nodes_at_begin;
|
uint _nodes_at_begin;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The Estimated Loop Clone Size: CloneFactor * (BodySize + BC) + CC, where BC
|
|
||||||
// and CC are totally ad-hoc/magic "body" and "clone" constants, respectively,
|
|
||||||
// used to ensure that node usage estimates made are on the safe side, for the
|
|
||||||
// most part.
|
|
||||||
static inline uint est_loop_clone_sz(uint fact, uint size) {
|
|
||||||
uint const bc = 31;
|
|
||||||
uint const cc = 41;
|
|
||||||
uint estimate = fact * (size + bc) + cc;
|
|
||||||
return (estimate - cc) / fact == size + bc ? estimate : UINT_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// This kit may be used for making of a reserved copy of a loop before this loop
|
// This kit may be used for making of a reserved copy of a loop before this loop
|
||||||
// goes under non-reversible changes.
|
// goes under non-reversible changes.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -3029,16 +3029,16 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
|||||||
|
|
||||||
assert(!loop->_head->is_CountedLoop(), "Non-counted loop only");
|
assert(!loop->_head->is_CountedLoop(), "Non-counted loop only");
|
||||||
if (!loop->_head->is_Loop()) {
|
if (!loop->_head->is_Loop()) {
|
||||||
return false; }
|
return false;
|
||||||
|
}
|
||||||
LoopNode *head = loop->_head->as_Loop();
|
LoopNode *head = loop->_head->as_Loop();
|
||||||
|
|
||||||
if (head->is_partial_peel_loop() || head->partial_peel_has_failed()) {
|
if (head->is_partial_peel_loop() || head->partial_peel_has_failed()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for complex exit control
|
// Check for complex exit control
|
||||||
for(uint ii = 0; ii < loop->_body.size(); ii++ ) {
|
for (uint ii = 0; ii < loop->_body.size(); ii++) {
|
||||||
Node *n = loop->_body.at(ii);
|
Node *n = loop->_body.at(ii);
|
||||||
int opc = n->Opcode();
|
int opc = n->Opcode();
|
||||||
if (n->is_Call() ||
|
if (n->is_Call() ||
|
||||||
@ -3065,12 +3065,12 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
|||||||
IfNode *peel_if_cmpu = NULL;
|
IfNode *peel_if_cmpu = NULL;
|
||||||
|
|
||||||
Node *iff = loop->tail();
|
Node *iff = loop->tail();
|
||||||
while( iff != head ) {
|
while (iff != head) {
|
||||||
if( iff->is_If() ) {
|
if (iff->is_If()) {
|
||||||
Node *ctrl = get_ctrl(iff->in(1));
|
Node *ctrl = get_ctrl(iff->in(1));
|
||||||
if (ctrl->is_top()) return false; // Dead test on live IF.
|
if (ctrl->is_top()) return false; // Dead test on live IF.
|
||||||
// If loop-varying exit-test, check for induction variable
|
// If loop-varying exit-test, check for induction variable
|
||||||
if( loop->is_member(get_loop(ctrl)) &&
|
if (loop->is_member(get_loop(ctrl)) &&
|
||||||
loop->is_loop_exit(iff) &&
|
loop->is_loop_exit(iff) &&
|
||||||
is_possible_iv_test(iff)) {
|
is_possible_iv_test(iff)) {
|
||||||
Node* cmp = iff->in(1)->in(1);
|
Node* cmp = iff->in(1)->in(1);
|
||||||
@ -3084,6 +3084,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
|||||||
}
|
}
|
||||||
iff = idom(iff);
|
iff = idom(iff);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefer signed compare over unsigned compare.
|
// Prefer signed compare over unsigned compare.
|
||||||
IfNode* new_peel_if = NULL;
|
IfNode* new_peel_if = NULL;
|
||||||
if (peel_if == NULL) {
|
if (peel_if == NULL) {
|
||||||
@ -3131,7 +3132,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
|||||||
Node_List worklist(area);
|
Node_List worklist(area);
|
||||||
Node_List sink_list(area);
|
Node_List sink_list(area);
|
||||||
|
|
||||||
if (!may_require_nodes(est_loop_clone_sz(2, loop->_body.size()))) {
|
if (!may_require_nodes(loop->est_loop_clone_sz(2))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8223502
|
||||||
|
* @summary Node estimate for loop unswitching is not correct:
|
||||||
|
* assert(delta <= 2 * required) failed: Bad node estimate
|
||||||
|
*
|
||||||
|
* @requires !vm.graal.enabled
|
||||||
|
*
|
||||||
|
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation
|
||||||
|
* -XX:-UseOnStackReplacement -XX:CompileOnly=LoopUnswitchingBadNodeBudget::test
|
||||||
|
* -XX:CompileCommand=dontinline,LoopUnswitchingBadNodeBudget::helper
|
||||||
|
* -XX:+UnlockExperimentalVMOptions -XX:-UseSwitchProfiling LoopUnswitchingBadNodeBudget
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class LoopUnswitchingBadNodeBudget {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
for (int i = 0; i < 20_000; i++) {
|
||||||
|
for (int j = 0; j < 100; j++) {
|
||||||
|
test(j, true, 0, 0, 0);
|
||||||
|
test(j, false, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int test(int j, boolean flag, int k, int l, int m) {
|
||||||
|
int res = 0;
|
||||||
|
for (int i = 0; i < 24; i++) {
|
||||||
|
if (flag) {
|
||||||
|
k = k / 2;
|
||||||
|
l = l * 2;
|
||||||
|
m = m + 2;
|
||||||
|
}
|
||||||
|
switch (j) {
|
||||||
|
case 0: break;
|
||||||
|
case 1: return helper(j, k, l, m);
|
||||||
|
case 2: return helper(j, k, l, m);
|
||||||
|
case 3: return helper(j, k, l, m);
|
||||||
|
case 4: return helper(j, k, l, m);
|
||||||
|
case 5: return helper(j, k, l, m);
|
||||||
|
case 6: return helper(j, k, l, m);
|
||||||
|
case 7: return helper(j, k, l, m);
|
||||||
|
case 8: return helper(j, k, l, m);
|
||||||
|
case 9: return helper(j, k, l, m);
|
||||||
|
case 10: return helper(j, k, l, m);
|
||||||
|
case 11: return helper(j, k, l, m);
|
||||||
|
case 12: return helper(j, k, l, m);
|
||||||
|
case 13: return helper(j, k, l, m);
|
||||||
|
case 14: return helper(j, k, l, m);
|
||||||
|
case 15: return helper(j, k, l, m);
|
||||||
|
case 16: return helper(j, k, l, m);
|
||||||
|
case 17: return helper(j, k, l, m);
|
||||||
|
case 18: return helper(j, k, l, m);
|
||||||
|
case 19: return helper(j, k, l, m);
|
||||||
|
case 20: return helper(j, k, l, m);
|
||||||
|
case 21: return helper(j, k, l, m);
|
||||||
|
case 22: return helper(j, k, l, m);
|
||||||
|
case 23: return helper(j, k, l, m);
|
||||||
|
case 24: return helper(j, k, l, m);
|
||||||
|
case 25: return helper(j, k, l, m);
|
||||||
|
case 26: return helper(j, k, l, m);
|
||||||
|
case 27: return helper(j, k, l, m);
|
||||||
|
case 28: return helper(j, k, l, m);
|
||||||
|
case 29: return helper(j, k, l, m);
|
||||||
|
case 30: return helper(j, k, l, m);
|
||||||
|
case 31: return helper(j, k, l, m);
|
||||||
|
case 32: return helper(j, k, l, m);
|
||||||
|
case 33: return helper(j, k, l, m);
|
||||||
|
case 34: return helper(j, k, l, m);
|
||||||
|
case 35: return helper(j, k, l, m);
|
||||||
|
case 36: return helper(j, k, l, m);
|
||||||
|
case 37: return helper(j, k, l, m);
|
||||||
|
case 38: return helper(j, k, l, m);
|
||||||
|
case 39: return helper(j, k, l, m);
|
||||||
|
case 40: return helper(j, k, l, m);
|
||||||
|
case 41: return helper(j, k, l, m);
|
||||||
|
case 42: return helper(j, k, l, m);
|
||||||
|
case 43: return helper(j, k, l, m);
|
||||||
|
case 44: return helper(j, k, l, m);
|
||||||
|
case 45: return helper(j, k, l, m);
|
||||||
|
case 46: return helper(j, k, l, m);
|
||||||
|
case 47: return helper(j, k, l, m);
|
||||||
|
case 48: return helper(j, k, l, m);
|
||||||
|
case 49: return helper(j, k, l, m);
|
||||||
|
case 50: return helper(j, k, l, m);
|
||||||
|
case 51: return helper(j, k, l, m);
|
||||||
|
case 52: return helper(j, k, l, m);
|
||||||
|
case 53: return helper(j, k, l, m);
|
||||||
|
case 54: return helper(j, k, l, m);
|
||||||
|
case 55: return helper(j, k, l, m);
|
||||||
|
case 56: return helper(j, k, l, m);
|
||||||
|
case 57: return helper(j, k, l, m);
|
||||||
|
case 58: return helper(j, k, l, m);
|
||||||
|
case 59: return helper(j, k, l, m);
|
||||||
|
case 60: return helper(j, k, l, m);
|
||||||
|
case 61: return helper(j, k, l, m);
|
||||||
|
case 62: return helper(j, k, l, m);
|
||||||
|
case 63: return helper(j, k, l, m);
|
||||||
|
case 64: return helper(j, k, l, m);
|
||||||
|
case 65: return helper(j, k, l, m);
|
||||||
|
case 66: return helper(j, k, l, m);
|
||||||
|
case 67: return helper(j, k, l, m);
|
||||||
|
case 68: return helper(j, k, l, m);
|
||||||
|
case 69: return helper(j, k, l, m);
|
||||||
|
case 70: return helper(j, k, l, m);
|
||||||
|
case 71: return helper(j, k, l, m);
|
||||||
|
case 72: return helper(j, k, l, m);
|
||||||
|
case 73: return helper(j, k, l, m);
|
||||||
|
case 74: return helper(j, k, l, m);
|
||||||
|
case 75: return helper(j, k, l, m);
|
||||||
|
case 76: return helper(j, k, l, m);
|
||||||
|
case 77: return helper(j, k, l, m);
|
||||||
|
case 78: return helper(j, k, l, m);
|
||||||
|
case 79: return helper(j, k, l, m);
|
||||||
|
case 80: return helper(j, k, l, m);
|
||||||
|
case 81: return helper(j, k, l, m);
|
||||||
|
case 82: return helper(j, k, l, m);
|
||||||
|
case 83: return helper(j, k, l, m);
|
||||||
|
case 84: return helper(j, k, l, m);
|
||||||
|
case 85: return helper(j, k, l, m);
|
||||||
|
case 86: return helper(j, k, l, m);
|
||||||
|
case 87: return helper(j, k, l, m);
|
||||||
|
case 88: return helper(j, k, l, m);
|
||||||
|
case 89: return helper(j, k, l, m);
|
||||||
|
case 90: return helper(j, k, l, m);
|
||||||
|
case 91: return helper(j, k, l, m);
|
||||||
|
case 92: return helper(j, k, l, m);
|
||||||
|
case 93: return helper(j, k, l, m);
|
||||||
|
case 94: return helper(j, k, l, m);
|
||||||
|
case 95: return helper(j, k, l, m);
|
||||||
|
case 96: return helper(j, k, l, m);
|
||||||
|
case 97: return helper(j, k, l, m);
|
||||||
|
case 98: return helper(j, k, l, m);
|
||||||
|
case 99: return helper(j, k, l, m);
|
||||||
|
}
|
||||||
|
res += helper(j, k, l, m);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int helper(int j, int k, int l, int m) {
|
||||||
|
return j + k;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user