• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / docc / 30614148740

31 Jul 2026 07:49AM UTC coverage: 64.691% (+0.2%) from 64.531%
30614148740

push

github

web-flow
Adding ProducerIntoConsumer MapFusion into the new, recursive MapFusionPass (#873)

Refactored the code of MapFusion Transform into MapFusionByAccessWorker.

The old transform still exists for its use as standalone transformation for now and also to run the old pass to cover everything not yet implemented in the new ByAccessWorker.

Refactored MapFusionByDomain into LoopFusionPass, the sequential & recursive loop-fusion logic into a base that handles the existing by-domain fusion and the by-access fusion, separately disablable.

For this, the existing per-loop caches of LoopFusionPass have been extended to contain the data needed by by-access fusion (assumptions, non-map loops and more details about subsets and locations of accesses).

LoopFusionPass still maintains these caches as fusions happen, so it never needs to clear any analysis.

For now, the MapFusionByAccessWorker has not been verified and skips any ConsumerIntoProducer fusions, as that is a greater change to how the cached data needs to be updated and its also a smaller portion of compile-time.

The MapFusionByAccessWorker was refactored to use the FusionLoopCandidate structure to access any cached data. It can be used as a basis for a new Transformation, that simply creates these per-loop structures on the fly, so that Transform and efficient pass can share code again.
The ByAccessWorker was also optimized to support per "fusion container" selection of replacing memory accesses with local transients and to consider the domain-equality checks already done by the NewMapFusionPass.

If the domains match, we can leave in the indirect writes in, which makes the fused code is a valid substitute for the original loop, avoiding the need for any loop-duplication.

Elliding same-subset indirect write-read patterns in the same block or successive blocks is a far easier problem to solve, then leaving the original loop lying around and hoping that it can be proven completely dead and removed by later ... (continued)

1388 of 1894 new or added lines in 13 files covered. (73.28%)

45088 of 69697 relevant lines covered (64.69%)

725.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.39
/opt/src/passes/normalization/map_fusion.cpp
1
#include "sdfg/passes/normalization/map_fusion.h"
2

3
#include "sdfg/data_flow/library_nodes/stdlib/malloc.h"
4
#include "sdfg/transformations/map_fusion.h"
5

6
namespace sdfg {
7
namespace passes {
8
namespace normalization {
9

10
MapFusion::MapFusion(
11
    builder::StructuredSDFGBuilder& builder,
12
    analysis::AnalysisManager& analysis_manager,
13
    bool allow_init_hoist,
14
    bool allow_prod_into_cons
15
)
16
    : visitor::NonStoppingStructuredSDFGVisitor(builder, analysis_manager), allow_init_hoist_(allow_init_hoist),
4✔
17
      allow_prod_into_cons_(allow_prod_into_cons) {}
4✔
18

19
bool MapFusion::accept(structured_control_flow::Sequence& node) {
14✔
20
    bool applied = false;
14✔
21

22
    if (node.size() < 2) {
14✔
23
        return applied;
8✔
24
    }
8✔
25

26
    // Iterate over sequence looking for consecutive (Map, StructuredLoop) pairs
27
    size_t i = 0;
6✔
28
    while (i + 1 < node.size()) {
12✔
29
        auto* first = dyn_cast<structured_control_flow::Map*>(&node.at(i));
6✔
30
        if (!first) {
6✔
31
            i++;
2✔
32
            continue;
2✔
33
        }
2✔
34
        if (first->root().size() == 0) {
4✔
35
            i++;
×
36
            continue;
×
37
        }
×
38

39
        if (auto* second = dyn_cast<structured_control_flow::StructuredLoop*>(&node.at(i + 1))) {
4✔
40
            if (second->root().size() == 0) {
4✔
41
                i++;
×
42
                continue;
×
43
            }
×
44
            transformations::MapFusion transformation(*first, *second, true, allow_init_hoist_, allow_prod_into_cons_);
4✔
45
            if (transformation.can_be_applied(builder_, analysis_manager_)) {
4✔
46
                auto first_id = first->element_id();
1✔
47
                auto second_id = second->element_id();
1✔
48
                transformation.apply(builder_, analysis_manager_);
1✔
49
                DEBUG_PRINTLN(
1✔
50
                    "Applied MapFusion to #" + std::to_string(first_id) + " " +
1✔
51
                    (transformation.last_fusion_direction() ==
1✔
52
                             loop_fusion::LoopFusionByAccessWorker::FusionDirection::ProducerIntoConsumer
1✔
53
                         ? "->"
1✔
54
                         : "<-") +
1✔
55
                    " #" + std::to_string(second_id)
1✔
56
                );
1✔
57
                applied = true;
1✔
58
            }
1✔
59
        } else if (i + 2 < node.size()) {
4✔
60
            auto* mid_block = dyn_cast<structured_control_flow::Block*>(&node.at(i + 1));
×
61
            if (mid_block && mid_block->is_a_library_node<stdlib::MallocNode>()) {
×
62
                if (auto* second = dyn_cast<structured_control_flow::StructuredLoop*>(&node.at(i + 2))) {
×
63
                    if (second->root().size() == 0) {
×
64
                        i++;
×
65
                        continue;
×
66
                    }
×
NEW
67
                    transformations::MapFusion
×
NEW
68
                        transformation(*first, *second, false, allow_init_hoist_, allow_prod_into_cons_);
×
69
                    if (transformation.can_be_applied(builder_, analysis_manager_)) {
×
NEW
70
                        auto first_id = first->element_id();
×
NEW
71
                        auto second_id = second->element_id();
×
72
                        transformation.apply(builder_, analysis_manager_);
×
73
                        DEBUG_PRINTLN(
×
NEW
74
                            "Applied MapFusion to #" + std::to_string(first_id) + " " +
×
NEW
75
                            (transformation.last_fusion_direction() ==
×
NEW
76
                                     loop_fusion::LoopFusionByAccessWorker::FusionDirection::ProducerIntoConsumer
×
NEW
77
                                 ? "->"
×
NEW
78
                                 : "<-") +
×
NEW
79
                            " #" + std::to_string(second_id) + " with intermediate malloc block"
×
80
                        );
×
81
                        applied = true;
×
82

83
                        // Move malloc block before the first map
84
                        this->builder_.move_child(node, i + 1, node, i);
×
85
                        i = i + 2; // Skip over the newly moved malloc block and the second loop that was just fused
×
86
                        continue;
×
87
                    }
×
88
                }
×
89
            }
×
90
        }
×
91
        i++;
4✔
92
    }
4✔
93

94
    return applied;
6✔
95
}
14✔
96

97
} // namespace normalization
98
} // namespace passes
99
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc