-
Notifications
You must be signed in to change notification settings - Fork 54
feat[next-dace]: Updated MoveDataflowIntoIfBody
#2460
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 3 commits
211956a
6a57bc9
83d99f3
4ed2ba6
c59e6c7
3e32691
501e60e
5a45f0a
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 | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -147,6 +147,7 @@ def can_be_applied( | |||||||
| if_block=if_block, | ||||||||
| raw_relocatable_dataflow=raw_relocatable_dataflow, | ||||||||
| non_relocatable_dataflow=non_relocatable_dataflow, | ||||||||
| enclosing_map=enclosing_map, | ||||||||
| ) | ||||||||
|
|
||||||||
| # If no branch has something to inline then we are done. | ||||||||
|
|
@@ -204,6 +205,7 @@ def apply( | |||||||
| if_block=if_block, | ||||||||
| raw_relocatable_dataflow=raw_relocatable_dataflow, | ||||||||
| non_relocatable_dataflow=non_relocatable_dataflow, | ||||||||
| enclosing_map=enclosing_map, | ||||||||
| ) | ||||||||
|
|
||||||||
| # Finally relocate the dataflow | ||||||||
|
|
@@ -551,6 +553,7 @@ def _has_if_block_relocatable_dataflow( | |||||||
| if_block=upstream_if_block, | ||||||||
| raw_relocatable_dataflow=raw_relocatable_dataflow, | ||||||||
| non_relocatable_dataflow=non_relocatable_dataflow, | ||||||||
| enclosing_map=enclosing_map, | ||||||||
| ) | ||||||||
| if all(len(rel_df) == 0 for rel_df in filtered_relocatable_dataflow.values()): | ||||||||
| return False | ||||||||
|
|
@@ -564,6 +567,7 @@ def _filter_relocatable_dataflow( | |||||||
| if_block: dace_nodes.NestedSDFG, | ||||||||
| raw_relocatable_dataflow: dict[str, set[dace_nodes.Node]], | ||||||||
| non_relocatable_dataflow: dict[str, set[dace_nodes.Node]], | ||||||||
| enclosing_map: dace_nodes.MapEntry, | ||||||||
| ) -> dict[str, set[dace_nodes.Node]]: | ||||||||
| """Partition the dependencies. | ||||||||
|
|
||||||||
|
|
@@ -581,6 +585,8 @@ def _filter_relocatable_dataflow( | |||||||
| that can be relocated, not yet filtered. | ||||||||
| non_relocatable_dataflow: The connectors and their associated dataflow | ||||||||
| that can not be relocated. | ||||||||
| enclosing_map: The limiting node, i.e. the MapEntry of the Map `if_block` | ||||||||
philip-paul-mueller marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
| is located in. | ||||||||
| """ | ||||||||
|
|
||||||||
| # Remove the parts of the dataflow that is unrelocatable. | ||||||||
|
|
@@ -592,8 +598,9 @@ def _filter_relocatable_dataflow( | |||||||
| for conn_name, rel_df in raw_relocatable_dataflow.items() | ||||||||
| } | ||||||||
|
|
||||||||
| # Now we determine the nodes that are in more than one sets. | ||||||||
| # These sets must be removed, from the individual sets. | ||||||||
| # Relocating nodes that are in more than one set is difficult. In the most | ||||||||
| # common case of just two branches, this anyway means they have to be | ||||||||
| # executed in any case. Thus we remove them now. | ||||||||
| known_nodes: set[dace_nodes.Node] = set() | ||||||||
| multiple_df_nodes: set[dace_nodes.Node] = set() | ||||||||
| for rel_df in relocatable_dataflow.values(): | ||||||||
|
|
@@ -606,35 +613,73 @@ def _filter_relocatable_dataflow( | |||||||
| for conn_name, rel_df in relocatable_dataflow.items() | ||||||||
| } | ||||||||
|
|
||||||||
| # However, not all dataflow can be moved inside the branch. For example if | ||||||||
| # something is used outside the dataflow, that is moved inside the `if`, | ||||||||
| # then we can not relocate it. | ||||||||
| # TODO(phimuell): If we operate outside of a Map we also have to make sure that | ||||||||
| # the data is single use data, is not an AccessNode that refers to global | ||||||||
| # memory nor is a source AccessNode. | ||||||||
| def filter_nodes( | ||||||||
| branch_nodes: set[dace_nodes.Node], | ||||||||
| sdfg: dace.SDFG, | ||||||||
| state: dace.SDFGState, | ||||||||
| nodes_proposed_for_reloc: set[dace_nodes.Node], | ||||||||
| ) -> set[dace_nodes.Node]: | ||||||||
| # For this to work the `if_block` must be considered part, we remove it later. | ||||||||
| branch_nodes.add(if_block) | ||||||||
| has_been_updated = True | ||||||||
| while has_been_updated: | ||||||||
| has_been_updated = False | ||||||||
| for node in list(branch_nodes): | ||||||||
| if node is if_block: | ||||||||
|
|
||||||||
| for reloc_node in list(nodes_proposed_for_reloc): | ||||||||
| assert ( | ||||||||
| state.in_degree(reloc_node) > 0 | ||||||||
| ) # Because we are currently always inside a Map | ||||||||
|
|
||||||||
| # If the node is needed by anything that is not also moved | ||||||||
| # into the `if` body, then it has to remain outside. For that we | ||||||||
| # have to pretend that `if_block` is also relocated. | ||||||||
| if any( | ||||||||
| oedge.dst not in nodes_proposed_for_reloc | ||||||||
| for oedge in state.out_edges(reloc_node) | ||||||||
| if oedge.dst is not if_block | ||||||||
| ): | ||||||||
| nodes_proposed_for_reloc.discard(reloc_node) | ||||||||
|
||||||||
| has_been_updated = True | ||||||||
| continue | ||||||||
| if any(oedge.dst not in branch_nodes for oedge in state.out_edges(node)): | ||||||||
| branch_nodes.remove(node) | ||||||||
|
|
||||||||
| # We do not look at all incoming nodes, but have to ignore some of them. | ||||||||
| # We ignore `enclosed_map` because it acts as boundary, and the node | ||||||||
| # on the other side of it is mapped into the `if` body anyway. Then we | ||||||||
| # have to ignore all AccessNodes, since they are either relocated into | ||||||||
| # the `if` body or are mapped into. We then have to look only at the | ||||||||
| # remaining nodes. | ||||||||
| incoming_nodes: set[dace_nodes.Node] = { | ||||||||
| iedge.src | ||||||||
| for iedge in state.in_edges(reloc_node) | ||||||||
| if not ( | ||||||||
| (iedge.src is enclosing_map) | ||||||||
| or isinstance(iedge.src, dace_nodes.AccessNode) | ||||||||
| ) | ||||||||
| } | ||||||||
| if incoming_nodes.issubset(nodes_proposed_for_reloc): | ||||||||
| # All nodes will be moved into the `if` body too, so no problem. | ||||||||
| pass | ||||||||
|
|
||||||||
| elif incoming_nodes.isdisjoint(nodes_proposed_for_reloc): | ||||||||
| # None of the incoming nodes will be moved into the if body, | ||||||||
| # thus `reloc_node` is an interface node, it might be _mapped_ | ||||||||
| # into the `if` body (if it is an `AccessNode`), but the node | ||||||||
| # itself will not be moved into the `if` body. | ||||||||
| nodes_proposed_for_reloc.discard(reloc_node) | ||||||||
| has_been_updated = True | ||||||||
| assert if_block in branch_nodes | ||||||||
| branch_nodes.remove(if_block) | ||||||||
| return branch_nodes | ||||||||
|
|
||||||||
| else: | ||||||||
| # Only some of the incoming nodes will be moved into the `if` | ||||||||
|
||||||||
| # Only some of the incoming nodes will be moved into the `if` | |
| # Only some of the incoming nodes could be moved into the `if` |
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 are right your suggestion is better.
Outdated
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.
and below:
| # body. This is legal only if the not moved nodes are | |
| # body. It would be legal to relocate the node if all incoming nodes were access nodes, this is why access nodes are not included in 'incoming_nodes'. | |
| # In this case, we cannot relocate the node, so we discard also those 'incoming_nodes' that were candidates for relocation. |
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 kind of like this suggestion, but it is partially a repetition of the comments about input_nodes.
However, I have renamed input_nodes (which is a bad name) to non_mappable_input_nodes which is a much more accurate then the old one and have updated the description by incorporating your suggestions.
I also have refactored it a bit it should be now simpler.
Uh oh!
There was an error while loading. Please reload this page.