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

daisytuner / sdfglib / 17698210449

13 Sep 2025 03:02PM UTC coverage: 60.505% (+1.2%) from 59.335%
17698210449

Pull #219

github

web-flow
Merge 7e6ec5a53 into 6c1992b40
Pull Request #219: stdlib Library Nodes and ConstantNodes

640 of 1885 new or added lines in 107 files covered. (33.95%)

107 existing lines in 40 files now uncovered.

9443 of 15607 relevant lines covered (60.5%)

106.96 hits per line

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

76.69
/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()
5✔
10
    : Pass() {
5✔
11

12
      };
5✔
13

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

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

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

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

32
        // By definition, a view is a pointer
33
        auto& type = sdfg.type(container);
4✔
34
        if (type.type_id() != types::TypeID::Pointer) {
4✔
35
            continue;
×
36
        }
37

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

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

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

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

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

65
            // Criterion: Must not be constant data
66
            if (helpers::is_number(viewed_container) || symbolic::is_nullptr(symbolic::symbol(viewed_container))) {
2✔
67
                continue;
×
68
            }
69

70
            // Criterion: Must not be address of
71
            auto& move_subset = move_edge.subset();
2✔
72
            if (move_subset.empty()) {
2✔
73
                continue;
×
74
            }
75

76
            // Replace all uses of the view by the pointer
77
            for (auto& user : uses) {
8✔
78
                // Criterion: Must be an access node
79
                if (!dynamic_cast<data_flow::AccessNode*>(user->element())) {
6✔
80
                    continue;
×
81
                }
82

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

109
                auto& use_node = static_cast<data_flow::AccessNode&>(*user->element());
4✔
110

111
                // Criterion: Must be a typed-pointer at this point, no empty subset / constant data
112
                auto& base_type = move_edge.base_type();
4✔
113
                auto& pointer_type = dynamic_cast<const types::Pointer&>(base_type);
4✔
114

115
                // Criterion: Must strictly propagate into computational memlets
116
                // Criterion: Types must match
117
                auto use_graph = user->parent();
4✔
118

119
                auto& result_base_type = types::infer_type(builder.subject(), move_edge.base_type(), move_subset);
4✔
120
                sdfg::types::Pointer result_type(static_cast<const types::IType&>(result_base_type));
4✔
121

122
                bool safe = true;
4✔
123
                for (auto& oedge : use_graph->out_edges(use_node)) {
6✔
124
                    if (oedge.subset().empty()) {
2✔
NEW
125
                        safe = false;
×
NEW
126
                        break;
×
127
                    }
128
                    if (oedge.type() != data_flow::MemletType::Computational) {
2✔
129
                        safe = false;
×
130
                        break;
×
131
                    }
132
                    if (result_base_type.type_id() != types::TypeID::Pointer && oedge.base_type() != result_type) {
2✔
133
                        safe = false;
×
134
                        break;
×
135
                    }
136
                }
137
                if (!safe) {
4✔
138
                    continue;
×
139
                }
140
                for (auto& iedge : use_graph->in_edges(use_node)) {
6✔
141
                    if (iedge.subset().empty()) {
2✔
NEW
142
                        safe = false;
×
NEW
143
                        break;
×
144
                    }
145
                    if (iedge.type() != data_flow::MemletType::Computational) {
2✔
146
                        safe = false;
×
147
                        break;
×
148
                    }
149
                    if (result_base_type.type_id() != types::TypeID::Pointer && iedge.base_type() != result_type) {
2✔
150
                        safe = false;
×
151
                        break;
×
152
                    }
153
                }
154
                if (!safe) {
4✔
155
                    continue;
×
156
                }
157

158
                // Propagate pointer type
159

160
                // Step 1: Replace container
161
                use_node.data() = viewed_container;
4✔
162

163
                // Step 2: Update edges
164
                for (auto& oedge : use_graph->out_edges(use_node)) {
6✔
165
                    // Compute new subset
166
                    data_flow::Subset new_subset;
2✔
167
                    for (auto dim : move_subset) {
5✔
168
                        new_subset.push_back(dim);
3✔
169
                    }
3✔
170

171
                    auto old_subset = oedge.subset();
2✔
172

173
                    // Handle first trailing dimensions
174
                    auto& trail_dim = old_subset.front();
2✔
175
                    auto& current_dim = new_subset.back();
2✔
176
                    auto new_dim = symbolic::add(current_dim, trail_dim);
2✔
177
                    new_subset.back() = new_dim;
2✔
178
                    old_subset.erase(old_subset.begin());
2✔
179

180
                    // Add remaining trailing dimensions
181
                    for (auto dim : old_subset) {
2✔
182
                        new_subset.push_back(dim);
×
183
                    }
×
184

185
                    // Build new type
186
                    if (move_subset.size() == 1) {
2✔
187
                        oedge.set_subset(new_subset);
1✔
188
                    } else {
1✔
189
                        // Case 2: multi-dimensional subset
190
                        oedge.set_subset(new_subset);
1✔
191
                        oedge.set_base_type(move_edge.base_type());
1✔
192
                    }
193
                }
2✔
194

195
                for (auto& iedge : use_graph->in_edges(use_node)) {
6✔
196
                    // Compute new subset
197
                    data_flow::Subset new_subset;
2✔
198
                    for (auto dim : move_subset) {
5✔
199
                        new_subset.push_back(dim);
3✔
200
                    }
3✔
201

202
                    auto old_subset = iedge.subset();
2✔
203

204
                    // Handle first trailing dimensions
205
                    auto& trail_dim = old_subset.front();
2✔
206
                    auto& current_dim = new_subset.back();
2✔
207
                    auto new_dim = symbolic::add(current_dim, trail_dim);
2✔
208
                    new_subset.back() = new_dim;
2✔
209
                    old_subset.erase(old_subset.begin());
2✔
210

211
                    // Add remaining trailing dimensions
212
                    for (auto dim : old_subset) {
2✔
213
                        new_subset.push_back(dim);
×
214
                    }
×
215

216
                    // Case 1: 1D subset, "original pointer is shifted"
217
                    if (move_subset.size() == 1) {
2✔
218
                        iedge.set_subset(new_subset);
1✔
219
                    } else {
1✔
220
                        // Case 2: multi-dimensional subset
221
                        iedge.set_subset(new_subset);
1✔
222
                        iedge.set_base_type(move_edge.base_type());
1✔
223
                    }
224
                }
2✔
225

226
                applied = true;
4✔
227
                reduced.insert(viewed_container);
4✔
228
            }
4✔
229
        }
2✔
230
    }
4✔
231

232
    return applied;
4✔
233
};
4✔
234

235
} // namespace passes
236
} // 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