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

Region Sequentializer #839

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft

Region Sequentializer #839

wants to merge 8 commits into from

Conversation

phate
Copy link
Owner

@phate phate commented Mar 28, 2025

This PR separates the sequentialization of the nodes from the LLVM converter. The reason for this change are as follows:

  1. The idea is to implement a small debugging command line tool that takes an LLVM module as input, and outputs all possible sequentializations of nodes within the module. Each new combination is output as its own module, which can then be compiled and executed to see that all combinations result in the same output. This obviously only works for small modules.
  2. We can eventually implement some heuristics to give a "better" sequentialization as the random one we are currently have.

This draft is mean to get feedback. I will later split it up in proper PRs and clean it up.

@haved @caleridas

@phate phate requested review from haved and caleridas March 28, 2025 17:18
const util::HashSet<const rvsdg::Node *> & visited);

size_t CurrentSequentialization_ = 0;
std::vector<Sequentialization> Sequentializations_;
Copy link
Owner Author

Choose a reason for hiding this comment

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

Yes, I am aware that this is exponential in space. However, I would like to start with this first.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That is fine. Looking at the implementation, it should be quite easy to make it linear in space by just storing the sequence, and possibly a nodeIteratiorIndex for each node.

return 0;
}

JLM_UNIT_TEST_REGISTER("jlm/llvm/backend/ExhaustiveSequentializerTests-Test", Test)
Copy link
Owner Author

Choose a reason for hiding this comment

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

I will implement proper unit tests once the region sequentializer interface is settled etc.

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.

Overall the design looks good and extensible. My only issue is with the API for iterating over sequentializations, as it is hard to keep track of when sequentializations start looping (silently when requesting a sequentialization).

Could we instead have a design where a sequentializer's GetSequentialization() always gives a valid sequentialization, and ComputeNextSequentialization() intead starts returning false when it is no longer changing the current sequentialization.

While it might be nice in some cases to query if there exist more sequentializations, without moving on to the next one, that does make it a bit harder for implementations to implement the interface. My suggested interface would instead be used like

do {
  auto & seq= sequentializer.GetSequentialization();
} while(sequentializer.ComputeNextSequentialization())

@phate

ExhaustiveRegionSequentializer::GetSequentialization()
{
if (!HasMoreSequentializations())
ComputeNextSequentialization();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I do not understand this code. Why can it not just return Sequentializations_[CurrentSequentialization_]. This code will effectively reset CurrentSequentialization_ to 0 if we are at the last sequentialization?

if (HasMoreSequentializations())
CurrentSequentialization_++;
else
CurrentSequentialization_ = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this looping behavior is a bit surprising. It sort of allows overflow, but then automatically fixes the overflow again once you actually call GetSequentialization().

The way it is currently, you have to query HasMoreSequentialization() after ComputeNextSequentialization(), to find out that it actually didn't have a "next sequentialization".
I feel like that naming is a bit backwards, as I would expect to call HasMoreSequentializations() before calling ComputeNextSequentialization().

If would consider remaning HasMoreSequentializations() to just HasSequentialization().

if (sequentializedNodes.size() == region.nnodes())
{
Sequentializations_.emplace_back(sequentializedNodes);
}
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 should not be inside the loop, no?
It should instead be at the very top of this function, and early return if the condition is true?

{
for (auto & node : region.Nodes())
{
if (AllPredecessorsVisited(node, visited) && !visited.Contains(&node))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would swap the order of the conditions, to skip visited nodes more quickly

const util::HashSet<const rvsdg::Node *> & visited);

size_t CurrentSequentialization_ = 0;
std::vector<Sequentialization> Sequentializations_;
Copy link
Collaborator

Choose a reason for hiding this comment

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

That is fine. Looking at the implementation, it should be quite easy to make it linear in space by just storing the sequence, and possibly a nodeIteratiorIndex for each node.

for (auto & [_, sequentializer] : Sequentializers_)
{
if (sequentializer->HasMoreSequentializations())
return true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Due to the looping behavior of the exhaustive sequentializer, I would be a bit worried about the RegionTreeSequentializer looping for a very long time, if it has two regions with, e.g., 11 and 10 sequentializations, it would run for 110 iterations before both sequentializers "line up" and have HasMoreSequentializations() return false.

* sequentialization.
*/
virtual Sequentialization
GetSequentialization() = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we make it return a const reference? If the user truly needs it to outlive the sequentializer they can always make a copy

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