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

daisytuner / sdfglib / 20770413849

06 Jan 2026 10:50PM UTC coverage: 62.168% (+21.4%) from 40.764%
20770413849

push

github

web-flow
Merge pull request #433 from daisytuner/clang-coverage

updates clang coverage flags

14988 of 24109 relevant lines covered (62.17%)

88.57 hits per line

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

40.07
/src/analysis/reference_analysis.cpp
1
#include "sdfg/analysis/reference_analysis.h"
2

3
#include <cassert>
4
#include <string>
5
#include <unordered_map>
6
#include <unordered_set>
7
#include <vector>
8

9
#include "sdfg/analysis/analysis.h"
10
#include "sdfg/analysis/loop_analysis.h"
11
#include "sdfg/structured_sdfg.h"
12
#include "sdfg/symbolic/maps.h"
13
#include "sdfg/symbolic/sets.h"
14

15
namespace sdfg {
16
namespace analysis {
17

18
ReferenceAnalysis::ReferenceAnalysis(StructuredSDFG& sdfg)
19
    : Analysis(sdfg), node_(sdfg.root()) {
13✔
20

21
      };
13✔
22

23
void ReferenceAnalysis::run(analysis::AnalysisManager& analysis_manager) {
13✔
24
    results_.clear();
13✔
25

26
    std::unordered_set<User*> undefined;
13✔
27
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions;
13✔
28
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions;
13✔
29

30
    auto& users = analysis_manager.get<Users>();
13✔
31
    visit_sequence(users, node_, undefined, open_definitions, closed_definitions);
13✔
32

33
    for (auto& entry : open_definitions) {
17✔
34
        closed_definitions.insert(entry);
17✔
35
    }
17✔
36

37
    for (auto& entry : closed_definitions) {
18✔
38
        if (results_.find(entry.first->container()) == results_.end()) {
18✔
39
            results_.insert({entry.first->container(), {}});
17✔
40
        }
17✔
41
        results_.at(entry.first->container()).insert(entry);
18✔
42
    }
18✔
43
};
13✔
44

45
/****** Visitor API ******/
46

47
void ReferenceAnalysis::visit_block(
48
    analysis::Users& users,
49
    structured_control_flow::Block& block,
50
    std::unordered_set<User*>& undefined,
51
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
52
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
53
) {
26✔
54
    auto& dataflow = block.dataflow();
26✔
55

56
    for (auto node : dataflow.topological_sort()) {
57✔
57
        if (!dynamic_cast<data_flow::AccessNode*>(node) || dynamic_cast<data_flow::ConstantNode*>(node)) {
57✔
58
            continue;
5✔
59
        }
5✔
60
        auto access_node = static_cast<data_flow::AccessNode*>(node);
52✔
61
        if (sdfg_.type(access_node->data()).type_id() != types::TypeID::Pointer) {
52✔
62
            continue;
×
63
        }
×
64

65
        // New definition (Move)
66
        if (users.has_user(access_node->data(), access_node, Use::MOVE)) {
52✔
67
            auto move_user = users.get_user(access_node->data(), access_node, Use::MOVE);
18✔
68

69
            // Close all definitions that we dominate
70
            std::unordered_map<User*, std::unordered_set<User*>> to_close;
18✔
71
            for (auto& user : open_definitions) {
18✔
72
                if (user.first->container() != access_node->data()) {
5✔
73
                    continue;
4✔
74
                }
4✔
75
                to_close.insert(user);
1✔
76
            }
1✔
77
            for (auto& user : to_close) {
18✔
78
                open_definitions.erase(user.first);
1✔
79
                closed_definitions.insert(user);
1✔
80
            }
1✔
81

82
            // Start new definition
83
            open_definitions.insert({move_user, {}});
18✔
84
        }
18✔
85

86
        User* read_user = nullptr;
52✔
87
        if (users.has_user(access_node->data(), access_node, Use::READ)) {
52✔
88
            read_user = users.get_user(access_node->data(), access_node, Use::READ);
6✔
89
        }
6✔
90
        User* write_user = nullptr;
52✔
91
        if (users.has_user(access_node->data(), access_node, Use::WRITE)) {
52✔
92
            write_user = users.get_user(access_node->data(), access_node, Use::WRITE);
8✔
93
        }
8✔
94
        User* view_user = nullptr;
52✔
95
        if (users.has_user(access_node->data(), access_node, Use::VIEW)) {
52✔
96
            view_user = users.get_user(access_node->data(), access_node, Use::VIEW);
20✔
97
        }
20✔
98
        if (!read_user && !write_user && !view_user) {
52✔
99
            continue;
18✔
100
        }
18✔
101

102
        // Add uses to open definitions
103
        bool found = false;
34✔
104
        for (auto& move : open_definitions) {
34✔
105
            if (move.first->container() != access_node->data()) {
21✔
106
                continue;
4✔
107
            }
4✔
108

109
            found = true;
17✔
110
            if (read_user) {
17✔
111
                move.second.insert(read_user);
6✔
112
            }
6✔
113
            if (write_user) {
17✔
114
                move.second.insert(write_user);
8✔
115
            }
8✔
116
            if (view_user) {
17✔
117
                move.second.insert(view_user);
3✔
118
            }
3✔
119
        }
17✔
120

121
        if (!found) {
34✔
122
            if (read_user) {
17✔
123
                undefined.insert(read_user);
×
124
            }
×
125
            if (write_user) {
17✔
126
                undefined.insert(write_user);
×
127
            }
×
128
            if (view_user) {
17✔
129
                undefined.insert(view_user);
17✔
130
            }
17✔
131
        }
17✔
132
    }
34✔
133
}
26✔
134

135
void ReferenceAnalysis::visit_if_else(
136
    analysis::Users& users,
137
    structured_control_flow::IfElse& if_else,
138
    std::unordered_set<User*>& undefined,
139
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
140
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
141
) {
×
142
    // Read Conditions
143
    for (size_t i = 0; i < if_else.size(); i++) {
×
144
        auto child = if_else.at(i).second;
×
145
        for (auto sym : symbolic::atoms(child)) {
×
146
            if (!sdfg_.exists(sym->get_name())) {
×
147
                continue;
×
148
            }
×
149
            if (sdfg_.type(sym->get_name()).type_id() != types::TypeID::Pointer) {
×
150
                continue;
×
151
            }
×
152

153
            auto current_user = users.get_user(sym->get_name(), &if_else, Use::READ);
×
154
            bool found = false;
×
155
            for (auto& entry : open_definitions) {
×
156
                if (entry.first->container() == sym->get_name()) {
×
157
                    entry.second.insert(current_user);
×
158
                    found = true;
×
159
                }
×
160
            }
×
161
            if (!found) {
×
162
                undefined.insert(current_user);
×
163
            }
×
164
        }
×
165
    }
×
166

167
    std::vector<std::unordered_set<User*>> undefined_branches(if_else.size());
×
168
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> open_definitions_branches(if_else.size());
×
169
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> closed_definitions_branches(if_else.size());
×
170
    for (size_t i = 0; i < if_else.size(); i++) {
×
171
        auto& child = if_else.at(i).first;
×
172
        visit_sequence(
×
173
            users, child, undefined_branches.at(i), open_definitions_branches.at(i), closed_definitions_branches.at(i)
×
174
        );
×
175
    }
×
176

177
    for (auto& closed_definition_branch : closed_definitions_branches) {
×
178
        for (auto& entry : closed_definition_branch) {
×
179
            closed_definitions.insert(entry);
×
180
        }
×
181
    }
×
182

183
    for (size_t i = 0; i < if_else.size(); i++) {
×
184
        for (auto& entry : undefined_branches.at(i)) {
×
185
            bool found = false;
×
186
            for (auto& entry2 : open_definitions) {
×
187
                if (entry2.first->container() == entry->container()) {
×
188
                    entry2.second.insert(entry);
×
189
                    found = true;
×
190
                }
×
191
            }
×
192
            if (!found) {
×
193
                undefined.insert(entry);
×
194
            }
×
195
        }
×
196
    }
×
197

198
    for (auto& branch : open_definitions_branches) {
×
199
        for (auto& entry : branch) {
×
200
            open_definitions.insert(entry);
×
201
        }
×
202
    }
×
203
}
×
204

205
void ReferenceAnalysis::visit_for(
206
    analysis::Users& users,
207
    structured_control_flow::StructuredLoop& for_loop,
208
    std::unordered_set<User*>& undefined,
209
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
210
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
211
) {
×
212
    // Visit body
213
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_body;
×
214
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_body;
×
215
    std::unordered_set<User*> undefined_body;
×
216
    visit_sequence(users, for_loop.root(), undefined_body, open_definitions_body, closed_definitions_body);
×
217

218
    for (auto& entry : closed_definitions_body) {
×
219
        closed_definitions.insert(entry);
×
220
    }
×
221

222
    for (auto& open : undefined_body) {
×
223
        // Loop-carried dependencies
224
        for (auto& entry : open_definitions_body) {
×
225
            if (entry.first->container() == open->container()) {
×
226
                entry.second.insert(open);
×
227
            }
×
228
        }
×
229

230
        bool found = false;
×
231
        for (auto entry : open_definitions) {
×
232
            if (entry.first->container() != open->container()) {
×
233
                continue;
×
234
            }
×
235

236
            entry.second.insert(open);
×
237
        }
×
238

239
        if (!found) {
×
240
            undefined.insert(open);
×
241
        }
×
242
    }
×
243

244
    for (auto& entry : open_definitions_body) {
×
245
        open_definitions.insert(entry);
×
246
    }
×
247
}
×
248

249
void ReferenceAnalysis::visit_while(
250
    analysis::Users& users,
251
    structured_control_flow::While& while_loop,
252
    std::unordered_set<User*>& undefined,
253
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
254
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
255
) {
×
256
    // Visit body
257
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_body;
×
258
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_body;
×
259
    std::unordered_set<User*> undefined_body;
×
260
    visit_sequence(users, while_loop.root(), undefined_body, open_definitions_body, closed_definitions_body);
×
261

262
    for (auto& entry : closed_definitions_body) {
×
263
        closed_definitions.insert(entry);
×
264
    }
×
265

266
    for (auto& open : undefined_body) {
×
267
        // Loop-carried dependencies
268
        for (auto& entry : open_definitions_body) {
×
269
            if (entry.first->container() == open->container()) {
×
270
                entry.second.insert(open);
×
271
            }
×
272
        }
×
273

274
        bool found = false;
×
275
        for (auto entry : open_definitions) {
×
276
            if (entry.first->container() != open->container()) {
×
277
                continue;
×
278
            }
×
279

280
            entry.second.insert(open);
×
281
        }
×
282

283
        if (!found) {
×
284
            undefined.insert(open);
×
285
        }
×
286
    }
×
287

288
    for (auto& entry : open_definitions_body) {
×
289
        open_definitions.insert(entry);
×
290
    }
×
291
}
×
292

293
void ReferenceAnalysis::visit_return(
294
    analysis::Users& users,
295
    structured_control_flow::Return& return_statement,
296
    std::unordered_set<User*>& undefined,
297
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
298
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
299
) {
×
300
    for (auto& entry : open_definitions) {
×
301
        closed_definitions.insert(entry);
×
302
    }
×
303
    open_definitions.clear();
×
304
}
×
305

306
void ReferenceAnalysis::visit_sequence(
307
    analysis::Users& users,
308
    structured_control_flow::Sequence& sequence,
309
    std::unordered_set<User*>& undefined,
310
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
311
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
312
) {
13✔
313
    for (size_t i = 0; i < sequence.size(); i++) {
39✔
314
        auto child = sequence.at(i);
26✔
315
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
26✔
316
            visit_block(users, *block, undefined, open_definitions, closed_definitions);
26✔
317
        } else if (auto for_loop = dynamic_cast<structured_control_flow::StructuredLoop*>(&child.first)) {
26✔
318
            visit_for(users, *for_loop, undefined, open_definitions, closed_definitions);
×
319
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
×
320
            visit_if_else(users, *if_else, undefined, open_definitions, closed_definitions);
×
321
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
×
322
            visit_while(users, *while_loop, undefined, open_definitions, closed_definitions);
×
323
        } else if (auto return_statement = dynamic_cast<structured_control_flow::Return*>(&child.first)) {
×
324
            visit_return(users, *return_statement, undefined, open_definitions, closed_definitions);
×
325
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
×
326
            visit_sequence(users, *sequence, undefined, open_definitions, closed_definitions);
×
327
        }
×
328
    }
26✔
329
}
13✔
330

331
std::unordered_set<User*> ReferenceAnalysis::defines(User& move) {
×
332
    assert(move.use() == Use::MOVE);
×
333
    if (results_.find(move.container()) == results_.end()) {
×
334
        return {};
×
335
    }
×
336
    auto& raws = results_.at(move.container());
×
337
    assert(raws.find(&move) != raws.end());
×
338

339
    auto& users_for_move = raws.at(&move);
×
340

341
    std::unordered_set<User*> users;
×
342
    for (auto& entry : users_for_move) {
×
343
        users.insert(entry);
×
344
    }
×
345

346
    return users;
×
347
};
×
348

349
std::unordered_map<User*, std::unordered_set<User*>> ReferenceAnalysis::definitions(const std::string& container) {
16✔
350
    if (results_.find(container) == results_.end()) {
16✔
351
        return {};
2✔
352
    }
2✔
353
    return results_.at(container);
14✔
354
};
16✔
355

356
std::unordered_set<User*> ReferenceAnalysis::defined_by(User& user) {
×
357
    auto definitions = this->definitions(user.container());
×
358

359
    std::unordered_set<User*> moves;
×
360
    for (auto& entry : definitions) {
×
361
        for (auto& r : entry.second) {
×
362
            if (&user == r) {
×
363
                moves.insert(entry.first);
×
364
            }
×
365
        }
×
366
    }
×
367
    return moves;
×
368
};
×
369

370
std::unordered_map<User*, std::unordered_set<User*>> ReferenceAnalysis::defined_by(const std::string& container) {
16✔
371
    auto moves = this->definitions(container);
16✔
372

373
    std::unordered_map<User*, std::unordered_set<User*>> uses_to_move_map;
16✔
374
    for (auto& entry : moves) {
16✔
375
        for (auto& use : entry.second) {
17✔
376
            if (uses_to_move_map.find(use) == uses_to_move_map.end()) {
17✔
377
                uses_to_move_map[use] = {};
17✔
378
            }
17✔
379
            uses_to_move_map[use].insert(entry.first);
17✔
380
        }
17✔
381
    }
15✔
382
    return uses_to_move_map;
16✔
383
};
16✔
384

385
} // namespace analysis
386
} // 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