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
4 changes: 2 additions & 2 deletions llvm/integration/rodinia_openmp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,9 @@ def test_cfd(compiler="clang++-19"):
verification={
"sdfgs": 6,
"MAP": 14,
"CPU_PARALLEL": 5,
"CPU_PARALLEL": 12,
"FOR": 13,
"SEQUENTIAL": 22,
"SEQUENTIAL": 15,
}
)
runner = TestRunner(
Expand Down
1 change: 1 addition & 0 deletions opt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ set(SOURCE_FILES
src/passes/map_fusion_by_domain_pass.cpp
src/passes/opt_pipeline.cpp
src/passes/redundant_load_elimination_pass.cpp
src/passes/zero_fill_to_memset_pass.cpp
src/passes/scheduler/cuda_scheduler.cpp
src/passes/scheduler/rocm_scheduler.cpp
src/passes/scheduler/vectorize_scheduler.cpp
Expand Down
78 changes: 78 additions & 0 deletions opt/include/sdfg/passes/zero_fill_to_memset_pass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#pragma once

#include <memory>
#include <string>
#include <vector>

#include "sdfg/analysis/loop_analysis.h"
#include "sdfg/analysis/memory_layout_analysis.h"
#include "sdfg/passes/pass.h"
#include "sdfg/structured_control_flow/map.h"
#include "sdfg/symbolic/symbolic.h"
#include "sdfg/types/type.h"
#include "sdfg/visitor/structured_sdfg_visitor.h"

namespace sdfg::passes {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not nested namespace syntax as 99.9% of all other files?


/**
* @brief Replaces perfectly-nested Map loops that zero out an entire array with a single memset.
*
* The pass detects a perfect nest of Map loops whose only effect is to overwrite the
* complete contents of a (multi-dimensional) array container with the literal value 0
* (and nothing else). Such a nest is semantically equivalent to a `memset(A, 0, sizeof(A))`
* and is rewritten to a single stdlib::MemsetNode.
*
* A nest qualifies when:
* - Each loop level is a Map with `init == 0`, unit stride and an extractable exclusive
* upper bound; the nest is perfect (each Map body contains exactly the next level).
* - The innermost body is a single Block whose only computation assigns the constant 0
* to one element of the array, indexed exactly by the induction variables of the nest.
* - The MemoryLayoutAnalysis tile for the target container at the outermost Map covers the
* whole array contiguously from offset 0 (bounded dimensions match the declared extent,
* and the covered elements form a dense block), guaranteeing the whole array is covered.
* Relying on the layout analysis also transparently handles linearized accesses such as
* `A[i*M + j]`, which are delinearized to the underlying multi-dimensional shape.
*/
class ZeroFillToMemsetPass : public sdfg::passes::Pass {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

sdfg::passes:: unnecessary

public:
struct State {
size_t applied = 0;
};

std::string name() override { return "ZeroFillToMemset"; }

bool run_pass(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) override;
};

class ZeroFillToMemsetVisitor : public sdfg::visitor::ActualStructuredSDFGVisitor {
public:
struct Candidate {
structured_control_flow::Map* map;
std::string array;
symbolic::Expression num;
std::unique_ptr<types::IType> ptr_type;
};

private:
builder::StructuredSDFGBuilder& builder_;
ZeroFillToMemsetPass::State& state_;
analysis::MemoryLayoutAnalysis& memory_layout_analysis_;
analysis::LoopAnalysis& loop_analysis_;
std::vector<Candidate> candidates_;

bool match(structured_control_flow::Map& node, Candidate& candidate);

public:
ZeroFillToMemsetVisitor(
builder::StructuredSDFGBuilder& builder,
ZeroFillToMemsetPass::State& state,
analysis::MemoryLayoutAnalysis& memory_layout_analysis,
analysis::LoopAnalysis& loop_analysis
);

bool visit(structured_control_flow::Map& node) override;

void apply();
};

} // namespace sdfg::passes
8 changes: 4 additions & 4 deletions opt/include/sdfg/targets/rocm/stdlib/memset.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ class MemsetNodeDispatcher_ROCMWithTransfers : public codegen::LibraryNodeDispat
const sdfg::stdlib::MemsetNode& node
);

void dispatch_code(
codegen::PrettyPrinter& stream,
codegen::PrettyPrinter& globals_stream,
codegen::CodeSnippetFactory& library_snippet_factory
void dispatch_code_with_edges(
codegen::CodegenOutput& out,
std::vector<codegen::DispatchInput>& inputs,
std::vector<codegen::DispatchOutput>& outputs
) override;
};

Expand Down
3 changes: 1 addition & 2 deletions opt/src/passes/scheduler/omp_scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ SchedulerAction OMPScheduler::find(

auto& loop_analysis = analysis_manager.get<analysis::LoopAnalysis>();
auto loop_info = loop_analysis.loop_info(&loop);
if (loop_info.loopnest_index == -1 || loop_info.num_maps <= 1 || loop_info.is_perfectly_nested ||
loop_info.has_side_effects) {
if (loop_info.loopnest_index == -1 || loop_info.num_maps <= 1 || loop_info.is_perfectly_nested) {
return NEXT;
} else {
return CHILDREN;
Expand Down
Loading
Loading