Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions jlm/hls/backend/rvsdg2rhls/rvsdg2rhls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +488,13 @@ dump_ref(llvm::RvsdgModule & rhls, const util::filepath & path)
<< "\n";
}
::llvm::LLVMContext ctx;
jlm::util::StatisticsCollector statisticsCollector;
auto jm2 = llvm::RvsdgToIpGraphConverter::CreateAndConvertModule(*reference, statisticsCollector);
util::StatisticsCollector statisticsCollector;
auto sequentializer =
llvm::CreateIdempotentRegionTreeSequentializer(reference->Rvsdg().GetRootRegion());
auto jm2 = llvm::RvsdgToIpGraphConverter::CreateAndConvertModule(
*reference,
statisticsCollector,
sequentializer);
auto lm2 = llvm::IpGraphToLlvmConverter::CreateAndConvertModule(*jm2, ctx);
std::error_code EC;
::llvm::raw_fd_ostream os(path.to_str(), EC);
Expand Down
3 changes: 3 additions & 0 deletions jlm/llvm/Makefile.sub
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
libllvm_SOURCES = \
jlm/llvm/backend/dot/DotWriter.cpp \
jlm/llvm/backend/IpGraphToLlvmConverter.cpp \
jlm/llvm/backend/RegionSequentializer.cpp \
jlm/llvm/backend/RvsdgToIpGraphConverter.cpp \
\
jlm/llvm/frontend/ControlFlowRestructuring.cpp \
Expand Down Expand Up @@ -137,10 +138,12 @@ libllvm_HEADERS = \
jlm/llvm/ir/aggregation.hpp \
jlm/llvm/backend/dot/DotWriter.hpp \
jlm/llvm/backend/IpGraphToLlvmConverter.hpp \
jlm/llvm/backend/RegionSequentializer.hpp \
jlm/llvm/backend/RvsdgToIpGraphConverter.hpp \

libllvm_TESTS += \
tests/jlm/llvm/backend/dot/DotWriterTests \
tests/jlm/llvm/backend/ExhaustiveSequentializerTests \
tests/jlm/llvm/backend/IpGraphToLlvmConverterTests \
tests/jlm/llvm/backend/RvsdgToIpGraphConverterTests \
tests/jlm/llvm/frontend/llvm/LoadTests \
Expand Down
205 changes: 205 additions & 0 deletions jlm/llvm/backend/RegionSequentializer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
* Copyright 2025 Nico Reißmann <nico.reissmann@gmail.com>
* See COPYING for terms of redistribution.
*/

#include <jlm/llvm/backend/RegionSequentializer.hpp>
#include <jlm/rvsdg/region.hpp>
#include <jlm/rvsdg/traverser.hpp>
#include <jlm/util/HashSet.hpp>

namespace jlm::llvm
{

RegionSequentializer::~RegionSequentializer() noexcept = default;

RegionSequentializer::RegionSequentializer(rvsdg::Region & region)
: Region_(&region)
{}

ExhaustiveRegionSequentializer::ExhaustiveRegionSequentializer(rvsdg::Region & region)
: RegionSequentializer(region)
{
util::HashSet<const rvsdg::Node *> visited;
std::vector<const rvsdg::Node *> sequentializedNodes;
ComputeSequentializations(region, visited, sequentializedNodes);
}

void
ExhaustiveRegionSequentializer::ComputeNextSequentialization()
{
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().

}

Sequentialization
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?


return Sequentializations_[CurrentSequentialization_];
}

bool
ExhaustiveRegionSequentializer::HasMoreSequentializations() const noexcept
{
JLM_ASSERT(CurrentSequentialization_ <= Sequentializations_.size());
return CurrentSequentialization_ != Sequentializations_.size();
}

void
ExhaustiveRegionSequentializer::ComputeSequentializations(
const rvsdg::Region & region,
util::HashSet<const rvsdg::Node *> & visited,
std::vector<const rvsdg::Node *> & sequentializedNodes) noexcept
{
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

{
sequentializedNodes.push_back(&node);
visited.Insert(&node);

ComputeSequentializations(region, visited, sequentializedNodes);

visited.Remove(&node);
sequentializedNodes.pop_back();
}
}

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?

}

bool
ExhaustiveRegionSequentializer::AllPredecessorsVisited(
const rvsdg::Node & node,
const util::HashSet<const rvsdg::Node *> & visited)
{
for (size_t n = 0; n < node.ninputs(); n++)
{
auto & origin = *node.input(n)->origin();
if (const auto predecessor = rvsdg::TryGetOwnerNode<rvsdg::Node>(origin))
{
if (!visited.Contains(predecessor))
{
return false;
}
}
}

return true;
}

IdempotentRegionSequentializer::~IdempotentRegionSequentializer() noexcept = default;

IdempotentRegionSequentializer::IdempotentRegionSequentializer(rvsdg::Region & region)
: RegionSequentializer(region)
{}

void
IdempotentRegionSequentializer::ComputeNextSequentialization()
{}

Sequentialization
IdempotentRegionSequentializer::GetSequentialization()
{
auto sequentialization = Sequentialization();
for (const auto node : rvsdg::TopDownTraverser(&GetRegion()))
{
sequentialization.push_back(node);
}
return sequentialization;
}

bool
IdempotentRegionSequentializer::HasMoreSequentializations() const noexcept
{
return true;
}

RegionTreeSequentializer::~RegionTreeSequentializer() noexcept = default;

RegionTreeSequentializer::RegionTreeSequentializer(SequentializerMap sequentializerMap)
: Sequentializers_(std::move(sequentializerMap))
{}

void
RegionTreeSequentializer::ComputeNextSequentializations()
{
for (auto & [region, sequentializer] : Sequentializers_)
{
sequentializer->ComputeNextSequentialization();
}
}

bool
RegionTreeSequentializer::HasMoreSequentializations() const noexcept
{
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.

}

return false;
}

Sequentialization
RegionTreeSequentializer::GetSequentialization(rvsdg::Region & region)
{
JLM_ASSERT(Sequentializers_.find(&region) != Sequentializers_.end());
return Sequentializers_[&region]->GetSequentialization();
}

template<class TRegionSequentializer>
void
InitializeUniformRegionTreeSequentializer(
rvsdg::Region & region,
SequentializerMap & sequentializerMap)
{
auto sequentializer = std::make_unique<TRegionSequentializer>(region);

for (auto & node : region.Nodes())
{
if (const auto structuralNode = dynamic_cast<const rvsdg::StructuralNode *>(&node))
{
for (size_t n = 0; n < structuralNode->nsubregions(); n++)
{
const auto subregion = structuralNode->subregion(n);
InitializeUniformRegionTreeSequentializer<TRegionSequentializer>(
*subregion,
sequentializerMap);
}
}
}

sequentializerMap[&region] = std::move(sequentializer);
}

RegionTreeSequentializer
CreateIdempotentRegionTreeSequentializer(rvsdg::Region & rootRegion)
{
SequentializerMap sequentializerMap;
InitializeUniformRegionTreeSequentializer<IdempotentRegionSequentializer>(
rootRegion,
sequentializerMap);
return RegionTreeSequentializer(std::move(sequentializerMap));
}

RegionTreeSequentializer
CreateExhaustiveRegionTreeSequentializer(rvsdg::Region & rootRegion)
{
SequentializerMap sequentializerMap;
InitializeUniformRegionTreeSequentializer<ExhaustiveRegionSequentializer>(
rootRegion,
sequentializerMap);
return RegionTreeSequentializer(std::move(sequentializerMap));
}

}
Loading
Loading