Skip to content

Commit dfd3da3

Browse files
committed
8307683: Loop Predication should not hoist range checks with trap on success projection by negating their condition
Reviewed-by: thartmann, roland
1 parent 96ed139 commit dfd3da3

File tree

5 files changed

+252
-37
lines changed

5 files changed

+252
-37
lines changed

src/hotspot/share/opto/loopPredicate.cpp

+61-25
Original file line numberDiff line numberDiff line change
@@ -831,16 +831,53 @@ class Invariance : public StackObj {
831831
// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format
832832
// Note: this function is particularly designed for loop predication. We require load_range
833833
// and offset to be loop invariant computed on the fly by "invar"
834-
bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, BasicType bt, Node *iv, Node *&range,
834+
bool IdealLoopTree::is_range_check_if(IfProjNode* if_success_proj, PhaseIdealLoop *phase, BasicType bt, Node *iv, Node *&range,
835835
Node *&offset, jlong &scale) const {
836+
IfNode* iff = if_success_proj->in(0)->as_If();
836837
if (!is_loop_exit(iff)) {
837838
return false;
838839
}
839840
if (!iff->in(1)->is_Bool()) {
840841
return false;
841842
}
842843
const BoolNode *bol = iff->in(1)->as_Bool();
843-
if (bol->_test._test != BoolTest::lt) {
844+
if (bol->_test._test != BoolTest::lt || if_success_proj->is_IfFalse()) {
845+
// We don't have the required range check pattern:
846+
// if (scale*iv + offset <u limit) {
847+
//
848+
// } else {
849+
// trap();
850+
// }
851+
//
852+
// Having the trap on the true projection:
853+
// if (scale*iv + offset <u limit) {
854+
// trap();
855+
// }
856+
//
857+
// is not correct. We would need to flip the test to get the expected "trap on false path" pattern:
858+
// if (scale*iv + offset >=u limit) {
859+
//
860+
// } else {
861+
// trap();
862+
// }
863+
//
864+
// If we create a Hoisted Range Check Predicate for this wrong pattern, it could succeed at runtime (i.e. true
865+
// for the value of "scale*iv + offset" in the first loop iteration and true for the value of "scale*iv + offset"
866+
// in the last loop iteration) while the check to be hoisted could fail in other loop iterations.
867+
//
868+
// Example:
869+
// Loop: "for (int i = -1; i < 1000; i++)"
870+
// init = "scale*iv + offset" in the first loop iteration = 1*-1 + 0 = -1
871+
// last = "scale*iv + offset" in the last loop iteration = 1*999 + 0 = 999
872+
// limit = 100
873+
//
874+
// Hoisted Range Check Predicate is always true:
875+
// init >=u limit && last >=u limit <=>
876+
// -1 >=u 100 && 999 >= u 100
877+
//
878+
// But for 0 <= x < 100: x >=u 100 is false.
879+
// We would wrongly skip the branch with the trap() and possibly miss to execute some other statements inside that
880+
// trap() branch.
844881
return false;
845882
}
846883
if (!bol->in(1)->is_Cmp()) {
@@ -871,14 +908,14 @@ bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, BasicT
871908
return true;
872909
}
873910

874-
bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar DEBUG_ONLY(COMMA ProjNode *predicate_proj)) const {
911+
bool IdealLoopTree::is_range_check_if(IfProjNode* if_success_proj, PhaseIdealLoop *phase, Invariance& invar DEBUG_ONLY(COMMA ProjNode *predicate_proj)) const {
875912
Node* range = nullptr;
876913
Node* offset = nullptr;
877914
jlong scale = 0;
878915
Node* iv = _head->as_BaseCountedLoop()->phi();
879916
Compile* C = Compile::current();
880917
const uint old_unique_idx = C->unique();
881-
if (!is_range_check_if(iff, phase, T_INT, iv, range, offset, scale)) {
918+
if (!is_range_check_if(if_success_proj, phase, T_INT, iv, range, offset, scale)) {
882919
return false;
883920
}
884921
if (!invar.is_invariant(range)) {
@@ -931,10 +968,8 @@ bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invari
931968
// max(scale*i + offset) = scale*(limit-stride) + offset
932969
// (2) stride*scale < 0
933970
// max(scale*i + offset) = scale*init + offset
934-
BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl,
935-
int scale, Node* offset,
936-
Node* init, Node* limit, jint stride,
937-
Node* range, bool upper, bool &overflow, bool negate) {
971+
BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree* loop, Node* ctrl, int scale, Node* offset, Node* init,
972+
Node* limit, jint stride, Node* range, bool upper, bool& overflow) {
938973
jint con_limit = (limit != nullptr && limit->is_Con()) ? limit->get_int() : 0;
939974
jint con_init = init->is_Con() ? init->get_int() : 0;
940975
jint con_offset = offset->is_Con() ? offset->get_int() : 0;
@@ -1060,7 +1095,7 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl,
10601095
cmp = new CmpUNode(max_idx_expr, range);
10611096
}
10621097
register_new_node(cmp, ctrl);
1063-
BoolNode* bol = new BoolNode(cmp, negate ? BoolTest::ge : BoolTest::lt);
1098+
BoolNode* bol = new BoolNode(cmp, BoolTest::lt);
10641099
register_new_node(bol, ctrl);
10651100

10661101
if (TraceLoopPredicate) {
@@ -1323,12 +1358,12 @@ void PhaseIdealLoop::loop_predication_follow_branches(Node *n, IdealLoopTree *lo
13231358
} while (stack.size() > 0);
13241359
}
13251360

1326-
bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_proj,
1361+
bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_success_proj,
13271362
ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl,
13281363
ConNode* zero, Invariance& invar, Deoptimization::DeoptReason reason) {
13291364
// Following are changed to nonnull when a predicate can be hoisted
13301365
IfProjNode* new_predicate_proj = nullptr;
1331-
IfNode* iff = if_proj->in(0)->as_If();
1366+
IfNode* iff = if_success_proj->in(0)->as_If();
13321367
Node* test = iff->in(1);
13331368
if (!test->is_Bool()) { //Conv2B, ...
13341369
return false;
@@ -1344,7 +1379,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
13441379

13451380
// Negate test if necessary (Parse Predicates always have IfTrue as success projection and IfFalse as uncommon trap)
13461381
bool negated = false;
1347-
if (if_proj->is_IfFalse()) {
1382+
if (if_success_proj->is_IfFalse()) {
13481383
new_predicate_bol = new BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate());
13491384
register_new_node(new_predicate_bol, ctrl);
13501385
negated = true;
@@ -1361,8 +1396,9 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
13611396
loop->dump_head();
13621397
}
13631398
#endif
1364-
} else if (cl != nullptr && loop->is_range_check_if(iff, this, invar DEBUG_ONLY(COMMA parse_predicate_proj))) {
1399+
} else if (cl != nullptr && loop->is_range_check_if(if_success_proj, this, invar DEBUG_ONLY(COMMA parse_predicate_proj))) {
13651400
// Range check for counted loops
1401+
assert(if_success_proj->is_IfTrue(), "trap must be on false projection for a range check");
13661402
const Node* cmp = bol->in(1)->as_Cmp();
13671403
Node* idx = cmp->in(1);
13681404
assert(!invar.is_invariant(idx), "index is variant");
@@ -1397,33 +1433,31 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
13971433
}
13981434
// If predicate expressions may overflow in the integer range, longs are used.
13991435
bool overflow = false;
1400-
// Negate test if necessary (Parse Predicates always have IfTrue as success projection and IfFalse as uncommon trap)
1401-
const bool negate = (if_proj->is_IfFalse());
1402-
14031436
// Test the lower bound
1404-
BoolNode* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false, overflow, negate);
1437+
BoolNode* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false, overflow);
14051438

14061439
const int if_opcode = iff->Opcode();
14071440
IfProjNode* lower_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : if_opcode);
14081441
IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If();
14091442
_igvn.hash_delete(lower_bound_iff);
14101443
lower_bound_iff->set_req(1, lower_bound_bol);
1411-
if (TraceLoopPredicate) tty->print_cr("lower bound check if: %s %d ", negate ? " negated" : "", lower_bound_iff->_idx);
1444+
if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx);
14121445

14131446
// Test the upper bound
1414-
BoolNode* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true, overflow, negate);
1447+
BoolNode* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true,
1448+
overflow);
14151449

14161450
IfProjNode* upper_bound_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : if_opcode);
14171451
assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate");
14181452
IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If();
14191453
_igvn.hash_delete(upper_bound_iff);
14201454
upper_bound_iff->set_req(1, upper_bound_bol);
1421-
if (TraceLoopPredicate) tty->print_cr("upper bound check if: %s %d ", negate ? " negated" : "", lower_bound_iff->_idx);
1455+
if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx);
14221456

14231457
// Fall through into rest of the cleanup code which will move any dependent nodes to the skeleton predicates of the
14241458
// upper bound test. We always need to create skeleton predicates in order to properly remove dead loops when later
14251459
// splitting the predicated loop into (unreachable) sub-loops (i.e. done by unrolling, peeling, pre/main/post etc.).
1426-
new_predicate_proj = add_template_assertion_predicate(iff, loop, if_proj, parse_predicate_proj, upper_bound_proj, scale,
1460+
new_predicate_proj = add_template_assertion_predicate(iff, loop, if_success_proj, parse_predicate_proj, upper_bound_proj, scale,
14271461
offset, init, limit, stride, rng, overflow, reason);
14281462

14291463
#ifndef PRODUCT
@@ -1439,10 +1473,10 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
14391473
}
14401474
assert(new_predicate_proj != nullptr, "sanity");
14411475
// Success - attach condition (new_predicate_bol) to predicate if
1442-
invar.map_ctrl(if_proj, new_predicate_proj); // so that invariance test can be appropriate
1476+
invar.map_ctrl(if_success_proj, new_predicate_proj); // so that invariance test can be appropriate
14431477

14441478
// Eliminate the old If in the loop body
1445-
dominated_by(new_predicate_proj, iff, if_proj->_con != new_predicate_proj->_con );
1479+
dominated_by(new_predicate_proj, iff, if_success_proj->_con != new_predicate_proj->_con);
14461480

14471481
C->set_major_progress();
14481482
return true;
@@ -1459,7 +1493,8 @@ IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL
14591493
Node* opaque_init = new OpaqueLoopInitNode(C, init);
14601494
register_new_node(opaque_init, upper_bound_proj);
14611495
bool negate = (if_proj->_con != predicate_proj->_con);
1462-
BoolNode* bol = rc_predicate(loop, upper_bound_proj, scale, offset, opaque_init, limit, stride, rng, (stride > 0) != (scale > 0), overflow, negate);
1496+
BoolNode* bol = rc_predicate(loop, upper_bound_proj, scale, offset, opaque_init, limit, stride, rng,
1497+
(stride > 0) != (scale > 0), overflow);
14631498
Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over
14641499
C->add_template_assertion_predicate_opaq(opaque_bol);
14651500
register_new_node(opaque_bol, upper_bound_proj);
@@ -1481,7 +1516,8 @@ IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL
14811516
max_value = new CastIINode(max_value, loop->_head->as_CountedLoop()->phi()->bottom_type());
14821517
register_new_node(max_value, predicate_proj);
14831518

1484-
bol = rc_predicate(loop, new_proj, scale, offset, max_value, limit, stride, rng, (stride > 0) != (scale > 0), overflow, negate);
1519+
bol = rc_predicate(loop, new_proj, scale, offset, max_value, limit, stride, rng, (stride > 0) != (scale > 0),
1520+
overflow);
14851521
opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1));
14861522
C->add_template_assertion_predicate_opaq(opaque_bol);
14871523
register_new_node(opaque_bol, new_proj);

src/hotspot/share/opto/loopTransform.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2858,7 +2858,7 @@ Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate(IdealLoopT
28582858
Node* value) {
28592859
bool overflow = false;
28602860
BoolNode* bol = rc_predicate(loop, ctrl, scale_con, offset, value, nullptr, stride_con,
2861-
limit, (stride_con > 0) != (scale_con > 0), overflow, false);
2861+
limit, (stride_con > 0) != (scale_con > 0), overflow);
28622862
Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1));
28632863
register_new_node(opaque_bol, ctrl);
28642864
IfNode* new_iff = nullptr;

src/hotspot/share/opto/loopnode.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1089,13 +1089,13 @@ int PhaseIdealLoop::extract_long_range_checks(const IdealLoopTree* loop, jlong s
10891089
for (uint i = 0; i < loop->_body.size(); i++) {
10901090
Node* c = loop->_body.at(i);
10911091
if (c->is_IfProj() && c->in(0)->is_RangeCheck()) {
1092-
CallStaticJavaNode* call = c->as_IfProj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
1092+
IfProjNode* if_proj = c->as_IfProj();
1093+
CallStaticJavaNode* call = if_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
10931094
if (call != nullptr) {
10941095
Node* range = nullptr;
10951096
Node* offset = nullptr;
10961097
jlong scale = 0;
1097-
RangeCheckNode* rc = c->in(0)->as_RangeCheck();
1098-
if (loop->is_range_check_if(rc, this, T_LONG, phi, range, offset, scale) &&
1098+
if (loop->is_range_check_if(if_proj, this, T_LONG, phi, range, offset, scale) &&
10991099
loop->is_invariant(range) && loop->is_invariant(offset) &&
11001100
original_iters_limit / ABS(scale * stride_con) >= min_iters) {
11011101
reduced_iters_limit = MIN2(reduced_iters_limit, original_iters_limit/ABS(scale));

src/hotspot/share/opto/loopnode.hpp

+5-8
Original file line numberDiff line numberDiff line change
@@ -733,8 +733,8 @@ class IdealLoopTree : public ResourceObj {
733733
bool policy_range_check(PhaseIdealLoop* phase, bool provisional, BasicType bt) const;
734734

735735
// Return TRUE if "iff" is a range check.
736-
bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar DEBUG_ONLY(COMMA ProjNode *predicate_proj)) const;
737-
bool is_range_check_if(IfNode* iff, PhaseIdealLoop* phase, BasicType bt, Node* iv, Node*& range, Node*& offset,
736+
bool is_range_check_if(IfProjNode* if_success_proj, PhaseIdealLoop* phase, Invariance& invar DEBUG_ONLY(COMMA ProjNode* predicate_proj)) const;
737+
bool is_range_check_if(IfProjNode* if_success_proj, PhaseIdealLoop* phase, BasicType bt, Node* iv, Node*& range, Node*& offset,
738738
jlong& scale) const;
739739

740740
// Estimate the number of nodes required when cloning a loop (body).
@@ -1366,15 +1366,12 @@ class PhaseIdealLoop : public PhaseTransform {
13661366
void register_control(Node* n, IdealLoopTree *loop, Node* pred, bool update_body = true);
13671367

13681368
// Construct a range check for a predicate if
1369-
BoolNode* rc_predicate(IdealLoopTree *loop, Node* ctrl,
1370-
int scale, Node* offset,
1371-
Node* init, Node* limit, jint stride,
1372-
Node* range, bool upper, bool &overflow,
1373-
bool negate);
1369+
BoolNode* rc_predicate(IdealLoopTree* loop, Node* ctrl, int scale, Node* offset, Node* init, Node* limit,
1370+
jint stride, Node* range, bool upper, bool& overflow);
13741371

13751372
// Implementation of the loop predication to promote checks outside the loop
13761373
bool loop_predication_impl(IdealLoopTree *loop);
1377-
bool loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_proj,
1374+
bool loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_success_proj,
13781375
ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl, ConNode* zero,
13791376
Invariance& invar, Deoptimization::DeoptReason reason);
13801377
bool loop_predication_should_follow_branches(IdealLoopTree* loop, IfProjNode* predicate_proj, float& loop_trip_cnt);

0 commit comments

Comments
 (0)