-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8347901: C2 should remove unused leaf / pure runtime calls #25760
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1306,7 +1306,20 @@ void CallLeafVectorNode::calling_convention( BasicType* sig_bt, VMRegPair *parm_ | |||||
| bool CallLeafPureNode::is_unused() const { | ||||||
| return proj_out_or_null(TypeFunc::Parms) == nullptr; | ||||||
| } | ||||||
| // We make a tuple of the global input state + TOP for the output values. | ||||||
|
|
||||||
| bool CallLeafPureNode::is_dead() const { | ||||||
| return proj_out_or_null(TypeFunc::Control) == nullptr; | ||||||
| } | ||||||
|
|
||||||
| /* We make a tuple of the global input state + TOP for the output values. | ||||||
| * We use this to delete a pure function that is not used: by replacing the call with | ||||||
| * such a tuple, we let output Proj's idealization pick the corresponding input of the | ||||||
| * pure call, so jumping over it, and effectively, removing the call from the graph. | ||||||
| * This avoids doing the graph surgery manually, but leave that to IGVN | ||||||
marc-chevalier marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| * that is specialized for doing that right. We need also tuple components for output | ||||||
| * values of the function to respect the return arity, and in case there is a projection | ||||||
| * that would pick an output (which shouldn't happen at the moment). | ||||||
| */ | ||||||
| TupleNode* CallLeafPureNode::make_tuple_of_input_state_and_top_return_values(const Compile* C) const { | ||||||
| // Transparently propagate input state but parameters | ||||||
| TupleNode* tuple = TupleNode::make( | ||||||
|
|
@@ -1326,7 +1339,7 @@ TupleNode* CallLeafPureNode::make_tuple_of_input_state_and_top_return_values(con | |||||
| } | ||||||
|
|
||||||
| Node* CallLeafPureNode::Ideal(PhaseGVN* phase, bool can_reshape) { | ||||||
marc-chevalier marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| if (proj_out_or_null(TypeFunc::Control) == nullptr) { // dead node | ||||||
| if (is_dead()) { // dead node | ||||||
|
||||||
| if (is_dead()) { // dead node | |
| if (is_dead()) { |
The comment seemed redundant. You could say who else is responsible of cleaning up the dead node though.
What would happen if the CallLeafPureNode loses its control projection, but not the other uses? I don't even know if that is possible. What do you think?
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.
IGVN takes care of removing a node without output.
This was motivated by https://bugs.openjdk.org/browse/JDK-8353341 I think @TobiHartmann told me it's common not to touch dead nodes during idealization.
I think it is possible to lose control projection but not data because data was already found dead, but data wasn't yet (but should happen shortly after). As soon as the data projection disappear, the node should be removed. remove_dead_node (used in IGVN) is aggressively removing a dead node and all the usages that become recursively dead. It's the classic constraint of having to find that both data and control are top when one is.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -916,6 +916,7 @@ class CallLeafNode : public CallRuntimeNode { | |
| class CallLeafPureNode : public CallLeafNode { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need a short description about what this node is for. What are the assumptions about it? |
||
| protected: | ||
| bool is_unused() const; | ||
| bool is_dead() const; | ||
| TupleNode* make_tuple_of_input_state_and_top_return_values(const Compile* C) const; | ||
|
|
||
| public: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1520,7 +1520,7 @@ Node* ModFNode::Ideal(PhaseGVN* phase, bool can_reshape) { | |
| if (!can_reshape) { | ||
| return nullptr; | ||
| } | ||
|
||
| if (proj_out_or_null(TypeFunc::Control) == nullptr) { // dead node | ||
| if (is_dead()) { // dead node | ||
| return nullptr; | ||
| } | ||
|
|
||
|
|
@@ -1574,7 +1574,7 @@ Node* ModDNode::Ideal(PhaseGVN* phase, bool can_reshape) { | |
| if (!can_reshape) { | ||
| return nullptr; | ||
| } | ||
| if (proj_out_or_null(TypeFunc::Control) == nullptr) { // dead node | ||
| if (is_dead()) { // dead node | ||
| return nullptr; | ||
| } | ||
|
|
||
|
|
||
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.
Can you add a quick comment why this check implies that the node is not used, i.e. what that means?
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 i'll need you to explain to me what is unclear at the moment. When I read the function, I see:
"A CallLeafPure is unused iff there is no output result projection."
I don't see what else to add that is not covered by "if we don't use the result, the pure call is unused", which is exactly the code. Is there any untold hypothesis lurking somewhere that I don't see? It seems to me it uses just very common concepts of C2.
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 call could have other uses for other projections. Why does this projection make it unused?
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 suppose I was not aware that
TypeFunc::Parmsstands for result projection.... the name does not make it immediately apparent.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 see. I think I'd be better to comment on the declaration of the class then. Something saying that CallLeafPureNode represents calls that are pure: they only have data input and output data (and control for practical reasons for now), no exceptions, no memory, no safepoint... They can be freely be moved around, duplicated or, if the result isn't used, removed. Then that explains... a lot of what we are doing, not just
is_unused.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 I was really just confused about the
Parms. I thought that means parameters .. and not results 🤣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.
It's actually both. For functions, the parameters are starting at
Parms, and the results too. Before that, it's all the special stuff: control, memory, io...