8072422: Cleanup: Remove some unused flags/code in loop optimizations
Remove unused flags, change test using them. Reviewed-by: kvn, twisti
This commit is contained in:
parent
fa667c5409
commit
69d14c811b
@ -229,21 +229,12 @@
|
||||
develop(bool, TraceLoopOpts, false, \
|
||||
"Trace executed loop optimizations") \
|
||||
\
|
||||
diagnostic(bool, LoopLimitCheck, true, \
|
||||
"Generate a loop limits check for overflow") \
|
||||
\
|
||||
develop(bool, TraceLoopLimitCheck, false, \
|
||||
"Trace generation of loop limits checks") \
|
||||
\
|
||||
diagnostic(bool, RangeLimitCheck, true, \
|
||||
"Additional overflow checks during range check elimination") \
|
||||
\
|
||||
develop(bool, TraceRangeLimitCheck, false, \
|
||||
"Trace additional overflow checks in RCE") \
|
||||
\
|
||||
diagnostic(bool, UnrollLimitCheck, true, \
|
||||
"Additional overflow checks during loop unroll") \
|
||||
\
|
||||
/* OptimizeFill not yet supported on PowerPC. */ \
|
||||
product(bool, OptimizeFill, true PPC64_ONLY(&& false), \
|
||||
"convert fill/copy loops into intrinsic") \
|
||||
|
@ -3773,9 +3773,7 @@ void GraphKit::add_predicate(int nargs) {
|
||||
add_predicate_impl(Deoptimization::Reason_predicate, nargs);
|
||||
}
|
||||
// loop's limit check predicate should be near the loop.
|
||||
if (LoopLimitCheck) {
|
||||
add_predicate_impl(Deoptimization::Reason_loop_limit_check, nargs);
|
||||
}
|
||||
add_predicate_impl(Deoptimization::Reason_loop_limit_check, nargs);
|
||||
}
|
||||
|
||||
//----------------------------- store barriers ----------------------------
|
||||
|
@ -313,11 +313,9 @@ Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry,
|
||||
// Search original predicates
|
||||
Node* entry = old_entry;
|
||||
ProjNode* limit_check_proj = NULL;
|
||||
if (LoopLimitCheck) {
|
||||
limit_check_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (limit_check_proj != NULL) {
|
||||
entry = entry->in(0)->in(0);
|
||||
}
|
||||
limit_check_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (limit_check_proj != NULL) {
|
||||
entry = entry->in(0)->in(0);
|
||||
}
|
||||
if (UseLoopPredicate) {
|
||||
ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
@ -353,11 +351,9 @@ Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry,
|
||||
// Skip related predicates.
|
||||
Node* PhaseIdealLoop::skip_loop_predicates(Node* entry) {
|
||||
Node* predicate = NULL;
|
||||
if (LoopLimitCheck) {
|
||||
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (predicate != NULL) {
|
||||
entry = entry->in(0)->in(0);
|
||||
}
|
||||
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (predicate != NULL) {
|
||||
entry = entry->in(0)->in(0);
|
||||
}
|
||||
if (UseLoopPredicate) {
|
||||
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
@ -393,11 +389,9 @@ ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimi
|
||||
// Find a predicate
|
||||
Node* PhaseIdealLoop::find_predicate(Node* entry) {
|
||||
Node* predicate = NULL;
|
||||
if (LoopLimitCheck) {
|
||||
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (predicate != NULL) { // right pattern that can be used by loop predication
|
||||
return entry;
|
||||
}
|
||||
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (predicate != NULL) { // right pattern that can be used by loop predication
|
||||
return entry;
|
||||
}
|
||||
if (UseLoopPredicate) {
|
||||
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
@ -646,19 +640,13 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl,
|
||||
Node* max_idx_expr = init;
|
||||
int stride_con = stride->get_int();
|
||||
if ((stride_con > 0) == (scale > 0) == upper) {
|
||||
if (LoopLimitCheck) {
|
||||
// With LoopLimitCheck limit is not exact.
|
||||
// Calculate exact limit here.
|
||||
// Note, counted loop's test is '<' or '>'.
|
||||
limit = exact_limit(loop);
|
||||
max_idx_expr = new SubINode(limit, stride);
|
||||
register_new_node(max_idx_expr, ctrl);
|
||||
if (TraceLoopPredicate) predString->print("(limit - stride) ");
|
||||
} else {
|
||||
max_idx_expr = new SubINode(limit, stride);
|
||||
register_new_node(max_idx_expr, ctrl);
|
||||
if (TraceLoopPredicate) predString->print("(limit - stride) ");
|
||||
}
|
||||
// Limit is not exact.
|
||||
// Calculate exact limit here.
|
||||
// Note, counted loop's test is '<' or '>'.
|
||||
limit = exact_limit(loop);
|
||||
max_idx_expr = new SubINode(limit, stride);
|
||||
register_new_node(max_idx_expr, ctrl);
|
||||
if (TraceLoopPredicate) predString->print("(limit - stride) ");
|
||||
} else {
|
||||
if (TraceLoopPredicate) predString->print("init ");
|
||||
}
|
||||
@ -721,12 +709,9 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
|
||||
Node* entry = head->in(LoopNode::EntryControl);
|
||||
ProjNode *predicate_proj = NULL;
|
||||
// Loop limit check predicate should be near the loop.
|
||||
if (LoopLimitCheck) {
|
||||
predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (predicate_proj != NULL)
|
||||
entry = predicate_proj->in(0)->in(0);
|
||||
}
|
||||
|
||||
predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (predicate_proj != NULL)
|
||||
entry = predicate_proj->in(0)->in(0);
|
||||
predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
if (!predicate_proj) {
|
||||
#ifndef PRODUCT
|
||||
|
@ -1468,209 +1468,156 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
|
||||
C->set_major_progress();
|
||||
|
||||
Node* new_limit = NULL;
|
||||
if (UnrollLimitCheck) {
|
||||
int stride_con = stride->get_int();
|
||||
int stride_p = (stride_con > 0) ? stride_con : -stride_con;
|
||||
uint old_trip_count = loop_head->trip_count();
|
||||
// Verify that unroll policy result is still valid.
|
||||
assert(old_trip_count > 1 &&
|
||||
(!adjust_min_trip || stride_p <= (1<<3)*loop_head->unrolled_count()), "sanity");
|
||||
int stride_con = stride->get_int();
|
||||
int stride_p = (stride_con > 0) ? stride_con : -stride_con;
|
||||
uint old_trip_count = loop_head->trip_count();
|
||||
// Verify that unroll policy result is still valid.
|
||||
assert(old_trip_count > 1 &&
|
||||
(!adjust_min_trip || stride_p <= (1<<3)*loop_head->unrolled_count()), "sanity");
|
||||
|
||||
// Adjust loop limit to keep valid iterations number after unroll.
|
||||
// Use (limit - stride) instead of (((limit - init)/stride) & (-2))*stride
|
||||
// which may overflow.
|
||||
if (!adjust_min_trip) {
|
||||
assert(old_trip_count > 1 && (old_trip_count & 1) == 0,
|
||||
"odd trip count for maximally unroll");
|
||||
// Don't need to adjust limit for maximally unroll since trip count is even.
|
||||
} else if (loop_head->has_exact_trip_count() && init->is_Con()) {
|
||||
// Loop's limit is constant. Loop's init could be constant when pre-loop
|
||||
// become peeled iteration.
|
||||
jlong init_con = init->get_int();
|
||||
// We can keep old loop limit if iterations count stays the same:
|
||||
// old_trip_count == new_trip_count * 2
|
||||
// Note: since old_trip_count >= 2 then new_trip_count >= 1
|
||||
// so we also don't need to adjust zero trip test.
|
||||
jlong limit_con = limit->get_int();
|
||||
// (stride_con*2) not overflow since stride_con <= 8.
|
||||
int new_stride_con = stride_con * 2;
|
||||
int stride_m = new_stride_con - (stride_con > 0 ? 1 : -1);
|
||||
jlong trip_count = (limit_con - init_con + stride_m)/new_stride_con;
|
||||
// New trip count should satisfy next conditions.
|
||||
assert(trip_count > 0 && (julong)trip_count < (julong)max_juint/2, "sanity");
|
||||
uint new_trip_count = (uint)trip_count;
|
||||
adjust_min_trip = (old_trip_count != new_trip_count*2);
|
||||
}
|
||||
// Adjust loop limit to keep valid iterations number after unroll.
|
||||
// Use (limit - stride) instead of (((limit - init)/stride) & (-2))*stride
|
||||
// which may overflow.
|
||||
if (!adjust_min_trip) {
|
||||
assert(old_trip_count > 1 && (old_trip_count & 1) == 0,
|
||||
"odd trip count for maximally unroll");
|
||||
// Don't need to adjust limit for maximally unroll since trip count is even.
|
||||
} else if (loop_head->has_exact_trip_count() && init->is_Con()) {
|
||||
// Loop's limit is constant. Loop's init could be constant when pre-loop
|
||||
// become peeled iteration.
|
||||
jlong init_con = init->get_int();
|
||||
// We can keep old loop limit if iterations count stays the same:
|
||||
// old_trip_count == new_trip_count * 2
|
||||
// Note: since old_trip_count >= 2 then new_trip_count >= 1
|
||||
// so we also don't need to adjust zero trip test.
|
||||
jlong limit_con = limit->get_int();
|
||||
// (stride_con*2) not overflow since stride_con <= 8.
|
||||
int new_stride_con = stride_con * 2;
|
||||
int stride_m = new_stride_con - (stride_con > 0 ? 1 : -1);
|
||||
jlong trip_count = (limit_con - init_con + stride_m)/new_stride_con;
|
||||
// New trip count should satisfy next conditions.
|
||||
assert(trip_count > 0 && (julong)trip_count < (julong)max_juint/2, "sanity");
|
||||
uint new_trip_count = (uint)trip_count;
|
||||
adjust_min_trip = (old_trip_count != new_trip_count*2);
|
||||
}
|
||||
|
||||
if (adjust_min_trip) {
|
||||
// Step 2: Adjust the trip limit if it is called for.
|
||||
// The adjustment amount is -stride. Need to make sure if the
|
||||
// adjustment underflows or overflows, then the main loop is skipped.
|
||||
Node* cmp = loop_end->cmp_node();
|
||||
assert(cmp->in(2) == limit, "sanity");
|
||||
assert(opaq != NULL && opaq->in(1) == limit, "sanity");
|
||||
if (adjust_min_trip) {
|
||||
// Step 2: Adjust the trip limit if it is called for.
|
||||
// The adjustment amount is -stride. Need to make sure if the
|
||||
// adjustment underflows or overflows, then the main loop is skipped.
|
||||
Node* cmp = loop_end->cmp_node();
|
||||
assert(cmp->in(2) == limit, "sanity");
|
||||
assert(opaq != NULL && opaq->in(1) == limit, "sanity");
|
||||
|
||||
// Verify that policy_unroll result is still valid.
|
||||
const TypeInt* limit_type = _igvn.type(limit)->is_int();
|
||||
assert(stride_con > 0 && ((limit_type->_hi - stride_con) < limit_type->_hi) ||
|
||||
stride_con < 0 && ((limit_type->_lo - stride_con) > limit_type->_lo), "sanity");
|
||||
// Verify that policy_unroll result is still valid.
|
||||
const TypeInt* limit_type = _igvn.type(limit)->is_int();
|
||||
assert(stride_con > 0 && ((limit_type->_hi - stride_con) < limit_type->_hi) ||
|
||||
stride_con < 0 && ((limit_type->_lo - stride_con) > limit_type->_lo), "sanity");
|
||||
|
||||
if (limit->is_Con()) {
|
||||
// The check in policy_unroll and the assert above guarantee
|
||||
// no underflow if limit is constant.
|
||||
new_limit = _igvn.intcon(limit->get_int() - stride_con);
|
||||
set_ctrl(new_limit, C->root());
|
||||
if (limit->is_Con()) {
|
||||
// The check in policy_unroll and the assert above guarantee
|
||||
// no underflow if limit is constant.
|
||||
new_limit = _igvn.intcon(limit->get_int() - stride_con);
|
||||
set_ctrl(new_limit, C->root());
|
||||
} else {
|
||||
// Limit is not constant.
|
||||
if (loop_head->unrolled_count() == 1) { // only for first unroll
|
||||
// Separate limit by Opaque node in case it is an incremented
|
||||
// variable from previous loop to avoid using pre-incremented
|
||||
// value which could increase register pressure.
|
||||
// Otherwise reorg_offsets() optimization will create a separate
|
||||
// Opaque node for each use of trip-counter and as result
|
||||
// zero trip guard limit will be different from loop limit.
|
||||
assert(has_ctrl(opaq), "should have it");
|
||||
Node* opaq_ctrl = get_ctrl(opaq);
|
||||
limit = new Opaque2Node( C, limit );
|
||||
register_new_node( limit, opaq_ctrl );
|
||||
}
|
||||
if (stride_con > 0 && (java_subtract(limit_type->_lo, stride_con) < limit_type->_lo) ||
|
||||
stride_con < 0 && (java_subtract(limit_type->_hi, stride_con) > limit_type->_hi)) {
|
||||
// No underflow.
|
||||
new_limit = new SubINode(limit, stride);
|
||||
} else {
|
||||
// Limit is not constant.
|
||||
if (loop_head->unrolled_count() == 1) { // only for first unroll
|
||||
// Separate limit by Opaque node in case it is an incremented
|
||||
// variable from previous loop to avoid using pre-incremented
|
||||
// value which could increase register pressure.
|
||||
// Otherwise reorg_offsets() optimization will create a separate
|
||||
// Opaque node for each use of trip-counter and as result
|
||||
// zero trip guard limit will be different from loop limit.
|
||||
assert(has_ctrl(opaq), "should have it");
|
||||
Node* opaq_ctrl = get_ctrl(opaq);
|
||||
limit = new Opaque2Node( C, limit );
|
||||
register_new_node( limit, opaq_ctrl );
|
||||
}
|
||||
if (stride_con > 0 && (java_subtract(limit_type->_lo, stride_con) < limit_type->_lo) ||
|
||||
stride_con < 0 && (java_subtract(limit_type->_hi, stride_con) > limit_type->_hi)) {
|
||||
// No underflow.
|
||||
new_limit = new SubINode(limit, stride);
|
||||
// (limit - stride) may underflow.
|
||||
// Clamp the adjustment value with MININT or MAXINT:
|
||||
//
|
||||
// new_limit = limit-stride
|
||||
// if (stride > 0)
|
||||
// new_limit = (limit < new_limit) ? MININT : new_limit;
|
||||
// else
|
||||
// new_limit = (limit > new_limit) ? MAXINT : new_limit;
|
||||
//
|
||||
BoolTest::mask bt = loop_end->test_trip();
|
||||
assert(bt == BoolTest::lt || bt == BoolTest::gt, "canonical test is expected");
|
||||
Node* adj_max = _igvn.intcon((stride_con > 0) ? min_jint : max_jint);
|
||||
set_ctrl(adj_max, C->root());
|
||||
Node* old_limit = NULL;
|
||||
Node* adj_limit = NULL;
|
||||
Node* bol = limit->is_CMove() ? limit->in(CMoveNode::Condition) : NULL;
|
||||
if (loop_head->unrolled_count() > 1 &&
|
||||
limit->is_CMove() && limit->Opcode() == Op_CMoveI &&
|
||||
limit->in(CMoveNode::IfTrue) == adj_max &&
|
||||
bol->as_Bool()->_test._test == bt &&
|
||||
bol->in(1)->Opcode() == Op_CmpI &&
|
||||
bol->in(1)->in(2) == limit->in(CMoveNode::IfFalse)) {
|
||||
// Loop was unrolled before.
|
||||
// Optimize the limit to avoid nested CMove:
|
||||
// use original limit as old limit.
|
||||
old_limit = bol->in(1)->in(1);
|
||||
// Adjust previous adjusted limit.
|
||||
adj_limit = limit->in(CMoveNode::IfFalse);
|
||||
adj_limit = new SubINode(adj_limit, stride);
|
||||
} else {
|
||||
// (limit - stride) may underflow.
|
||||
// Clamp the adjustment value with MININT or MAXINT:
|
||||
//
|
||||
// new_limit = limit-stride
|
||||
// if (stride > 0)
|
||||
// new_limit = (limit < new_limit) ? MININT : new_limit;
|
||||
// else
|
||||
// new_limit = (limit > new_limit) ? MAXINT : new_limit;
|
||||
//
|
||||
BoolTest::mask bt = loop_end->test_trip();
|
||||
assert(bt == BoolTest::lt || bt == BoolTest::gt, "canonical test is expected");
|
||||
Node* adj_max = _igvn.intcon((stride_con > 0) ? min_jint : max_jint);
|
||||
set_ctrl(adj_max, C->root());
|
||||
Node* old_limit = NULL;
|
||||
Node* adj_limit = NULL;
|
||||
Node* bol = limit->is_CMove() ? limit->in(CMoveNode::Condition) : NULL;
|
||||
if (loop_head->unrolled_count() > 1 &&
|
||||
limit->is_CMove() && limit->Opcode() == Op_CMoveI &&
|
||||
limit->in(CMoveNode::IfTrue) == adj_max &&
|
||||
bol->as_Bool()->_test._test == bt &&
|
||||
bol->in(1)->Opcode() == Op_CmpI &&
|
||||
bol->in(1)->in(2) == limit->in(CMoveNode::IfFalse)) {
|
||||
// Loop was unrolled before.
|
||||
// Optimize the limit to avoid nested CMove:
|
||||
// use original limit as old limit.
|
||||
old_limit = bol->in(1)->in(1);
|
||||
// Adjust previous adjusted limit.
|
||||
adj_limit = limit->in(CMoveNode::IfFalse);
|
||||
adj_limit = new SubINode(adj_limit, stride);
|
||||
} else {
|
||||
old_limit = limit;
|
||||
adj_limit = new SubINode(limit, stride);
|
||||
}
|
||||
assert(old_limit != NULL && adj_limit != NULL, "");
|
||||
register_new_node( adj_limit, ctrl ); // adjust amount
|
||||
Node* adj_cmp = new CmpINode(old_limit, adj_limit);
|
||||
register_new_node( adj_cmp, ctrl );
|
||||
Node* adj_bool = new BoolNode(adj_cmp, bt);
|
||||
register_new_node( adj_bool, ctrl );
|
||||
new_limit = new CMoveINode(adj_bool, adj_limit, adj_max, TypeInt::INT);
|
||||
old_limit = limit;
|
||||
adj_limit = new SubINode(limit, stride);
|
||||
}
|
||||
register_new_node(new_limit, ctrl);
|
||||
assert(old_limit != NULL && adj_limit != NULL, "");
|
||||
register_new_node( adj_limit, ctrl ); // adjust amount
|
||||
Node* adj_cmp = new CmpINode(old_limit, adj_limit);
|
||||
register_new_node( adj_cmp, ctrl );
|
||||
Node* adj_bool = new BoolNode(adj_cmp, bt);
|
||||
register_new_node( adj_bool, ctrl );
|
||||
new_limit = new CMoveINode(adj_bool, adj_limit, adj_max, TypeInt::INT);
|
||||
}
|
||||
assert(new_limit != NULL, "");
|
||||
// Replace in loop test.
|
||||
assert(loop_end->in(1)->in(1) == cmp, "sanity");
|
||||
if (cmp->outcnt() == 1 && loop_end->in(1)->outcnt() == 1) {
|
||||
// Don't need to create new test since only one user.
|
||||
_igvn.hash_delete(cmp);
|
||||
cmp->set_req(2, new_limit);
|
||||
} else {
|
||||
// Create new test since it is shared.
|
||||
Node* ctrl2 = loop_end->in(0);
|
||||
Node* cmp2 = cmp->clone();
|
||||
cmp2->set_req(2, new_limit);
|
||||
register_new_node(cmp2, ctrl2);
|
||||
Node* bol2 = loop_end->in(1)->clone();
|
||||
bol2->set_req(1, cmp2);
|
||||
register_new_node(bol2, ctrl2);
|
||||
_igvn.replace_input_of(loop_end, 1, bol2);
|
||||
}
|
||||
// Step 3: Find the min-trip test guaranteed before a 'main' loop.
|
||||
// Make it a 1-trip test (means at least 2 trips).
|
||||
|
||||
// Guard test uses an 'opaque' node which is not shared. Hence I
|
||||
// can edit it's inputs directly. Hammer in the new limit for the
|
||||
// minimum-trip guard.
|
||||
assert(opaq->outcnt() == 1, "");
|
||||
_igvn.replace_input_of(opaq, 1, new_limit);
|
||||
register_new_node(new_limit, ctrl);
|
||||
}
|
||||
assert(new_limit != NULL, "");
|
||||
// Replace in loop test.
|
||||
assert(loop_end->in(1)->in(1) == cmp, "sanity");
|
||||
if (cmp->outcnt() == 1 && loop_end->in(1)->outcnt() == 1) {
|
||||
// Don't need to create new test since only one user.
|
||||
_igvn.hash_delete(cmp);
|
||||
cmp->set_req(2, new_limit);
|
||||
} else {
|
||||
// Create new test since it is shared.
|
||||
Node* ctrl2 = loop_end->in(0);
|
||||
Node* cmp2 = cmp->clone();
|
||||
cmp2->set_req(2, new_limit);
|
||||
register_new_node(cmp2, ctrl2);
|
||||
Node* bol2 = loop_end->in(1)->clone();
|
||||
bol2->set_req(1, cmp2);
|
||||
register_new_node(bol2, ctrl2);
|
||||
_igvn.replace_input_of(loop_end, 1, bol2);
|
||||
}
|
||||
|
||||
// Adjust max trip count. The trip count is intentionally rounded
|
||||
// down here (e.g. 15-> 7-> 3-> 1) because if we unwittingly over-unroll,
|
||||
// the main, unrolled, part of the loop will never execute as it is protected
|
||||
// by the min-trip test. See bug 4834191 for a case where we over-unrolled
|
||||
// and later determined that part of the unrolled loop was dead.
|
||||
loop_head->set_trip_count(old_trip_count / 2);
|
||||
|
||||
// Double the count of original iterations in the unrolled loop body.
|
||||
loop_head->double_unrolled_count();
|
||||
|
||||
} else { // LoopLimitCheck
|
||||
|
||||
// Adjust max trip count. The trip count is intentionally rounded
|
||||
// down here (e.g. 15-> 7-> 3-> 1) because if we unwittingly over-unroll,
|
||||
// the main, unrolled, part of the loop will never execute as it is protected
|
||||
// by the min-trip test. See bug 4834191 for a case where we over-unrolled
|
||||
// and later determined that part of the unrolled loop was dead.
|
||||
loop_head->set_trip_count(loop_head->trip_count() / 2);
|
||||
|
||||
// Double the count of original iterations in the unrolled loop body.
|
||||
loop_head->double_unrolled_count();
|
||||
|
||||
// -----------
|
||||
// Step 2: Cut back the trip counter for an unroll amount of 2.
|
||||
// Loop will normally trip (limit - init)/stride_con. Since it's a
|
||||
// CountedLoop this is exact (stride divides limit-init exactly).
|
||||
// We are going to double the loop body, so we want to knock off any
|
||||
// odd iteration: (trip_cnt & ~1). Then back compute a new limit.
|
||||
Node *span = new SubINode( limit, init );
|
||||
register_new_node( span, ctrl );
|
||||
Node *trip = new DivINode( 0, span, stride );
|
||||
register_new_node( trip, ctrl );
|
||||
Node *mtwo = _igvn.intcon(-2);
|
||||
set_ctrl(mtwo, C->root());
|
||||
Node *rond = new AndINode( trip, mtwo );
|
||||
register_new_node( rond, ctrl );
|
||||
Node *spn2 = new MulINode( rond, stride );
|
||||
register_new_node( spn2, ctrl );
|
||||
new_limit = new AddINode( spn2, init );
|
||||
register_new_node( new_limit, ctrl );
|
||||
|
||||
// Hammer in the new limit
|
||||
Node *ctrl2 = loop_end->in(0);
|
||||
Node *cmp2 = new CmpINode( loop_head->incr(), new_limit );
|
||||
register_new_node( cmp2, ctrl2 );
|
||||
Node *bol2 = new BoolNode( cmp2, loop_end->test_trip() );
|
||||
register_new_node( bol2, ctrl2 );
|
||||
_igvn.replace_input_of(loop_end, CountedLoopEndNode::TestValue, bol2);
|
||||
|
||||
// Step 3: Find the min-trip test guaranteed before a 'main' loop.
|
||||
// Make it a 1-trip test (means at least 2 trips).
|
||||
if( adjust_min_trip ) {
|
||||
assert( new_limit != NULL, "" );
|
||||
// Guard test uses an 'opaque' node which is not shared. Hence I
|
||||
// can edit it's inputs directly. Hammer in the new limit for the
|
||||
// minimum-trip guard.
|
||||
assert( opaq->outcnt() == 1, "" );
|
||||
_igvn.hash_delete(opaq);
|
||||
opaq->set_req(1, new_limit);
|
||||
}
|
||||
} // LoopLimitCheck
|
||||
|
||||
// Guard test uses an 'opaque' node which is not shared. Hence I
|
||||
// can edit it's inputs directly. Hammer in the new limit for the
|
||||
// minimum-trip guard.
|
||||
assert(opaq->outcnt() == 1, "");
|
||||
_igvn.replace_input_of(opaq, 1, new_limit);
|
||||
}
|
||||
|
||||
// Adjust max trip count. The trip count is intentionally rounded
|
||||
// down here (e.g. 15-> 7-> 3-> 1) because if we unwittingly over-unroll,
|
||||
// the main, unrolled, part of the loop will never execute as it is protected
|
||||
// by the min-trip test. See bug 4834191 for a case where we over-unrolled
|
||||
// and later determined that part of the unrolled loop was dead.
|
||||
loop_head->set_trip_count(old_trip_count / 2);
|
||||
|
||||
// Double the count of original iterations in the unrolled loop body.
|
||||
loop_head->double_unrolled_count();
|
||||
|
||||
// ---------
|
||||
// Step 4: Clone the loop body. Move it inside the loop. This loop body
|
||||
@ -1904,7 +1851,6 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset
|
||||
// )
|
||||
|
||||
if (low_limit->get_int() == -max_jint) {
|
||||
if (!RangeLimitCheck) return;
|
||||
// We need this guard when scale*pre_limit+offset >= limit
|
||||
// due to underflow. So we need execute pre-loop until
|
||||
// scale*I+offset >= min_int. But (min_int-offset) will
|
||||
@ -1956,7 +1902,6 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset
|
||||
*pre_limit = adjust_limit((-stride_con), scale, plus_one, upper_limit, *pre_limit, pre_ctrl);
|
||||
|
||||
if (low_limit->get_int() == -max_jint) {
|
||||
if (!RangeLimitCheck) return;
|
||||
// We need this guard when scale*main_limit+offset >= limit
|
||||
// due to underflow. So we need execute main-loop while
|
||||
// scale*I+offset+1 > min_int. But (min_int-offset-1) will
|
||||
@ -2258,7 +2203,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
add_constraint( stride_con, scale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit );
|
||||
if (!conditional_rc) {
|
||||
// (0-offset)/scale could be outside of loop iterations range.
|
||||
conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck;
|
||||
conditional_rc = !loop->dominates_backedge(iff);
|
||||
}
|
||||
} else {
|
||||
if (PrintOpto) {
|
||||
@ -2294,7 +2239,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
// ((MIN_INT+1)-offset)/scale could be outside of loop iterations range.
|
||||
// Note: negative offset is replaced with 0 but (MIN_INT+1)/scale could
|
||||
// still be outside of loop range.
|
||||
conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck;
|
||||
conditional_rc = !loop->dominates_backedge(iff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -2340,26 +2285,6 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
// Note:: we are making the main loop limit no longer precise;
|
||||
// need to round up based on stride.
|
||||
cl->set_nonexact_trip_count();
|
||||
if (!LoopLimitCheck && stride_con != 1 && stride_con != -1) { // Cutout for common case
|
||||
// "Standard" round-up logic: ([main_limit-init+(y-1)]/y)*y+init
|
||||
// Hopefully, compiler will optimize for powers of 2.
|
||||
Node *ctrl = get_ctrl(main_limit);
|
||||
Node *stride = cl->stride();
|
||||
Node *init = cl->init_trip()->uncast();
|
||||
Node *span = new SubINode(main_limit,init);
|
||||
register_new_node(span,ctrl);
|
||||
Node *rndup = _igvn.intcon(stride_con + ((stride_con>0)?-1:1));
|
||||
Node *add = new AddINode(span,rndup);
|
||||
register_new_node(add,ctrl);
|
||||
Node *div = new DivINode(0,add,stride);
|
||||
register_new_node(div,ctrl);
|
||||
Node *mul = new MulINode(div,stride);
|
||||
register_new_node(mul,ctrl);
|
||||
Node *newlim = new AddINode(mul,init);
|
||||
register_new_node(newlim,ctrl);
|
||||
main_limit = newlim;
|
||||
}
|
||||
|
||||
Node *main_cle = cl->loopexit();
|
||||
Node *main_bol = main_cle->in(1);
|
||||
// Hacking loop bounds; need private copies of exit test
|
||||
|
@ -138,7 +138,7 @@ void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) {
|
||||
Node* uniqc = proj_true->unique_ctrl_out();
|
||||
Node* entry = head->in(LoopNode::EntryControl);
|
||||
Node* predicate = find_predicate(entry);
|
||||
if (predicate != NULL && LoopLimitCheck && UseLoopPredicate) {
|
||||
if (predicate != NULL && UseLoopPredicate) {
|
||||
// We may have two predicates, find first.
|
||||
entry = find_predicate(entry->in(0)->in(0));
|
||||
if (entry != NULL) predicate = entry;
|
||||
|
@ -463,8 +463,6 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
|
||||
|
||||
Node *hook = new Node(6);
|
||||
|
||||
if (LoopLimitCheck) {
|
||||
|
||||
// ===================================================
|
||||
// Generate loop limit check to avoid integer overflow
|
||||
// in cases like next (cyclic loops):
|
||||
@ -593,103 +591,6 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
|
||||
}
|
||||
set_subtree_ctrl( limit );
|
||||
|
||||
} else { // LoopLimitCheck
|
||||
|
||||
// If compare points to incr, we are ok. Otherwise the compare
|
||||
// can directly point to the phi; in this case adjust the compare so that
|
||||
// it points to the incr by adjusting the limit.
|
||||
if (cmp->in(1) == phi || cmp->in(2) == phi)
|
||||
limit = gvn->transform(new AddINode(limit,stride));
|
||||
|
||||
// trip-count for +-tive stride should be: (limit - init_trip + stride - 1)/stride.
|
||||
// Final value for iterator should be: trip_count * stride + init_trip.
|
||||
Node *one_p = gvn->intcon( 1);
|
||||
Node *one_m = gvn->intcon(-1);
|
||||
|
||||
Node *trip_count = NULL;
|
||||
switch( bt ) {
|
||||
case BoolTest::eq:
|
||||
ShouldNotReachHere();
|
||||
case BoolTest::ne: // Ahh, the case we desire
|
||||
if (stride_con == 1)
|
||||
trip_count = gvn->transform(new SubINode(limit,init_trip));
|
||||
else if (stride_con == -1)
|
||||
trip_count = gvn->transform(new SubINode(init_trip,limit));
|
||||
else
|
||||
ShouldNotReachHere();
|
||||
set_subtree_ctrl(trip_count);
|
||||
//_loop.map(trip_count->_idx,loop(limit));
|
||||
break;
|
||||
case BoolTest::le: // Maybe convert to '<' case
|
||||
limit = gvn->transform(new AddINode(limit,one_p));
|
||||
set_subtree_ctrl( limit );
|
||||
hook->init_req(4, limit);
|
||||
|
||||
bt = BoolTest::lt;
|
||||
// Make the new limit be in the same loop nest as the old limit
|
||||
//_loop.map(limit->_idx,limit_loop);
|
||||
// Fall into next case
|
||||
case BoolTest::lt: { // Maybe convert to '!=' case
|
||||
if (stride_con < 0) // Count down loop rolls through MAXINT
|
||||
ShouldNotReachHere();
|
||||
Node *range = gvn->transform(new SubINode(limit,init_trip));
|
||||
set_subtree_ctrl( range );
|
||||
hook->init_req(0, range);
|
||||
|
||||
Node *bias = gvn->transform(new AddINode(range,stride));
|
||||
set_subtree_ctrl( bias );
|
||||
hook->init_req(1, bias);
|
||||
|
||||
Node *bias1 = gvn->transform(new AddINode(bias,one_m));
|
||||
set_subtree_ctrl( bias1 );
|
||||
hook->init_req(2, bias1);
|
||||
|
||||
trip_count = gvn->transform(new DivINode(0,bias1,stride));
|
||||
set_subtree_ctrl( trip_count );
|
||||
hook->init_req(3, trip_count);
|
||||
break;
|
||||
}
|
||||
|
||||
case BoolTest::ge: // Maybe convert to '>' case
|
||||
limit = gvn->transform(new AddINode(limit,one_m));
|
||||
set_subtree_ctrl( limit );
|
||||
hook->init_req(4 ,limit);
|
||||
|
||||
bt = BoolTest::gt;
|
||||
// Make the new limit be in the same loop nest as the old limit
|
||||
//_loop.map(limit->_idx,limit_loop);
|
||||
// Fall into next case
|
||||
case BoolTest::gt: { // Maybe convert to '!=' case
|
||||
if (stride_con > 0) // count up loop rolls through MININT
|
||||
ShouldNotReachHere();
|
||||
Node *range = gvn->transform(new SubINode(limit,init_trip));
|
||||
set_subtree_ctrl( range );
|
||||
hook->init_req(0, range);
|
||||
|
||||
Node *bias = gvn->transform(new AddINode(range,stride));
|
||||
set_subtree_ctrl( bias );
|
||||
hook->init_req(1, bias);
|
||||
|
||||
Node *bias1 = gvn->transform(new AddINode(bias,one_p));
|
||||
set_subtree_ctrl( bias1 );
|
||||
hook->init_req(2, bias1);
|
||||
|
||||
trip_count = gvn->transform(new DivINode(0,bias1,stride));
|
||||
set_subtree_ctrl( trip_count );
|
||||
hook->init_req(3, trip_count);
|
||||
break;
|
||||
}
|
||||
} // switch( bt )
|
||||
|
||||
Node *span = gvn->transform(new MulINode(trip_count,stride));
|
||||
set_subtree_ctrl( span );
|
||||
hook->init_req(5, span);
|
||||
|
||||
limit = gvn->transform(new AddINode(span,init_trip));
|
||||
set_subtree_ctrl( limit );
|
||||
|
||||
} // LoopLimitCheck
|
||||
|
||||
if (!UseCountedLoopSafepoints) {
|
||||
// Check for SafePoint on backedge and remove
|
||||
Node *sfpt = x->in(LoopNode::LoopBackControl);
|
||||
@ -829,7 +730,7 @@ Node* PhaseIdealLoop::exact_limit( IdealLoopTree *loop ) {
|
||||
CountedLoopNode *cl = loop->_head->as_CountedLoop();
|
||||
assert(cl->is_valid_counted_loop(), "");
|
||||
|
||||
if (!LoopLimitCheck || ABS(cl->stride_con()) == 1 ||
|
||||
if (ABS(cl->stride_con()) == 1 ||
|
||||
cl->limit()->Opcode() == Op_LoopLimit) {
|
||||
// Old code has exact limit (it could be incorrect in case of int overflow).
|
||||
// Loop limit is exact with stride == 1. And loop may already have exact limit.
|
||||
@ -1897,12 +1798,10 @@ void IdealLoopTree::dump_head( ) const {
|
||||
tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx);
|
||||
if (_irreducible) tty->print(" IRREDUCIBLE");
|
||||
Node* entry = _head->in(LoopNode::EntryControl);
|
||||
if (LoopLimitCheck) {
|
||||
Node* predicate = PhaseIdealLoop::find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (predicate != NULL ) {
|
||||
tty->print(" limit_check");
|
||||
entry = entry->in(0)->in(0);
|
||||
}
|
||||
Node* predicate = PhaseIdealLoop::find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
|
||||
if (predicate != NULL ) {
|
||||
tty->print(" limit_check");
|
||||
entry = entry->in(0)->in(0);
|
||||
}
|
||||
if (UseLoopPredicate) {
|
||||
entry = PhaseIdealLoop::find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
@ -2322,7 +2221,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
|
||||
// Some parser-inserted loop predicates could never be used by loop
|
||||
// predication or they were moved away from loop during some optimizations.
|
||||
// For example, peeling. Eliminate them before next loop optimizations.
|
||||
if (UseLoopPredicate || LoopLimitCheck) {
|
||||
if (UseLoopPredicate) {
|
||||
eliminate_useless_predicates();
|
||||
}
|
||||
|
||||
|
@ -661,8 +661,7 @@ void Parse::do_all_blocks() {
|
||||
// (Note that dead locals do not get phis built, ever.)
|
||||
ensure_phis_everywhere();
|
||||
|
||||
if (block->is_SEL_head() &&
|
||||
(UseLoopPredicate || LoopLimitCheck)) {
|
||||
if (block->is_SEL_head() && UseLoopPredicate) {
|
||||
// Add predicate to single entry (not irreducible) loop head.
|
||||
assert(!block->has_merged_backedge(), "only entry paths should be merged for now");
|
||||
// Need correct bci for predicate.
|
||||
|
@ -26,10 +26,19 @@
|
||||
* @test
|
||||
* @bug 8073184
|
||||
* @summary CastII that guards counted loops confuses range check elimination with LoopLimitCheck off
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-LoopLimitCheck -XX:CompileOnly=TestCastIINoLoopLimitCheck.m -Xcomp TestCastIINoLoopLimitCheck
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:CompileOnly=TestCastIINoLoopLimitCheck.m -Xcomp TestCastIINoLoopLimitCheck
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* The test was originally run with
|
||||
*
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-LoopLimitCheck
|
||||
*
|
||||
* to trigger a problem with code guarded with !LoopLimitCheck.
|
||||
* JDK-8072422 has removed that code but kept the test because the
|
||||
* test generates an interesting graph shape.
|
||||
*/
|
||||
public class TestCastIINoLoopLimitCheck {
|
||||
|
||||
static void m(int i, int index, char[] buf) {
|
||||
|
Loading…
Reference in New Issue
Block a user