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

daisytuner / sdfglib / 16779684622

06 Aug 2025 02:21PM UTC coverage: 64.3% (-1.0%) from 65.266%
16779684622

push

github

web-flow
Merge pull request #172 from daisytuner/opaque-pointers

Opaque pointers, typed memlets, untyped tasklet connectors

330 of 462 new or added lines in 38 files covered. (71.43%)

382 existing lines in 30 files now uncovered.

8865 of 13787 relevant lines covered (64.3%)

116.73 hits per line

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

77.17
/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_external(container)) {
6✔
29
            continue;
×
30
        }
31

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

38
        // Criterion: Must have at least one move
39
        auto moves = users.moves(container);
6✔
40
        if (moves.empty()) {
6✔
41
            continue;
3✔
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 raw memory address
66
            if (helpers::is_number(viewed_container) || symbolic::is_nullptr(symbolic::symbol(viewed_container))) {
2✔
67
                continue;
×
68
            }
69

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

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

110
                auto use_graph = user->parent();
4✔
111

112
                // Criterion: Must be a typed-pointer
113
                auto& base_type = move_edge.base_type();
4✔
114
                if (base_type.type_id() == types::TypeID::Pointer) {
4✔
115
                    auto& element_type = static_cast<const types::Pointer&>(base_type).pointee_type();
4✔
116
                    if (element_type.type_id() == types::TypeID::Scalar) {
4✔
117
                        if (element_type.primitive_type() == types::PrimitiveType::Int8) {
2✔
NEW
118
                            continue;
×
119
                        }
120
                    }
2✔
121
                }
4✔
122

123
                // Criterion: Must be a computational memlet
124
                bool computational = true;
4✔
125
                for (auto& oedge : use_graph->out_edges(use_node)) {
6✔
126
                    if (oedge.type() != data_flow::MemletType::Computational || oedge.has_range()) {
2✔
127
                        computational = false;
×
128
                        break;
×
129
                    }
130
                }
131
                if (!computational) {
4✔
132
                    continue;
×
133
                }
134
                for (auto& iedge : use_graph->in_edges(use_node)) {
6✔
135
                    if (iedge.type() != data_flow::MemletType::Computational || iedge.has_range()) {
2✔
136
                        computational = false;
×
137
                        break;
×
138
                    }
139
                }
140
                if (!computational) {
4✔
141
                    continue;
×
142
                }
143

144
                // Step 1: Replace container
145
                use_node.data() = viewed_container;
4✔
146

147
                // Step 2: Update edges
148
                for (auto& oedge : use_graph->out_edges(use_node)) {
6✔
149
                    // Compute new subset
150
                    data_flow::Subset new_subset;
2✔
151
                    for (auto dim : move_subset) {
5✔
152
                        new_subset.push_back(dim);
3✔
153
                    }
3✔
154

155
                    auto old_subset = oedge.subset();
2✔
156

157
                    // Handle first trailing dimensions
158
                    auto& trail_dim = old_subset.front();
2✔
159
                    auto& current_dim = new_subset.back();
2✔
160
                    auto new_dim = symbolic::add(current_dim, trail_dim);
2✔
161
                    new_subset.back() = new_dim;
2✔
162
                    old_subset.erase(old_subset.begin());
2✔
163

164
                    // Add remaining trailing dimensions
165
                    for (auto dim : old_subset) {
2✔
166
                        new_subset.push_back(dim);
×
167
                    }
×
168

169
                    // Pad with zeros until scalar type
170
                    auto inferred_type = &types::infer_type(builder.subject(), move_edge.base_type(), new_subset);
2✔
171
                    while (inferred_type->type_id() != types::TypeID::Scalar) {
2✔
NEW
172
                        new_subset.push_back(symbolic::zero());
×
NEW
173
                        inferred_type = &types::infer_type(builder.subject(), move_edge.base_type(), new_subset);
×
174
                    }
175

176
                    oedge.set_subset(new_subset);
2✔
177
                    oedge.set_base_type(move_edge.base_type());
2✔
178
                }
2✔
179
                for (auto& iedge : use_graph->in_edges(use_node)) {
6✔
180
                    // Compute new subset
181
                    data_flow::Subset new_subset;
2✔
182
                    for (auto dim : move_subset) {
5✔
183
                        new_subset.push_back(dim);
3✔
184
                    }
3✔
185

186
                    auto old_subset = iedge.subset();
2✔
187

188
                    // Handle first trailing dimensions
189
                    auto& trail_dim = old_subset.front();
2✔
190
                    auto& current_dim = new_subset.back();
2✔
191
                    auto new_dim = symbolic::add(current_dim, trail_dim);
2✔
192
                    new_subset.back() = new_dim;
2✔
193
                    old_subset.erase(old_subset.begin());
2✔
194

195
                    // Add remaining trailing dimensions
196
                    for (auto dim : old_subset) {
2✔
197
                        new_subset.push_back(dim);
×
198
                    }
×
199

200
                    // Pad with zeros until scalar type
201
                    auto inferred_type = &types::infer_type(builder.subject(), move_edge.base_type(), new_subset);
2✔
202
                    while (inferred_type->type_id() != types::TypeID::Scalar) {
2✔
NEW
203
                        new_subset.push_back(symbolic::zero());
×
NEW
204
                        inferred_type = &types::infer_type(builder.subject(), move_edge.base_type(), new_subset);
×
205
                    }
206

207
                    iedge.set_subset(new_subset);
2✔
208
                    iedge.set_base_type(move_edge.base_type());
2✔
209
                }
2✔
210

211
                applied = true;
4✔
212
                reduced.insert(viewed_container);
4✔
213
            }
4✔
214
        }
2✔
215
    }
6✔
216

217
    return applied;
4✔
218
};
4✔
219

220
} // namespace passes
221
} // 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