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

daisytuner / sdfglib / 16441825485

22 Jul 2025 10:35AM UTC coverage: 66.003% (+0.9%) from 65.094%
16441825485

Pull #153

github

web-flow
Merge f4c3684cd into abe57c083
Pull Request #153: Introduces different memlet types for computation, references and dereferencing

243 of 352 new or added lines in 30 files covered. (69.03%)

70 existing lines in 7 files now uncovered.

8321 of 12607 relevant lines covered (66.0%)

133.97 hits per line

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

77.88
/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 (type.type_id() != types::TypeID::Pointer) {
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 = static_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 = static_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
            if (move_subset.empty()) {
1✔
NEW
73
                continue;
×
74
            }
75
            auto& viewed_type = types::infer_type(sdfg, sdfg.type(viewed_container), move_subset);
1✔
76
            types::Pointer final_type(viewed_type);
1✔
77
            if (type != final_type) {
1✔
78
                continue;
×
79
            }
80

81
            // Replace all uses of the view by the pointer
82
            for (auto& user : uses) {
4✔
83
                // Criterion: Must be dominated by the move
84
                if (!users.dominates(*move, *user)) {
3✔
85
                    continue;
1✔
86
                }
87
                // Criterion: Pointer and view are constant
88
                auto uses_between = users.all_uses_between(*move, *user);
2✔
89
                bool unsafe = false;
2✔
90
                for (auto& use : uses_between) {
3✔
91
                    if (use->use() != analysis::Use::MOVE) {
1✔
92
                        continue;
1✔
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) {
2✔
106
                    continue;
×
107
                }
108

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

115
                auto use_graph = user->parent();
2✔
116

117
                // Criterion: Must be a computational memlet
118
                bool computational = true;
2✔
119
                for (auto& oedge : use_graph->out_edges(use_node)) {
3✔
120
                    if (oedge.type() != data_flow::MemletType::Computational) {
1✔
NEW
121
                        computational = false;
×
NEW
122
                        break;
×
123
                    }
124
                }
125
                if (!computational) {
2✔
NEW
126
                    continue;
×
127
                }
128
                for (auto& iedge : use_graph->in_edges(use_node)) {
3✔
129
                    if (iedge.type() != data_flow::MemletType::Computational) {
1✔
NEW
130
                        computational = false;
×
NEW
131
                        break;
×
132
                    }
133
                }
134
                if (!computational) {
2✔
NEW
135
                    continue;
×
136
                }
137

138
                // Step 1: Replace container
139
                use_node.data() = viewed_container;
2✔
140

141
                // Step 2: Update edges
142
                for (auto& oedge : use_graph->out_edges(use_node)) {
3✔
143
                    // Compute new subset
144
                    data_flow::Subset new_subset;
1✔
145
                    for (auto dim : move_subset) {
2✔
146
                        new_subset.push_back(dim);
1✔
147
                    }
1✔
148

149
                    auto old_subset = oedge.subset();
1✔
150

151
                    // Handle first trailing dimensions
152
                    auto& trail_dim = old_subset.front();
1✔
153
                    auto& current_dim = new_subset.back();
1✔
154
                    auto new_dim = symbolic::add(current_dim, trail_dim);
1✔
155
                    new_subset.back() = new_dim;
1✔
156
                    old_subset.erase(old_subset.begin());
1✔
157

158
                    // Add remaining trailing dimensions
159
                    for (auto dim : old_subset) {
1✔
160
                        new_subset.push_back(dim);
×
161
                    }
×
162

163
                    oedge.set_subset(new_subset);
1✔
164
                }
1✔
165
                for (auto& iedge : use_graph->in_edges(use_node)) {
3✔
166
                    // Compute new subset
167
                    data_flow::Subset new_subset;
1✔
168
                    for (auto dim : move_subset) {
2✔
169
                        new_subset.push_back(dim);
1✔
170
                    }
1✔
171

172
                    auto old_subset = iedge.subset();
1✔
173

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

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

186
                    iedge.set_subset(new_subset);
1✔
187
                }
1✔
188

189
                applied = true;
2✔
190
                reduced.insert(viewed_container);
2✔
191
            }
2✔
192
        }
1✔
193
    }
5✔
194

195
    return applied;
3✔
196
};
3✔
197

198
} // namespace passes
199
} // 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