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

daisytuner / sdfglib / 21026558861

15 Jan 2026 09:38AM UTC coverage: 62.594% (+0.3%) from 62.264%
21026558861

Pull #446

github

web-flow
Merge 7b9320de6 into eaabb9b4d
Pull Request #446: Fix arg capturing

265 of 396 new or added lines in 7 files covered. (66.92%)

11 existing lines in 4 files now uncovered.

15902 of 25405 relevant lines covered (62.59%)

96.77 hits per line

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

66.34
/src/analysis/arguments_analysis.cpp
1
#include "sdfg/analysis/arguments_analysis.h"
2
#include "sdfg/analysis/mem_access_range_analysis.h"
3
#include "sdfg/analysis/type_analysis.h"
4
#include "sdfg/analysis/users.h"
5
#include "sdfg/types/utils.h"
6

7
namespace sdfg {
8
namespace analysis {
9

10
void ArgumentsAnalysis::find_arguments_and_locals(
11
    analysis::AnalysisManager& analysis_manager, structured_control_flow::ControlFlowNode& node
12
) {
13✔
13
    auto& users = analysis_manager.get<analysis::Users>();
13✔
14
    analysis::UsersView scope_users(users, node);
13✔
15

16
    analysis::TypeAnalysis type_analysis(sdfg_, &node, analysis_manager);
13✔
17

18
    std::unordered_map<std::string, DataRwFlags> all_containers;
13✔
19
    for (auto& user : scope_users.uses()) {
60✔
20
        if (user->container() == symbolic::__nullptr__()->get_name()) {
60✔
NEW
21
            continue;
×
NEW
22
        }
×
23

24
        DataRwFlags meta;
60✔
25
        switch (user->use()) {
60✔
26
            case analysis::READ:
37✔
27
                meta.found_explicit_read();
37✔
28
                break;
37✔
29
            case analysis::WRITE:
23✔
30
                meta.found_explicit_write();
23✔
31
                break;
23✔
NEW
32
            case analysis::MOVE:
×
NEW
33
            case analysis::VIEW:
×
NEW
34
            default:
×
NEW
35
                meta.found_analysis_escape();
×
36
        }
60✔
37
        auto it = all_containers.insert({user->container(), meta});
60✔
38
        if (!it.second) {
60✔
39
            it.first->second.merge(meta);
25✔
40
        }
25✔
41
    }
60✔
42

43
    bool inferred_types = true;
13✔
44
    std::map<std::string, RegionArgument> arguments;
13✔
45
    std::unordered_set<std::string> locals;
13✔
46
    for (auto& [container, rwFlags] : all_containers) {
35✔
47
        bool is_scalar = false;
35✔
48
        bool is_ptr = false;
35✔
49

50
        auto type = type_analysis.get_outer_type(container);
35✔
51
        if (type == nullptr) {
35✔
NEW
52
            inferred_types = false;
×
NEW
53
            is_ptr = true;
×
NEW
54
            is_scalar = false;
×
55
        } else {
35✔
56
            is_scalar = type->type_id() == types::TypeID::Scalar;
35✔
57
            is_ptr = type->type_id() == types::TypeID::Pointer || type->type_id() == types::TypeID::Array;
35✔
58
        }
35✔
59

60
        if (sdfg_.is_argument(container) || sdfg_.is_external(container)) {
35✔
61
            arguments.insert({container, {rwFlags, is_scalar, is_ptr}});
11✔
62
            continue;
11✔
63
        }
11✔
64

65
        size_t total_uses = users.uses(container).size();
24✔
66
        size_t scope_uses = scope_users.uses(container).size();
24✔
67

68
        if (scope_uses < total_uses) {
24✔
69
            arguments.insert({container, {rwFlags, is_scalar, is_ptr}});
4✔
70
        } else {
20✔
71
            locals.insert(container);
20✔
72
        }
20✔
73
    }
24✔
74

75
    node_arguments_.insert({&node, arguments});
13✔
76
    node_locals_.insert({&node, locals});
13✔
77
    node_inferred_types_.insert({&node, inferred_types});
13✔
78
}
13✔
79

80
void ArgumentsAnalysis::collect_arg_sizes(
81
    analysis::AnalysisManager& analysis_manager,
82
    structured_control_flow::ControlFlowNode& node,
83
    bool allow_dynamic_sizes_,
84
    bool do_not_throw
85
) {
11✔
86
    std::unordered_set<std::string> internal_vars;
11✔
87
    argument_sizes_.insert({&node, {}});
11✔
88
    argument_element_sizes_.insert({&node, {}});
11✔
89

90
    auto& mem_access_ranges = analysis_manager.get<analysis::MemAccessRanges>();
11✔
91

92
    auto arguments = this->arguments(analysis_manager, node);
11✔
93
    auto locals = this->locals(analysis_manager, node);
11✔
94

95
    internal_vars.insert(locals.begin(), locals.end());
11✔
96
    std::ranges::for_each(arguments, [&internal_vars](const auto& pair) { internal_vars.insert(pair.first); });
12✔
97

98
    analysis::TypeAnalysis type_analysis(sdfg_, &node, analysis_manager);
11✔
99

100
    for (auto& [argument, meta] : arguments) {
12✔
101
        if (!meta.is_scalar) {
12✔
102
            auto range = mem_access_ranges.get(argument, node, internal_vars);
6✔
103
            if (range == nullptr) {
6✔
NEW
104
                if (do_not_throw) {
×
NEW
105
                    known_sizes_.insert({&node, false});
×
NEW
106
                    return;
×
NEW
107
                } else {
×
NEW
108
                    throw std::runtime_error("Range not found for " + argument);
×
NEW
109
                }
×
NEW
110
            }
×
111
            auto base_type = type_analysis.get_outer_type(argument);
6✔
112
            auto elem_size = types::get_contiguous_element_size(*base_type, true);
6✔
113
            if (range->is_undefined()) {
6✔
NEW
114
                if (!allow_dynamic_sizes_) {
×
NEW
115
                    if (do_not_throw) {
×
NEW
116
                        known_sizes_.insert({&node, false});
×
NEW
117
                        return;
×
NEW
118
                    } else {
×
NEW
119
                        throw std::runtime_error("Argument " + argument + " has undefined range");
×
NEW
120
                    }
×
NEW
121
                }
×
NEW
122
                DEBUG_PRINTLN("Argument " << argument << " has undefined range, using malloc_usable_size");
×
NEW
123
                argument_sizes_.at(&node).insert({argument, symbolic::malloc_usable_size(symbolic::symbol(argument))});
×
NEW
124
                argument_element_sizes_.at(&node).insert({argument, elem_size});
×
NEW
125
                continue;
×
NEW
126
            }
×
127

128
            symbolic::Expression size = symbolic::one();
6✔
129
            if (!range->dims().empty()) {
6✔
130
                size = symbolic::add(range->dims().at(0).second, symbolic::one());
6✔
131
            }
6✔
132

133
            bool is_nested_type = true;
6✔
134
            auto peeled_type = types::peel_to_next_element(*base_type);
6✔
135
            while (is_nested_type) {
12✔
136
                if (peeled_type == nullptr) {
6✔
NEW
137
                    if (do_not_throw) {
×
NEW
138
                        known_sizes_.insert({&node, false});
×
NEW
139
                        return;
×
NEW
140
                    } else {
×
NEW
141
                        throw std::runtime_error("Could not infer type for argument: " + argument);
×
NEW
142
                    }
×
NEW
143
                }
×
144
                if (peeled_type->type_id() == types::TypeID::Array) {
6✔
NEW
145
                    auto array_type = dynamic_cast<const types::Array*>(peeled_type);
×
NEW
146
                    size = symbolic::mul(size, array_type->num_elements());
×
NEW
147
                    peeled_type = &array_type->element_type();
×
148
                } else if (peeled_type->type_id() == types::TypeID::Pointer) {
6✔
NEW
149
                    if (do_not_throw) {
×
NEW
150
                        known_sizes_.insert({&node, false});
×
NEW
151
                        return;
×
NEW
152
                    } else {
×
NEW
153
                        throw std::runtime_error("Non-contiguous pointer type: " + argument);
×
NEW
154
                    }
×
155
                } else {
6✔
156
                    is_nested_type = false;
6✔
157
                }
6✔
158
            }
6✔
159

160

161
            size = symbolic::mul(size, elem_size);
6✔
162
            DEBUG_PRINTLN("Size of " << argument << " is " << size->__str__());
6✔
163
            if (size.is_null()) {
6✔
NEW
164
                if (do_not_throw) {
×
NEW
165
                    known_sizes_.insert({&node, false});
×
NEW
166
                    return;
×
NEW
167
                } else {
×
NEW
168
                    throw std::runtime_error("Cannot figure out access size of " + argument);
×
NEW
169
                }
×
170
            } else {
6✔
171
                argument_sizes_.at(&node).insert({argument, size});
6✔
172
                argument_element_sizes_.at(&node).insert({argument, elem_size});
6✔
173
            }
6✔
174
        } else {
6✔
175
            auto type = type_analysis.get_outer_type(argument);
6✔
176
            if (type == nullptr) {
6✔
NEW
177
                if (do_not_throw) {
×
NEW
178
                    known_sizes_.insert({&node, false});
×
NEW
179
                    return;
×
NEW
180
                } else {
×
NEW
181
                    throw std::runtime_error("Could not infer type for argument: " + argument);
×
NEW
182
                }
×
NEW
183
            }
×
184
            auto size = types::get_contiguous_element_size(*type);
6✔
185
            argument_sizes_.at(&node).insert({argument, size});
6✔
186
            argument_element_sizes_.at(&node).insert({argument, size});
6✔
187
        }
6✔
188
    }
12✔
189

190
    known_sizes_.insert({&node, true});
11✔
191
}
11✔
192

193
ArgumentsAnalysis::ArgumentsAnalysis(StructuredSDFG& sdfg) : Analysis(sdfg) {}
11✔
194

195
void ArgumentsAnalysis::run(analysis::AnalysisManager& analysis_manager) {}
11✔
196

197
const std::map<std::string, RegionArgument>& ArgumentsAnalysis::
198
    arguments(analysis::AnalysisManager& analysis_manager, structured_control_flow::ControlFlowNode& node) {
23✔
199
    if (node_arguments_.find(&node) != node_arguments_.end()) {
23✔
200
        return node_arguments_.at(&node);
22✔
201
    } else {
22✔
202
        find_arguments_and_locals(analysis_manager, node);
1✔
203
        return node_arguments_.at(&node);
1✔
204
    }
1✔
205
}
23✔
206

207
const std::unordered_set<std::string>& ArgumentsAnalysis::
208
    locals(analysis::AnalysisManager& analysis_manager, structured_control_flow::ControlFlowNode& node) {
21✔
209
    if (node_locals_.find(&node) != node_locals_.end()) {
21✔
210
        return node_locals_.at(&node);
21✔
211
    } else {
21✔
NEW
212
        find_arguments_and_locals(analysis_manager, node);
×
NEW
213
        return node_locals_.at(&node);
×
NEW
214
    }
×
215
}
21✔
216

217
bool ArgumentsAnalysis::
218
    inferred_types(analysis::AnalysisManager& analysis_manager, structured_control_flow::ControlFlowNode& node) {
12✔
219
    if (node_inferred_types_.find(&node) != node_inferred_types_.end()) {
12✔
NEW
220
        return node_inferred_types_.at(&node);
×
221
    } else {
12✔
222
        find_arguments_and_locals(analysis_manager, node);
12✔
223
        return node_inferred_types_.at(&node);
12✔
224
    }
12✔
225
}
12✔
226

227
const std::unordered_map<std::string, symbolic::Expression>& ArgumentsAnalysis::argument_sizes(
228
    analysis::AnalysisManager& analysis_manager,
229
    structured_control_flow::ControlFlowNode& node,
230
    bool allow_dynamic_sizes_
231
) {
13✔
232
    if (argument_sizes_.find(&node) != argument_sizes_.end() && known_sizes_.at(&node)) {
13✔
233
        return argument_sizes_.at(&node);
13✔
234
    } else {
13✔
NEW
235
        collect_arg_sizes(analysis_manager, node, allow_dynamic_sizes_, false);
×
NEW
236
        return argument_sizes_.at(&node);
×
NEW
237
    }
×
238
}
13✔
239

240
const std::unordered_map<std::string, symbolic::Expression>& ArgumentsAnalysis::argument_element_sizes(
241
    analysis::AnalysisManager& analysis_manager,
242
    structured_control_flow::ControlFlowNode& node,
243
    bool allow_dynamic_sizes_
244
) {
1✔
245
    if (argument_element_sizes_.find(&node) != argument_element_sizes_.end() && known_sizes_.at(&node)) {
1✔
246
        return argument_element_sizes_.at(&node);
1✔
247
    } else {
1✔
NEW
248
        collect_arg_sizes(analysis_manager, node, allow_dynamic_sizes_, false);
×
NEW
249
        return argument_element_sizes_.at(&node);
×
NEW
250
    }
×
251
}
1✔
252

253
bool ArgumentsAnalysis::argument_size_known(
254
    analysis::AnalysisManager& analysis_manager,
255
    structured_control_flow::ControlFlowNode& node,
256
    bool allow_dynamic_sizes_
257
) {
11✔
258
    if (known_sizes_.find(&node) != known_sizes_.end()) {
11✔
NEW
259
        return known_sizes_.at(&node);
×
260
    } else {
11✔
261
        collect_arg_sizes(analysis_manager, node, allow_dynamic_sizes_, true);
11✔
262
        return known_sizes_.at(&node);
11✔
263
    }
11✔
264
}
11✔
265

266
} // namespace analysis
267
} // 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