-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
8353290: C2: Refactor PhaseIdealLoop::is_counted_loop() #24458
base: master
Are you sure you want to change the base?
Conversation
👋 Welcome back kxu! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
/reviewers 2 C2 changes |
This reverts commit fd60717.
Webrevs
|
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's a good idea to refactor this, thanks for tackling it! Some initial general comments, I will have a closer look at your patch later again.
src/hotspot/share/opto/loopnode.cpp
Outdated
@@ -310,7 +310,7 @@ IdealLoopTree* PhaseIdealLoop::insert_outer_loop(IdealLoopTree* loop, LoopNode* | |||
// clone the outer loop as well as the inner, unrolling needs to only | |||
// clone the inner loop etc. No optimizations need to change the outer | |||
// strip mined loop as it is only a skeleton. | |||
IdealLoopTree* PhaseIdealLoop::create_outer_strip_mined_loop(BoolNode *test, Node *cmp, Node *init_control, | |||
IdealLoopTree* PhaseIdealLoop::create_outer_strip_mined_loop(Node *init_control, |
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.
Generally, for the touched code, you can also fix the *
placement to be at the type.
IdealLoopTree* PhaseIdealLoop::create_outer_strip_mined_loop(Node *init_control, | |
IdealLoopTree* PhaseIdealLoop::create_outer_strip_mined_loop(Node* init_control, |
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.
Good point. I tried to fix them as I go but missed this one.
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.
With the x
-> head
change, there are some more opportunities :-)
src/hotspot/share/opto/loopnode.cpp
Outdated
@@ -364,7 +364,7 @@ void PhaseIdealLoop::insert_loop_limit_check_predicate(ParsePredicateSuccessProj | |||
#endif | |||
} | |||
|
|||
Node* PhaseIdealLoop::loop_exit_control(Node* x, IdealLoopTree* loop) { | |||
Node* PhaseIdealLoop::loop_exit_control(const Node* x, const IdealLoopTree* loop) const { |
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.
There are quite some places where we use x
to denote a loop_head
. Maybe you can also fix that with this patch.
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 would prefer a simple head
for function named .*loop.*
. Updated all relevant functions I touched.
Node* phi_incr = nullptr; | ||
incr = loop_iv_incr(incr, x, loop, phi_incr); | ||
assert(incr != nullptr && incr->Opcode() == Op_Add(bt), "no incr"); | ||
LoopExitTest exit_test = loop_exit_test(back_control, loop); |
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.
Just an idea: Would it make sense to have a single LoopStructure
(or another name) class that contains all the information stored now with separate structs LoopExitTest
, LoopIvIncr
and LoopIvStride
? Then we could offer query methods for validation like is_valid()
, is_stride_valid()
etc., or check for existence like has_stride()
, or access specific nodes like stride()
, incr()
etc.
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.
Let me see what I can do! :)
IdealLoopTree* loop, float cl_prob, float le_fcnt, | ||
Node*& entry_control, Node*& iffalse); | ||
|
||
class CountedLoopConverter { |
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.
Probably quite a subjective matter, but what about just naming it CountedLoop
? Then you have counted_loop.convert()
.
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 disagree: I don't want to confuse it with CountedLoopNode
or making it looks like extending from IdealLoopTree
. Besides it wouldn't not necessarily guarantee a counted loop until confirmed by is_counted_loop()
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.
What I had in mind was something like that (I'm also fine with CountedLoopConverter
:
CountedLoop counted_loop(...);
counted_loop.convert();
return counted_loop.is_valid();
But maybe you can explain in more detail what the follow-up work will be and how you use this class again later?
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.
About the placement of this class. You could probably also move it out of the already huge PhaseIdealLoop
class to make it a non-inner class, if there is not some strong coupling that you absolutely need.
IdealLoopTree* loop, float cl_prob, float le_fcnt, | ||
Node*& entry_control, Node*& iffalse); | ||
|
||
class CountedLoopConverter { | ||
PhaseIdealLoop* _phase; |
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 suggest to add const
whenever you can. For example, here you will probably not change the _phase
pointer anymore:
PhaseIdealLoop* _phase; | |
PhaseIdealLoop* const _phase; |
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 was my initial thought, too; however, PhaseIdealLoop::insert_loop_limit_check_predicate()
, ::lazy_replace()
, ::set_subtree_ctrl()
and many other mutations make this impossible.
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.
You might be confusing it with having:
const PhaseIdealLoop* _phase
where we cannot call any non-const methods. That's indeed not possible. But what I mean was to make the pointer const:
PhaseIdealLoop* const _phase;
such that you cannot do _phase = xyz
later. You would probably not do that anyway but it's an easy addition and safety for all fields not being reassigned again. It also helps to see which fields are going to be updated as part of the mutable state and which fields are not.
src/hotspot/share/opto/loopnode.hpp
Outdated
Node* _phi_incr; | ||
Node* _stride; | ||
bool _includes_limit; | ||
BoolTest::mask _mask; | ||
Node* _increment; |
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.
Here you have (_phi_)incr
and increment
. I suggest to make the naming consistent. I personally prefer full names whenever we can if it's not a universal abbreviation like cmp
or iv
. But what we count as well-known abbreviation is debatable and also depends on personal taste.
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.
Updated s/_phi_incr/_phi_increment
src/hotspot/share/opto/loopnode.hpp
Outdated
float _cl_prob; | ||
Node* _sfpt; | ||
jlong _final_correction; | ||
Node* _trunc1; |
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.
trunc1
is a little hard to understand. Can we find a better name?
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.
Droped Node* _trunc1
in favour of TypeInteger* _increment_truncation_type
. Added a note in should_stress_long_counted_loop()
.
return false; | ||
} | ||
|
||
bool PhaseIdealLoop::CountedLoopConverter::is_counted_loop() { |
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.
is_counted_loop()
is still huge. When trying to refactor it anyway, it might be a good idea to further split the code up into separate methods for all the different checks. That would increase the readability since we have a lot of different checks.
IdealLoopTree* loop, float cl_prob, float le_fcnt, | ||
Node*& entry_control, Node*& iffalse); | ||
|
||
class CountedLoopConverter { |
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.
About the placement of this class. You could probably also move it out of the already huge PhaseIdealLoop
class to make it a non-inner class, if there is not some strong coupling that you absolutely need.
This PR refactors
PhaseIdealLoop::is_counted_loop()
into (mostly)CountedLoopConverter::is_counted_loop()
andCountedLoopConverter::convert()
to decouple the detection and conversion code. This enables us to try different loop configurations easily and finally convert once a counted loop is found.A nested
PhaseIdealLoop::CountedLoopConverter
class is created to handle the context, but I'm not if this is the best name or place for it. Please let me know what you think.Blocks JDK-8336759.
Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/24458/head:pull/24458
$ git checkout pull/24458
Update a local copy of the PR:
$ git checkout pull/24458
$ git pull https://git.openjdk.org/jdk.git pull/24458/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 24458
View PR using the GUI difftool:
$ git pr show -t 24458
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/24458.diff
Using Webrev
Link to Webrev Comment