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

Remove invariant state edges between Lambda[Entry|Exit]MemoryState nodes #785

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

sjalander
Copy link
Collaborator

@sjalander sjalander commented Jan 30, 2025

If the pass results in a single noninvariant state edge, then the Lambda[Exit|Entry]MemoryState nodes are removed.

Copy link

The execution time of dynamatic/pivot has changed
  Golden cycle time: 1190
  Simulated cycles: 1181

Copy link
Collaborator

@haved haved left a comment

Choose a reason for hiding this comment

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

I have some suggestions in comments, but looks good overall

@phate do you think it would make sense to put the InvariantMemoryStateEdge removal in llvm instead? It does not contain anything HLS specific

// We only apply this for memory state edges that is invariant between
// LambdaEntryMemoryStateSplit and LambdaExitMemoryStateMerge nodes.
// So we first check if we have a LambdaExitMemoryStateMerge node.
if (memoryState->origin()->nusers() == 1)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This if could be an early return, which would help avoid the deep nesting below

Copy link
Collaborator Author

@sjalander sjalander Jan 31, 2025

Choose a reason for hiding this comment

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

The second check is enough, so this one has been removed.

if (memoryState->origin()->nusers() == 1)
{
auto exitNode = rvsdg::output::GetNode(*memoryState->origin());
if (rvsdg::is<const llvm::LambdaExitMemoryStateMergeOperation>(exitNode->GetOperation()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

This too could be an early return

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Changed to an early return.

* @brief Remove invariant memory state edges between Lambda[Entry/Exit]MemoryState nodes.
*
* The pass checks all lambdas in the module for invariant memory state edges between a
* LambdaEntreyMemoryStateSplit and LambdaExitMemoryStateMerge node and removes them. The memory
Copy link
Collaborator

Choose a reason for hiding this comment

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

This docstring repeats some details from the other docstring. Maybe add a @see instead to keep things in one place

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Rewrote the text and added the @see

Copy link

The execution time of dynamatic/pivot has changed
  Golden cycle time: 1190
  Simulated cycles: 1181

Copy link

The execution time of dynamatic/pivot has changed
  Golden cycle time: 1190
  Simulated cycles: 1181

@sjalander sjalander changed the title Improved removal of invariant state edges Remove invariant state edges between Lambda[Entry|Exit]MemoryState nodes Feb 1, 2025
Copy link

github-actions bot commented Feb 1, 2025

The execution time of dynamatic/pivot has changed
  Golden cycle time: 1190
  Simulated cycles: 1181

Copy link
Owner

@phate phate left a comment

Choose a reason for hiding this comment

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

I stopped reviewing after I saw what that pass tries to do. This should be added to the InvariantValueRedirection pass and not be its own pass. As the pass is currently, it also does not take care of calls, which limits its applicability significantly.

@haved
Copy link
Collaborator

haved commented Feb 2, 2025

@phate I see what you mean about being a part of invariant value redirection. One thing to note there is that IVR only performs redirections, and does not remove dead state edges. This means IVR can remove invariant states from the LambdaMemoryStateMerge, but not always from the LambdaMemoryStateSplit. A simple solution is to leave that for dead node elimination to handle. In the meantime there will be a mismatch between the split and merge, but that is probably fine?

@phate
Copy link
Owner

phate commented Feb 3, 2025

@haved @sjalander : Let's hold back on this one until after the meeting tomorrow. I thought a little bit about it last night. There is more to it than immediately meets the eye. It is better to have a whiteboard available.

Copy link

github-actions bot commented Feb 3, 2025

The execution time of dynamatic/pivot has changed
  Golden cycle time: 1190
  Simulated cycles: 1181

@sjalander sjalander requested review from haved and phate February 10, 2025 10:05
Copy link
Owner

@phate phate left a comment

Choose a reason for hiding this comment

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

The code can be simplified quite a bit, but otherwise LGTM.

#ifndef JLM_HLS_OPT_INVARIANTLAMBDAMEMORYSTATEREMOVAL_HPP
#define JLM_HLS_OPT_INVARIANTLAMBDAMEMORYSTATEREMOVAL_HPP

#include <jlm/rvsdg/region.hpp>
Copy link
Owner

Choose a reason for hiding this comment

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

I think the only reason why you need this header is because of rvsdg::RegionResult, but that can be forward declared and the header is not necessary.

* @brief Remove invariant memory state edges between Lambda[Entry/Exit]MemoryState nodes.
*
* The pass applies RemoveInvariantMemoryStateEdges(rvsdg::RegionResult * memoryState) to all
* memory states of all lambdas in the module.
Copy link
Owner

Choose a reason for hiding this comment

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

of all lambdas in the module that are only exported.

Comment on lines +56 to +57
* @param rvsdgModule The RVSDG moduled for which invariant memory state edges in all lambda nodes
* are to be removed.
Copy link
Owner

Choose a reason for hiding this comment

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

for which invariant memory state edges are removed in lambdas.

}
};

/* InvariantLambdaMemoryStateRemoval class */
Copy link
Owner

Choose a reason for hiding this comment

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

Can be removed.

Comment on lines +167 to +168
InvariantLambdaMemoryStateRemoval::~InvariantLambdaMemoryStateRemoval()
{}
Copy link
Owner

Choose a reason for hiding this comment

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

... = default;

Comment on lines +61 to +64
// The memory state edge is invariant, so we could in principle remove it from the lambda
// But the LLVM dialect expects to always have a memory state, so we connect the argument
// directly to the result
memoryState->divert_to(entryNode->input(0)->origin());
Copy link
Owner

Choose a reason for hiding this comment

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

You seem to assume here that you only have a single non-invariant state edge. What about if all state edges are non-invariant?

else if (outputs.size() == 1)
{
// Single edge that is not invariant, so we can elmintate the two MemoryState nodes
memoryState->divert_to(outputs.front());
Copy link
Owner

Choose a reason for hiding this comment

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

outputs[0] is a bit more readable.

{
// Single edge that is not invariant, so we can elmintate the two MemoryState nodes
memoryState->divert_to(outputs.front());
entryNode->output(indexes.front())->divert_users(entryNode->input(0)->origin());
Copy link
Owner

Choose a reason for hiding this comment

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

This line should not be necessary, I believe. After the line above, the exit node and entry node should be dead.


void
InvariantLambdaMemoryStateRemoval::RemoveInvariantMemoryStateEdges(
rvsdg::RegionResult * memoryState)
Copy link
Owner

Choose a reason for hiding this comment

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

Maybe you can call it memoryStateResult so one does know what exactly it is when reading the code.

int i = 0;
for (auto index : indexes)
{
entryNode->output(index)->divert_users(newEntryNodeOutputs.at(i));
Copy link
Owner

Choose a reason for hiding this comment

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

newEntryNodeOutputs[i]

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.

3 participants