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

daisytuner / docc / 22851518064

09 Mar 2026 11:34AM UTC coverage: 64.621% (+0.2%) from 64.441%
22851518064

push

github

web-flow
Merge pull request #562 from daisytuner/map-fusion-multi-dims

Extends MapFusion with support for multi-dimensional loop nests

174 of 215 new or added lines in 3 files covered. (80.93%)

13 existing lines in 4 files now uncovered.

24651 of 38147 relevant lines covered (64.62%)

376.52 hits per line

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

50.0
/sdfg/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()) {
14✔
20

21
      };
14✔
22

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

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

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

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

37
    for (auto& entry : closed_definitions) {
19✔
38
        if (results_.find(entry.first->container()) == results_.end()) {
19✔
39
            results_.insert({entry.first->container(), {}});
18✔
40
        }
18✔
41
        results_.at(entry.first->container()).insert(entry);
19✔
42
    }
19✔
43
};
14✔
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
) {
28✔
54
    auto& dataflow = block.dataflow();
28✔
55

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

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

69
            // Close all definitions that we dominate
70
            std::unordered_map<User*, std::unordered_set<User*>> to_close;
19✔
71
            for (auto& user : open_definitions) {
19✔
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) {
19✔
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, {}});
19✔
84
        }
19✔
85

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

102
        // Add uses to open definitions
103
        bool found = false;
37✔
104
        for (auto& move : open_definitions) {
37✔
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) {
37✔
122
            if (read_user) {
20✔
123
                undefined.insert(read_user);
1✔
124
            }
1✔
125
            if (write_user) {
20✔
126
                undefined.insert(write_user);
1✔
127
            }
1✔
128
            if (view_user) {
20✔
129
                undefined.insert(view_user);
18✔
130
            }
18✔
131
        }
20✔
132
    }
37✔
133
}
28✔
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
) {
1✔
212
    // Visit body
213
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_body;
1✔
214
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_body;
1✔
215
    std::unordered_set<User*> undefined_body;
1✔
216
    visit_sequence(users, for_loop.root(), undefined_body, open_definitions_body, closed_definitions_body);
1✔
217

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

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

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

236
            entry.second.insert(open);
1✔
237
            found = true;
1✔
238
        }
1✔
239

240
        if (!found) {
2✔
241
            undefined.insert(open);
1✔
242
        }
1✔
243
    }
2✔
244

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

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

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

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

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

281
            entry.second.insert(open);
×
NEW
282
            found = true;
×
UNCOV
283
        }
×
284

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

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

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

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

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

341
    auto& users_for_move = raws.at(&move);
×
342

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

348
    return users;
×
349
};
×
350

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

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

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

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

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

387
} // namespace analysis
388
} // 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