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

daisytuner / docc / 26812579723

02 Jun 2026 10:00AM UTC coverage: 61.302% (+0.3%) from 61.039%
26812579723

push

github

web-flow
Fixes for LLVM frontend (#731)

- Removed catching InvalidSDFGException in LLVM frontend
- Deactivated 8 LLVM test suite tests (6 SEGFAULT, 2 have wrong results)
- Fixed lifting for memcpy, memmove, and memset and added test cases for this
- Fixed bug in BlockSorting
- Fixed bug where the DataDependencyAnalysis tried to get the type of __daisy_nullptr
- DOT visualizer can, now, also handle return states in (unstructured) SDFGs
- Added unit test for DOT visualizer on (unstructured) SDFGs

10 of 15 new or added lines in 4 files covered. (66.67%)

1 existing line in 1 file now uncovered.

35679 of 58202 relevant lines covered (61.3%)

10989.89 hits per line

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

67.32
/opt/src/passes/offloading/code_motion/block_sorting.cpp
1
#include "sdfg/passes/offloading/code_motion/block_sorting.h"
2

3
#include <climits>
4
#include <string>
5
#include <unordered_set>
6
#include <utility>
7

8
#include "sdfg/analysis/analysis.h"
9
#include "sdfg/analysis/users.h"
10
#include "sdfg/builder/structured_sdfg_builder.h"
11
#include "sdfg/data_flow/access_node.h"
12
#include "sdfg/data_flow/data_flow_graph.h"
13
#include "sdfg/data_flow/library_node.h"
14
#include "sdfg/data_flow/library_nodes/stdlib/alloca.h"
15
#include "sdfg/data_flow/library_nodes/stdlib/calloc.h"
16
#include "sdfg/data_flow/library_nodes/stdlib/free.h"
17
#include "sdfg/data_flow/library_nodes/stdlib/malloc.h"
18
#include "sdfg/data_flow/library_nodes/stdlib/memset.h"
19
#include "sdfg/data_flow/memlet.h"
20
#include "sdfg/data_flow/tasklet.h"
21
#include "sdfg/element.h"
22
#include "sdfg/structured_control_flow/block.h"
23
#include "sdfg/structured_control_flow/control_flow_node.h"
24
#include "sdfg/structured_control_flow/if_else.h"
25
#include "sdfg/structured_control_flow/return.h"
26
#include "sdfg/structured_control_flow/sequence.h"
27
#include "sdfg/structured_control_flow/structured_loop.h"
28
#include "sdfg/structured_control_flow/while.h"
29
#include "sdfg/targets/offloading/data_offloading_node.h"
30

31
namespace sdfg {
32
namespace passes {
33

34
bool BlockSortingPass::bubble_up(
35
    builder::StructuredSDFGBuilder& builder,
36
    analysis::AnalysisManager& analysis_manager,
37
    structured_control_flow::Sequence& sequence,
38
    long long index
39
) {
5✔
40
    // Skip assignments
41
    auto current_child = sequence.at(index);
5✔
42
    if (!current_child.second.empty()) {
5✔
43
        return false;
×
44
    }
×
45
    auto next_child = sequence.at(index + 1);
5✔
46
    if (!next_child.second.empty()) {
5✔
47
        return false;
×
48
    }
×
49

50
    // Childs must be blocks
51
    auto* current_block = dynamic_cast<structured_control_flow::Block*>(&current_child.first);
5✔
52
    if (!current_block) {
5✔
53
        return false;
×
54
    }
×
55
    auto* next_block = dynamic_cast<structured_control_flow::Block*>(&next_child.first);
5✔
56
    if (!next_block) {
5✔
57
        return false;
×
58
    }
×
59

60
    // Check if current block has side-effects
61
    bool side_effect = false;
5✔
62
    for (auto* libnode : current_block->dataflow().library_nodes()) {
5✔
63
        if (this->is_libnode_side_effect_white_listed(libnode)) {
2✔
64
            continue;
2✔
65
        }
2✔
66
        if (libnode->side_effect()) {
×
67
            side_effect = true;
×
68
            break;
×
69
        }
×
70
    }
×
71
    if (side_effect) {
5✔
72
        return false;
×
73
    }
×
74

75
    // Check if happens-before relation allows swapping
76
    auto& users_analysis = analysis_manager.get<analysis::Users>();
5✔
77
    analysis::UsersView current_users(users_analysis, *current_block);
5✔
78
    analysis::UsersView next_users(users_analysis, *next_block);
5✔
79
    bool safe = true;
5✔
80
    for (auto user : next_users.uses()) {
7✔
81
        if (current_users.uses(user->container()).size() > 0) {
7✔
82
            safe = false;
×
83
            break;
×
84
        }
×
85
    }
7✔
86
    if (!safe) {
5✔
87
        return false;
×
88
    }
×
89

90
    // Check if libnode/reference can be bubbled up
91
    if (!this->can_be_bubbled_up(*next_block)) {
5✔
92
        return false;
×
93
    }
×
94

95
    // Compare priority and order
96
    auto [current_prio, current_order] = this->get_prio_and_order(current_block);
5✔
97
    auto [next_prio, next_order] = this->get_prio_and_order(next_block);
5✔
98
    if (current_prio > next_prio) {
5✔
99
        return false;
1✔
100
    }
1✔
101
    if (current_prio == next_prio && current_order <= next_order) {
4✔
102
        return false;
×
103
    }
×
104

105
    // Swap blocks
106
    builder.move_child(sequence, index + 1, sequence, index);
4✔
107
    analysis_manager.invalidate_all();
4✔
108

109
    return true;
4✔
110
}
4✔
111

112
bool BlockSortingPass::bubble_down(
113
    builder::StructuredSDFGBuilder& builder,
114
    analysis::AnalysisManager& analysis_manager,
115
    structured_control_flow::Sequence& sequence,
116
    long long index
117
) {
5✔
118
    // Skip assignments
119
    auto current_child = sequence.at(index);
5✔
120
    if (!current_child.second.empty()) {
5✔
121
        return false;
×
122
    }
×
123
    auto next_child = sequence.at(index - 1);
5✔
124
    if (!next_child.second.empty()) {
5✔
125
        return false;
×
126
    }
×
127

128
    // Childs must be blocks
129
    auto* current_block = dynamic_cast<structured_control_flow::Block*>(&current_child.first);
5✔
130
    if (!current_block) {
5✔
131
        return false;
×
132
    }
×
133
    auto* next_block = dynamic_cast<structured_control_flow::Block*>(&next_child.first);
5✔
134
    if (!next_block) {
5✔
135
        return false;
×
136
    }
×
137

138
    // Check if current block has side-effects
139
    bool side_effect = false;
5✔
140
    for (auto* libnode : current_block->dataflow().library_nodes()) {
5✔
141
        if (this->is_libnode_side_effect_white_listed(libnode)) {
1✔
142
            continue;
1✔
143
        }
1✔
144
        if (libnode->side_effect()) {
×
145
            side_effect = true;
×
146
            break;
×
147
        }
×
148
    }
×
149
    if (side_effect) {
5✔
150
        return false;
×
151
    }
×
152

153
    // Check if happens-before relation allows swapping
154
    auto& users_analysis = analysis_manager.get<analysis::Users>();
5✔
155
    analysis::UsersView current_users(users_analysis, *current_block);
5✔
156
    analysis::UsersView next_users(users_analysis, *next_block);
5✔
157
    bool safe = true;
5✔
158
    for (auto user : next_users.uses()) {
6✔
159
        if (current_users.uses(user->container()).size() > 0) {
6✔
160
            safe = false;
×
161
            break;
×
162
        }
×
163
    }
6✔
164
    if (!safe) {
5✔
165
        return false;
×
166
    }
×
167

168
    // Check if libnode can be bubbled down
169
    if (!this->can_be_bubbled_down(*next_block)) {
5✔
170
        return false;
4✔
171
    }
4✔
172

173
    // Compare priority and order
174
    auto [current_prio, current_order] = this->get_prio_and_order(current_block);
1✔
175
    auto [next_prio, next_order] = this->get_prio_and_order(next_block);
1✔
176
    if (current_prio > next_prio) {
1✔
177
        return false;
×
178
    }
×
179
    if (current_prio == next_prio && current_order <= next_order) {
1✔
180
        return false;
×
181
    }
×
182

183
    // Swap blocks
184
    builder.move_child(sequence, index - 1, sequence, index);
1✔
185
    analysis_manager.invalidate_all();
1✔
186

187
    return true;
1✔
188
}
1✔
189

190
bool BlockSortingPass::sort(
191
    builder::StructuredSDFGBuilder& builder,
192
    analysis::AnalysisManager& analysis_manager,
193
    structured_control_flow::Sequence& sequence
194
) {
5✔
195
    if (sequence.size() == 0) {
5✔
196
        return false;
×
197
    }
×
198
    bool applied = false;
5✔
199

200
    // Bubble up
201
    size_t i;
5✔
202
    for (i = 0; i < sequence.size(); i++) {
10✔
203
        auto* node = &sequence.at(i).first;
10✔
204
        if (dynamic_cast<structured_control_flow::Return*>(node) ||
10✔
205
            dynamic_cast<structured_control_flow::Break*>(node) ||
10✔
206
            dynamic_cast<structured_control_flow::Continue*>(node)) {
10✔
207
            // Sorting after return, break, and continue is useless
208
            break;
×
209
        } else if (auto* sequence2 = dynamic_cast<structured_control_flow::Sequence*>(node)) {
10✔
210
            applied |= this->sort(builder, analysis_manager, *sequence2);
×
211
        } else if (auto* while_loop = dynamic_cast<structured_control_flow::While*>(node)) {
10✔
212
            applied |= this->sort(builder, analysis_manager, while_loop->root());
×
213
        } else if (auto* loop = dynamic_cast<structured_control_flow::StructuredLoop*>(node)) {
10✔
214
            applied |= this->sort(builder, analysis_manager, loop->root());
×
215
        } else if (auto* if_else = dynamic_cast<structured_control_flow::IfElse*>(node)) {
10✔
216
            for (size_t k = 0; k < if_else->size(); k++) {
×
217
                applied |= this->sort(builder, analysis_manager, if_else->at(k).first);
×
218
            }
×
219
        }
×
220

221
        if (i == sequence.size() - 1) {
10✔
222
            break;
5✔
223
        }
5✔
224

225
        bool local_applied = false;
5✔
226
        long long index = i;
5✔
227
        while (index >= 0 && this->bubble_up(builder, analysis_manager, sequence, index)) {
9✔
228
            local_applied = true;
4✔
229
            index--;
4✔
230
        }
4✔
231
        applied |= local_applied;
5✔
232
    }
5✔
233

234
    // Bubble down
235
    for (size_t j = i; j > 0; j--) {
10✔
236
        bool local_applied = false;
5✔
237
        long long index = j;
5✔
238
        while (index <= i && this->bubble_down(builder, analysis_manager, sequence, index)) {
6✔
239
            local_applied = true;
1✔
240
            index++;
1✔
241
        }
1✔
242
        applied |= local_applied;
5✔
243
    }
5✔
244

245
    return applied;
5✔
246
}
5✔
247

248
bool BlockSortingPass::run_pass(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
5✔
249
    return this->sort(builder, analysis_manager, builder.subject().root());
5✔
250
}
5✔
251

252
bool BlockSortingPass::is_libnode_side_effect_white_listed(data_flow::LibraryNode* libnode) {
3✔
253
    return dynamic_cast<stdlib::AllocaNode*>(libnode) || dynamic_cast<stdlib::CallocNode*>(libnode) ||
3✔
254
           dynamic_cast<stdlib::FreeNode*>(libnode) || dynamic_cast<stdlib::MallocNode*>(libnode) ||
3✔
255
           dynamic_cast<stdlib::MemsetNode*>(libnode) || dynamic_cast<offloading::DataOffloadingNode*>(libnode);
3✔
256
}
3✔
257

258
bool BlockSortingPass::can_be_bubbled_up(structured_control_flow::Block& block) {
5✔
259
    if (this->is_reference_block(block)) {
5✔
260
        return true;
2✔
261
    }
2✔
262

263
    if (this->is_libnode_block(block)) {
3✔
264
        auto* libnode = *block.dataflow().library_nodes().begin();
3✔
265
        if (auto* offloading_node = dynamic_cast<offloading::DataOffloadingNode*>(libnode)) {
3✔
266
            return offloading_node->is_h2d() || offloading_node->is_alloc();
×
267
        }
×
268
        return dynamic_cast<stdlib::AllocaNode*>(libnode) || dynamic_cast<stdlib::CallocNode*>(libnode) ||
3✔
269
               dynamic_cast<stdlib::MallocNode*>(libnode) || dynamic_cast<stdlib::MemsetNode*>(libnode);
3✔
270
    }
3✔
271

272
    return false;
×
273
}
3✔
274

275
bool BlockSortingPass::can_be_bubbled_down(structured_control_flow::Block& block) {
5✔
276
    if (!this->is_libnode_block(block)) {
5✔
277
        return false;
1✔
278
    }
1✔
279

280
    auto* libnode = *block.dataflow().library_nodes().begin();
4✔
281
    if (auto* offloading_node = dynamic_cast<offloading::DataOffloadingNode*>(libnode)) {
4✔
282
        return offloading_node->is_d2h() || offloading_node->is_free();
×
283
    }
×
284
    return dynamic_cast<stdlib::FreeNode*>(libnode);
4✔
285
}
4✔
286

287
std::pair<int, std::string> BlockSortingPass::get_prio_and_order(structured_control_flow::Block* block) {
12✔
288
    auto& dfg = block->dataflow();
12✔
289
    if (this->is_libnode_block(*block)) {
12✔
290
        auto* libnode = *block->dataflow().library_nodes().begin();
6✔
291
        if (dynamic_cast<stdlib::AllocaNode*>(libnode) || dynamic_cast<stdlib::CallocNode*>(libnode) ||
6✔
292
            dynamic_cast<stdlib::MallocNode*>(libnode)) {
6✔
293
            auto& oedge = *block->dataflow().out_edges(*libnode).begin();
3✔
294
            auto& dst = static_cast<data_flow::AccessNode&>(oedge.dst());
3✔
295
            return {300, dst.data()};
3✔
296
        } else if (dynamic_cast<stdlib::FreeNode*>(libnode)) {
3✔
297
            auto& iedge = *block->dataflow().in_edge_for_connector(*libnode, libnode->input(0));
3✔
298
            auto& src = static_cast<const data_flow::AccessNode&>(iedge.src());
3✔
299
            return {300, src.data()};
3✔
300
        } else if (dynamic_cast<stdlib::MemsetNode*>(libnode)) {
3✔
NEW
301
            auto& iedge = *block->dataflow().in_edge_for_connector(*libnode, libnode->input(0));
×
NEW
302
            auto& dst = static_cast<const data_flow::AccessNode&>(iedge.src());
×
303
            return {200, dst.data()};
×
304
        } else if (auto* offloading_node = dynamic_cast<offloading::DataOffloadingNode*>(libnode)) {
×
305
            std::string order = "";
×
306
            if (offloading_node->is_h2d()) {
×
307
                auto& iedge = *dfg.in_edges(*offloading_node).begin();
×
308
                auto& src = static_cast<data_flow::AccessNode&>(iedge.src());
×
309
                order = src.data();
×
310
            } else if (offloading_node->is_alloc() || offloading_node->is_d2h() || offloading_node->is_free()) {
×
311
                auto& oedge = *dfg.out_edges(*offloading_node).begin();
×
312
                auto& dst = static_cast<data_flow::AccessNode&>(oedge.dst());
×
313
                order = dst.data();
×
314
            }
×
315
            return {400, order};
×
316
        }
×
317
    } else if (this->is_reference_block(*block)) {
6✔
318
        return {100, ""};
4✔
319
    }
4✔
320

321
    return {INT_MIN, ""};
2✔
322
}
12✔
323

324
bool BlockSortingPass::is_reference_block(structured_control_flow::Block& block) {
11✔
325
    auto& dfg = block.dataflow();
11✔
326
    if (dfg.nodes().size() != 2) {
11✔
327
        return false;
2✔
328
    }
2✔
329
    if (dfg.edges().size() != 1) {
9✔
330
        return false;
×
331
    }
×
332
    auto& edge = *dfg.edges().begin();
9✔
333
    if (edge.type() != data_flow::MemletType::Reference && edge.type() != data_flow::MemletType::Dereference_Src &&
9✔
334
        edge.type() != data_flow::MemletType::Dereference_Dst) {
9✔
335
        return false;
3✔
336
    }
3✔
337
    return true;
6✔
338
}
9✔
339

340
bool BlockSortingPass::is_libnode_block(structured_control_flow::Block& next_block) {
20✔
341
    auto& next_dfg = next_block.dataflow();
20✔
342
    if (next_dfg.library_nodes().size() != 1) {
20✔
343
        return false;
7✔
344
    }
7✔
345
    auto* libnode = *next_dfg.library_nodes().begin();
13✔
346
    if (next_dfg.edges().size() != libnode->inputs().size() + libnode->outputs().size()) {
13✔
347
        return false;
×
348
    }
×
349
    return true;
13✔
350
}
13✔
351

352
} // namespace passes
353
} // 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