Skip to content
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

feature[next]: Non-tree-size-increasing collapse tuple on ifs #1762

Merged
merged 27 commits into from
Jan 15, 2025

Conversation

tehrengruber
Copy link
Contributor

@tehrengruber tehrengruber commented Dec 1, 2024

Removing the tuple expressions across if_ calls on ITIR has been a pain point in the past. While the PROPAGATE_TO_IF_ON_TUPLES option of the CollapseTuplePass works very reliably, the resulting increase in the tree size has been prohibitive. With the refactoring to GTIR this problem became much less pronounced, as we could restrict the propagation to field-level, i.e., outside of stencils, but the tree still grew exponentially in the number of references to boolean arguments used inside if_ conditions. This PR adds an additional option PROPAGATE_TO_IF_ON_TUPLES_CPS to the CollapseTuplePass, which is similar to the existing PROPAGATE_TO_IF_ON_TUPLES, but propagates in the opposite direction, i.e. into the tree. This allows removal of tuple expressions across if_ calls without increasing the size of the tree. This is particularly important for if statements in the frontend, where outwards propagation can have devastating effects on the tree size, without any gained optimization potential. For example

complex_lambda(if cond1
  if cond2
    {...}
  else:
    {...}
else
  {...})

is problematic, since PROPAGATE_TO_IF_ON_TUPLES would propagate, and hence duplicate, complex_lambda three times, while we only want to get rid of the tuple expressions inside of the if_s. Note that this transformation is not mutually exclusive to PROPAGATE_TO_IF_ON_TUPLES.

Copy link
Contributor

@havogt havogt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need more documentation of the new trafo or additionally a more detailed explanation on how it works.

src/gt4py/next/iterator/transforms/collapse_tuple.py Outdated Show resolved Hide resolved
src/gt4py/next/iterator/transforms/collapse_tuple.py Outdated Show resolved Hide resolved
@@ -185,6 +229,8 @@ def transform(self, node: ir.Node, **kwargs) -> Optional[ir.Node]:
method = getattr(self, f"transform_{transformation.name.lower()}")
result = method(node, **kwargs)
if result is not None:
assert result is not node
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this assert useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case one (erronously) returns the same node again instead of None to signify no change, fp_transform runs into an endless loop. This is a cheap way to prevent this case.

src/gt4py/next/iterator/transforms/collapse_tuple.py Outdated Show resolved Hide resolved
self, node: ir.FunCall, **kwargs
) -> Optional[ir.Node]:
if not cpm.is_call_to(node, "if_"):
for i, arg in enumerate(node.args):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we iterate over any functions args or do we know more?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No we don't know more. We need to build and simplify the continuation first to know if we want to transform. It might be possible to handle multiple ifs, but the code would become more complex and error prone, and there is no benefit. It is just important to remember that the entire node is split into the continuation and the first matching if argument.

Contrary to the regular inference, this method does not descend into already typed sub-nodes
and can be used as a lightweight way to restore type information during a pass.

Note that this function is stateful, which is usually desired, and more performant.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the statefulness?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reformulated:

Note that this function alters the input node, which is usually desired, and more performant.

@tehrengruber tehrengruber requested a review from havogt January 10, 2025 00:36
Copy link
Contributor

@havogt havogt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only have a few proposals to improve readability.

src/gt4py/next/iterator/transforms/collapse_tuple.py Outdated Show resolved Hide resolved
src/gt4py/next/iterator/transforms/collapse_tuple.py Outdated Show resolved Hide resolved
src/gt4py/next/iterator/transforms/collapse_tuple.py Outdated Show resolved Hide resolved
@tehrengruber tehrengruber merged commit 21e7f64 into GridTools:main Jan 15, 2025
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants