-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8323972: C2 compilation fails with assert(!x->as_Loop()->is_loop_nest_inner_loop()) failed: loop was transformed #17965
Conversation
👋 Welcome back roland! A progress list of the required criteria for merging this PR into |
// a negative stride). We add a CastII here to guarantee that, when the counted loop is created in a subsequent loop | ||
// opts pass, an accurate range of values for the limits is found. | ||
const TypeInt* inner_iters_actual_int_range = TypeInt::make(0, iters_limit, Type::WidenMin); | ||
inner_iters_actual_int = new CastIINode(outer_head, inner_iters_actual_int, inner_iters_actual_int_range, ConstraintCastNode::UnconditionalDependency); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix idea looks reasonable to me. I have two questions:
- Do we really need to pin the
CastII
here? We have not pinned theConvL2I
before. And here I think we just want to ensure that the type is not lost. - Related to the first question, could we just use a normal dependency instead?
I was also wondering if we should try to improve the type of ConvL2I
and of Add/Sub
(and possibly also Mul
) nodes in general? For ConvL2I
, we could set a better type if we know that (int)lo <= (int)hi
and abs(hi - lo) <= 2^32
. We still have a problem to set a better type if we have a narrow range of inputs that includes min
and max
(e.g. min+1, min, max, max-1
). In this case, ConvL2I
just uses int
as type. Then we could go a step further and do the same type optimization for Add/Sub
nodes by directly looking through a convert/cast node at the input type. The resulting Add/Sub
range could maybe be represented by something better than int
:
Example:
input type to ConvL2I
: [2147483647L, 2147483648L]
-> type of ConvL2I
is int
since we cannot represent "[max_int, min_int]
" with two intervals otherwise.
AddI
= ConvL2I
+ 2 -> type could be improved to [min_int+1,min_int+2]
.
But that might succeed the scope of this fix. Going with CastII
for now seems to be the least risk.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing this.
The fix idea looks reasonable to me. I have two questions:
* Do we really need to pin the `CastII` here? We have not pinned the `ConvL2I` before. And here I think we just want to ensure that the type is not lost.
I think it's good practice to set the control of a cast node. It probably doesn't make much of a difference here but we had so many issues with cast nodes that not setting control on cast makes me nervous now.
* Related to the first question, could we just use a normal dependency instead?
The problem with a normal dependency is that initially the cast and its non transformed input have the same types. So, there is a chance the cast is processed by igvn before its input changes and if that happens, the cast would then be removed.
I was also wondering if we should try to improve the type of
ConvL2I
and ofAdd/Sub
(and possibly alsoMul
) nodes in general? ForConvL2I
, we could set a better type if we know that(int)lo <= (int)hi
andabs(hi - lo) <= 2^32
. We still have a problem to set a better type if we have a narrow range of inputs that includesmin
andmax
(e.g.min+1, min, max, max-1
). In this case,ConvL2I
just usesint
as type. Then we could go a step further and do the same type optimization forAdd/Sub
nodes by directly looking through a convert/cast node at the input type. The resultingAdd/Sub
range could maybe be represented by something better thanint
:Example: input type to
ConvL2I
:[2147483647L, 2147483648L]
-> type ofConvL2I
isint
since we cannot represent "[max_int, min_int]
" with two intervals otherwise.AddI
=ConvL2I
+ 2 -> type could be improved to[min_int+1,min_int+2]
.But that might succeed the scope of this fix. Going with
CastII
for now seems to be the least risk.
I thought about that too (I didn't go as far as you did though) and my conclusion is that the change I propose should be more robust (what if the improved type computation still misses some cases that we later find are required) and less risky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's good practice to set the control of a cast node. It probably doesn't make much of a difference here but we had so many issues with cast nodes that not setting control on cast makes me nervous now.
That is indeed a general problem. The situation certainly got better by removing the code that optimized cast nodes that were pinned at If Projections (7766785). By pinning the casts now, you probably want to prevent the cast nodes to be pushed through nodes such that it floats "too high" and causing unforeseenable data graph folding while control is not?
The problem with a normal dependency is that initially the cast and its non transformed input have the same types. So, there is a chance the cast is processed by igvn before its input changes and if that happens, the cast would then be removed.
I see, thanks for the explanation. Then it makes sense to keep the cast node not matter what.
I thought about that too (I didn't go as far as you did though) and my conclusion is that the change I propose should be more robust (what if the improved type computation still misses some cases that we later find are required) and less risky.
I agree, this fix should use casts. Would be interesting to follow this idea in a separate RFE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is indeed a general problem. The situation certainly got better by removing the code that optimized cast nodes that were pinned at If Projections (7766785). By pinning the casts now, you probably want to prevent the cast nodes to be pushed through nodes such that it floats "too high" and causing unforeseenable data graph folding while control is not?
Something like that. I don't see how things could go wrong in this particular case so, quite possibly, the control input is useless.
@rwestrel This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 446 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks reasonable, but these ad-hoc CastII also make me nervous.
What worries me with adding such "Ad-Hoc" CastII nodes is that elsewhere a very similar computation may not have the same tight type. And then you have a tight type somewhere, and a loose type elsewhere. This is how we get the data-flow collapsing and the cfg not folding.
} | ||
|
||
public static void test() { | ||
for (long i = 9223372034707292164L; i > 9223372034707292158L; i += -2L) { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm always amazed at how such simple tests can fail. Is there any way we can improve the test coverage for Long loops?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fuzzer test cases that call Objects.checkIndex()
I suppose would possibly catch bugs.
@rwestrel please wait for our testing to complete, I just launched it. |
I agree with that. Still feels like the most reasonable fix for this particular issue. |
Thanks for running it. Any update on testing? |
@rwestrel Yes, the tests are passing! Ship it! 🚢 |
@chhagedorn @eme64 thanks for the reviews! |
/integrate |
Going to push as commit e1b0af2.
Your commit was automatically rebased without conflicts. |
Long counted loop are transformed into a loop nest of 2 "regular"
loops and in a subsequent loop opts round, the inner loop is
transformed into a counted loop. The limit for the inner loop is set,
when the loop nest is created, so it's expected there's no need for a
loop limit check when the counted loop is created. The assert fires
because, when the counted loop is created, it is found that it needs a
loop limit check. The reason for that is that the limit is
transformed, between nest creation and counted loop creation, in a way
that the range of values of the inner loop's limit becomes
unknown. The limit when the nest is created is:
The type of 122 is
2..6
but it is then transformed to:That is the
(ConvL2I (AddL ...))
is transformed into a(SubI (ConvL2I ))
.ConvL2I
for an input that's out of the int range ofvalues returns TypeInt::INT and the bounds of the limit are lost. I
propose adding a
CastII
after theConvL2I
so the range of valuesof the limit doesn't get lost.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/17965/head:pull/17965
$ git checkout pull/17965
Update a local copy of the PR:
$ git checkout pull/17965
$ git pull https://git.openjdk.org/jdk.git pull/17965/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 17965
View PR using the GUI difftool:
$ git pr show -t 17965
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/17965.diff
Webrev
Link to Webrev Comment