RFR: 8307683: Loop Predication is wrongly applied to non-RangeCheckNodes without a LoadRangeNode
Tobias Hartmann
thartmann at openjdk.org
Fri May 26 08:19:57 UTC 2023
On Thu, 25 May 2023 16:48:35 GMT, Christian Hagedorn <chagedorn at openjdk.org> wrote:
> [JDK-4809552](https://bugs.openjdk.org/browse/JDK-4809552) allowed Loop Predication to be applied to `IfNodes` that have a positive value instead of a `LoadRangeNode`:
> https://github.com/openjdk/jdk/blob/48d21bd089a3f344ee5407926f8ed2af3734d2b0/src/hotspot/share/opto/loopPredicate.cpp#L854-L862
>
> This, however, is only correct if we have an actual `RangeCheckNode` for an array. The reason for that is that if we hoist a real range check and create a Hoisted Predicate for it, we only need to check the lower and upper bound of all array accesses (i.e. the array access of the first and the last loop iteration). All array accesses in between are implicitly covered and do not need to be checked again.
>
> But if we face an `IfNode` without a `LoadRangeNode`, we could be comparing anything. We do not have any guarantee that if the first and last loop iteration check succeed that the other loop iteration checks will also succeed. An example of this is shown in the test case `test()`. We wrongly create a Hoisted Range Check Predicate where the lower and upper bound are always true, but for some values of the loop induction variable, the hoisted check would actually fail. We then crash because an added Assertion Predicate exactly performs this failing check (crash with halt). Without any loop splitting (i.e. no Assertion Predicates), we have a wrong execution due to never executing the branch where we increment `iFld2` because we removed it together with the check.
>
> Thanks,
> Christian
Looks good to me. Scary, that we didn't find this earlier.
test/hotspot/jtreg/compiler/predicates/TestHoistedPredicateForNonRangeCheck.java line 82:
> 80: // to never executing iFld2++ (we removed the check and the branch with the trap).
> 81: for (int i = -1; i < 1000; i++) {
> 82: if (Integer.compareUnsigned(i, 100) < 0) { // Loop Predication creates a Hoisted Range Check Predicate due to trap with Float.isNan().
Maybe add a comment explaining that this is equivalent to `i <u 100` <=> `i >= 0 && i < 100` and we add a predicate for the else branch, i.e. for `i < 0 || i >= 100`, and remove the if branch.
test/hotspot/jtreg/compiler/predicates/TestHoistedPredicateForNonRangeCheck.java line 103:
> 101: static void testCalendar2(boolean flag) {
> 102:
> 103: flag = !flag;
Suggestion:
flag = !flag;
-------------
Marked as reviewed by thartmann (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/14156#pullrequestreview-1445458846
PR Review Comment: https://git.openjdk.org/jdk/pull/14156#discussion_r1206393211
PR Review Comment: https://git.openjdk.org/jdk/pull/14156#discussion_r1206357502
More information about the hotspot-compiler-dev
mailing list