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

daisytuner / sdfglib / 16439520920

22 Jul 2025 08:53AM UTC coverage: 65.927% (+0.8%) from 65.094%
16439520920

Pull #153

github

web-flow
Merge a0eea6968 into abe57c083
Pull Request #153: Restricts memlets to contiguous memory

211 of 300 new or added lines in 29 files covered. (70.33%)

66 existing lines in 7 files now uncovered.

8314 of 12611 relevant lines covered (65.93%)

128.5 hits per line

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

75.2
/src/passes/dataflow/reference_propagation.cpp
1
#include "sdfg/passes/dataflow/reference_propagation.h"
2

3
#include "sdfg/analysis/users.h"
4
#include "sdfg/types/utils.h"
5

6
namespace sdfg {
7
namespace passes {
8

9
ReferencePropagation::ReferencePropagation()
4✔
10
    : Pass() {
4✔
11

12
      };
4✔
13

NEW
14
std::string ReferencePropagation::name() { return "ReferencePropagation"; };
×
15

16
bool ReferencePropagation::run_pass(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
3✔
17
    bool applied = false;
3✔
18

19
    auto& sdfg = builder.subject();
3✔
20

21
    // Replaces all views
22
    auto& users = analysis_manager.get<analysis::Users>();
3✔
23
    std::unordered_set<std::string> reduced;
3✔
24
    for (auto& container : sdfg.containers()) {
9✔
25
        if (reduced.find(container) != reduced.end()) {
6✔
26
            continue;
1✔
27
        }
28
        if (sdfg.is_external(container)) {
5✔
29
            continue;
×
30
        }
31

32
        // By definition, a view is a pointer
33
        auto& type = sdfg.type(container);
5✔
34
        if (!dynamic_cast<const types::Pointer*>(&type)) {
5✔
35
            continue;
×
36
        }
37

38
        // Criterion: Must have at least one move
39
        auto moves = users.moves(container);
5✔
40
        if (moves.empty()) {
5✔
41
            continue;
3✔
42
        }
43

44
        // Criterion: No sub-views (will be eliminated iteratively)
45
        if (users.views(container).size() > 0) {
2✔
46
            continue;
×
47
        }
48

49
        // Eliminate views
50
        auto uses = users.uses(container);
2✔
51
        for (auto& move : moves) {
4✔
52
            auto& access_node = dynamic_cast<data_flow::AccessNode&>(*move->element());
2✔
53
            auto& dataflow = *move->parent();
2✔
54
            auto& move_edge = *dataflow.in_edges(access_node).begin();
2✔
55

56
            // Criterion: Must be a reference memlet
57
            if (move_edge.type() != data_flow::MemletType::Reference) {
2✔
58
                continue;
1✔
59
            }
60

61
            // Retrieve underlying container
62
            auto& viewed_node = dynamic_cast<const data_flow::AccessNode&>(move_edge.src());
1✔
63
            auto& viewed_container = viewed_node.data();
1✔
64

65
            // Criterion: Must not be raw memory address
66
            if (helpers::is_number(viewed_container) || symbolic::is_nullptr(symbolic::symbol(viewed_container))) {
1✔
67
                continue;
×
68
            }
69

70
            // Criterion: Must not be reinterpret cast
71
            auto& move_subset = move_edge.subset();
1✔
72
            auto& viewed_type = types::infer_type(sdfg, sdfg.type(viewed_container), move_subset);
1✔
73
            types::Pointer final_type(viewed_type);
1✔
74
            if (type != final_type) {
1✔
75
                continue;
×
76
            }
77

78
            // Replace all uses of the view by the pointer
79
            for (auto& user : uses) {
4✔
80
                // Criterion: Must be dominated by the move
81
                if (!users.dominates(*move, *user)) {
3✔
82
                    continue;
1✔
83
                }
84
                // Criterion: Pointer and view are constant
85
                auto uses_between = users.all_uses_between(*move, *user);
2✔
86
                bool unsafe = false;
2✔
87
                for (auto& use : uses_between) {
3✔
88
                    if (use->use() != analysis::Use::MOVE) {
1✔
89
                        continue;
1✔
90
                    }
91
                    // Pointer is not constant
92
                    if (use->container() == viewed_container) {
×
93
                        unsafe = true;
×
94
                        break;
×
95
                    }
96
                    // View is reassigned
97
                    if (use->container() == container) {
×
98
                        unsafe = true;
×
99
                        break;
×
100
                    }
101
                }
102
                if (unsafe) {
2✔
103
                    continue;
×
104
                }
105

106
                // Can only replace access nodes
107
                if (!dynamic_cast<data_flow::AccessNode*>(user->element())) {
2✔
108
                    continue;
×
109
                }
110
                auto& use_node = static_cast<data_flow::AccessNode&>(*user->element());
2✔
111

112
                auto use_graph = user->parent();
2✔
113

114
                // Criterion: Must not be a dereference memlet
115
                bool deref = false;
2✔
116
                for (auto& oedge : use_graph->out_edges(use_node)) {
3✔
117
                    if (oedge.type() == data_flow::MemletType::Dereference_Src) {
1✔
NEW
118
                        deref = true;
×
NEW
119
                        break;
×
120
                    }
121
                }
122
                for (auto& iedge : use_graph->in_edges(use_node)) {
3✔
123
                    if (iedge.type() == data_flow::MemletType::Dereference_Dst) {
1✔
NEW
124
                        deref = true;
×
NEW
125
                        break;
×
126
                    }
127
                }
128
                if (deref) {
2✔
NEW
129
                    continue;
×
130
                }
131

132
                // Step 1: Replace container
133
                use_node.data() = viewed_container;
2✔
134

135
                // Step 2: Update edges
136
                for (auto& oedge : use_graph->out_edges(use_node)) {
3✔
137
                    // Compute new subset
138
                    data_flow::Subset new_subset;
1✔
139

140
                    // Add leading dimensions from move
141
                    if (move_edge.src_conn() == "void") {
1✔
142
                        for (size_t i = 0; i < move_subset.size(); i++) {
2✔
143
                            new_subset.push_back(move_subset[i]);
1✔
144
                        }
1✔
145
                    }
1✔
146

147
                    auto old_subset = oedge.subset();
1✔
148

149
                    // Handle first trailing dimensions
150
                    if (new_subset.empty()) {
1✔
151
                        auto& trail_dim = old_subset.front();
×
152
                        if (!symbolic::eq(trail_dim, symbolic::zero())) {
×
153
                            throw std::runtime_error("View propagation not implemented for non-void source connection");
×
154
                        }
155
                        old_subset.erase(old_subset.begin());
×
156
                    } else {
×
157
                        auto& trail_dim = old_subset.front();
1✔
158
                        auto& current_dim = new_subset.back();
1✔
159
                        auto new_dim = symbolic::add(current_dim, trail_dim);
1✔
160
                        new_subset.back() = new_dim;
1✔
161
                        old_subset.erase(old_subset.begin());
1✔
162
                    }
1✔
163

164
                    // Add remaining trailing dimensions
165
                    for (auto& dim : old_subset) {
1✔
166
                        new_subset.push_back(dim);
×
167
                    }
168
                    oedge.set_subset(new_subset);
1✔
169
                }
1✔
170
                for (auto& iedge : use_graph->in_edges(use_node)) {
3✔
171
                    // Compute new subset
172
                    data_flow::Subset new_subset;
1✔
173

174
                    // Add leading dimensions from move
175
                    if (move_edge.src_conn() == "void") {
1✔
176
                        for (size_t i = 0; i < move_subset.size(); i++) {
2✔
177
                            new_subset.push_back(move_subset[i]);
1✔
178
                        }
1✔
179
                    }
1✔
180

181
                    auto old_subset = iedge.subset();
1✔
182

183
                    // Handle first trailing dimensions
184
                    if (new_subset.empty()) {
1✔
185
                        auto& trail_dim = old_subset.front();
×
186
                        if (!symbolic::eq(trail_dim, symbolic::zero())) {
×
187
                            throw std::runtime_error("View propagation not implemented for non-void source connection");
×
188
                        }
189
                        old_subset.erase(old_subset.begin());
×
190
                    } else {
×
191
                        auto& trail_dim = old_subset.front();
1✔
192
                        auto& current_dim = new_subset.back();
1✔
193
                        auto new_dim = symbolic::add(current_dim, trail_dim);
1✔
194
                        new_subset.back() = new_dim;
1✔
195
                        old_subset.erase(old_subset.begin());
1✔
196
                    }
1✔
197

198
                    // Add remaining trailing dimensions
199
                    for (auto& dim : old_subset) {
1✔
200
                        new_subset.push_back(dim);
×
201
                    }
202
                    iedge.set_subset(new_subset);
1✔
203
                }
1✔
204

205
                applied = true;
2✔
206
                reduced.insert(viewed_container);
2✔
207
            }
2✔
208
        }
1✔
209
    }
5✔
210

211
    return applied;
3✔
212
};
3✔
213

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

© 2026 Coveralls, Inc