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

daisytuner / sdfglib / 21034827905

15 Jan 2026 02:29PM UTC coverage: 62.59% (+0.3%) from 62.264%
21034827905

push

github

web-flow
Merge pull request #446 from daisytuner/FixArgCapturing

Fix arg capturing

260 of 393 new or added lines in 7 files covered. (66.16%)

7 existing lines in 3 files now uncovered.

15899 of 25402 relevant lines covered (62.59%)

96.79 hits per line

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

48.45
/src/codegen/instrumentation/arg_capture_plan.cpp
1
#include "sdfg/codegen/instrumentation/arg_capture_plan.h"
2

3
#include <iostream>
4
#include <memory>
5
#include <string>
6
#include <utility>
7

8
#include "sdfg/analysis/analysis.h"
9
#include "sdfg/analysis/arguments_analysis.h"
10
#include "sdfg/analysis/loop_analysis.h"
11
#include "sdfg/analysis/type_analysis.h"
12
#include "sdfg/codegen/language_extension.h"
13
#include "sdfg/helpers/helpers.h"
14
#include "sdfg/structured_control_flow/structured_loop.h"
15
#include "sdfg/symbolic/symbolic.h"
16
#include "sdfg/types/utils.h"
17

18
namespace sdfg {
19
namespace codegen {
20

21
CaptureVarPlan::CaptureVarPlan(
22
    bool capture_input,
23
    bool capture_output,
24
    int argIdx,
25
    bool isExternal,
26
    sdfg::types::PrimitiveType innerType,
27
    const sdfg::symbolic::Expression size,
28
    bool isScalar
29
)
30
    : capture_input(capture_input), capture_output(capture_output), arg_idx(argIdx), is_external(isExternal),
4✔
31
      inner_type(innerType), size(size), is_scalar(isScalar) {}
4✔
32

33
bool ArgCapturePlan::should_instrument(const structured_control_flow::ControlFlowNode& node) const {
62✔
34
    return this->nodes_.count(&node);
62✔
35
}
62✔
36

37
void ArgCapturePlan::begin_instrumentation(
38
    const structured_control_flow::ControlFlowNode& node, PrettyPrinter& stream, LanguageExtension& language_extension
39
) const {
×
40
    stream << "const bool __daisy_cap_en_" << node.element_id() << " = __daisy_capture_enter(__capture_ctx, "
×
41
           << node.element_id() << ");" << std::endl;
×
42

43
    stream << "if (__daisy_cap_en_" << node.element_id() << ")";
×
44
    stream << "{" << std::endl;
×
45

46
    auto& node_plan = this->nodes_.at(&node);
×
47
    this->emit_arg_captures(stream, language_extension, node_plan, false, std::to_string(node.element_id()));
×
48

49
    stream << "}" << std::endl;
×
50
}
×
51

52
void ArgCapturePlan::end_instrumentation(
53
    const structured_control_flow::ControlFlowNode& node, PrettyPrinter& stream, LanguageExtension& language_extension
54
) const {
×
55
    stream << "if (__daisy_cap_en_" << node.element_id() << ")";
×
56
    stream << "{" << std::endl;
×
57

58
    auto& node_plan = this->nodes_.at(&node);
×
59
    this->emit_arg_captures(stream, language_extension, node_plan, true, std::to_string(node.element_id()));
×
60

61
    stream << "}" << std::endl;
×
62

63
    stream << "__daisy_capture_end(__capture_ctx);" << std::endl;
×
64
}
×
65

66
std::unique_ptr<ArgCapturePlan> ArgCapturePlan::none(StructuredSDFG& sdfg) {
43✔
67
    return std::make_unique<ArgCapturePlan>(
43✔
68
        sdfg,
43✔
69
        std::unordered_map<
43✔
70
            const structured_control_flow::ControlFlowNode*,
43✔
71
            std::unordered_map<std::string, CaptureVarPlan>>{}
43✔
72
    );
43✔
73
}
43✔
74

75
std::unique_ptr<ArgCapturePlan> ArgCapturePlan::root(StructuredSDFG& sdfg) {
×
76
    analysis::AnalysisManager analysis_manager(sdfg);
×
77
    std::unordered_map<const structured_control_flow::ControlFlowNode*, std::unordered_map<std::string, CaptureVarPlan>>
×
78
        nodes;
×
79
    auto root_plan = create_capture_plan(sdfg, analysis_manager, sdfg.root());
×
80
    nodes.insert({&sdfg.root(), root_plan});
×
81
    return std::make_unique<ArgCapturePlan>(sdfg, nodes);
×
82
}
×
83

84
std::unique_ptr<ArgCapturePlan> ArgCapturePlan::outermost_loops_plan(StructuredSDFG& sdfg) {
2✔
85
    analysis::AnalysisManager analysis_manager(sdfg);
2✔
86
    auto& loop_tree_analysis = analysis_manager.get<analysis::LoopAnalysis>();
2✔
87
    auto ols = loop_tree_analysis.outermost_loops();
2✔
88

89
    std::unordered_map<const structured_control_flow::ControlFlowNode*, std::unordered_map<std::string, CaptureVarPlan>>
2✔
90
        nodes;
2✔
91
    for (size_t i = 0; i < ols.size(); i++) {
2✔
92
        auto& loop = ols[i];
×
93
        auto loop_plan = create_capture_plan(sdfg, analysis_manager, *loop);
×
94
        nodes.insert({loop, loop_plan});
×
95
    }
×
96

97
    DEBUG_PRINTLN("Created arg capture plan for " + std::to_string(nodes.size()) + " nodes.");
2✔
98

99
    return std::make_unique<ArgCapturePlan>(sdfg, nodes);
2✔
100
}
2✔
101

102
void ArgCapturePlan::emit_arg_captures(
103
    PrettyPrinter& stream,
104
    LanguageExtension& language_extension,
105
    const std::unordered_map<std::string, CaptureVarPlan>& plan,
106
    bool after,
107
    std::string element_id
108
) const {
×
109
    auto afterBoolStr = after ? "true" : "false";
×
110
    for (auto& [argName, varPlan] : plan) {
×
111
        auto argIdx = varPlan.arg_idx;
×
112
        if ((!after && varPlan.capture_input) || (after && varPlan.capture_output)) {
×
113
            std::string safe_name;
×
NEW
114
            symbolic::Expression size = varPlan.size;
×
115
            if (varPlan.is_external) {
×
116
                safe_name = language_extension.external_prefix() + argName;
×
NEW
117
                size = symbolic::subs(
×
NEW
118
                    size, symbolic::symbol(argName), symbolic::symbol(language_extension.external_prefix() + argName)
×
NEW
119
                );
×
120
            } else {
×
121
                safe_name = argName;
×
122
            }
×
123

124

NEW
125
            stream << "\t__daisy_capture_raw(" << "__capture_ctx, " << argIdx << ", " << (varPlan.is_scalar ? "&" : "")
×
NEW
126
                   << safe_name << ", " << language_extension.expression(size) << ", " << varPlan.inner_type << ", "
×
NEW
127
                   << afterBoolStr << ", " << element_id << ");" << std::endl;
×
128
        }
×
129
    }
×
130
}
×
131

132
bool ArgCapturePlan::add_capture_plan(
133
    StructuredSDFG& sdfg,
134
    analysis::AnalysisManager& analysis_manager,
135
    structured_control_flow::ControlFlowNode& node,
136
    const std::string& var_name,
137
    analysis::RegionArgument region_arg,
138
    int arg_idx,
139
    bool is_external,
140
    std::unordered_map<std::string, CaptureVarPlan>& plan
141
) {
4✔
142
    analysis::TypeAnalysis type_analysis(sdfg, &node, analysis_manager);
4✔
143
    auto type = type_analysis.get_outer_type(var_name);
4✔
144
    if (type == nullptr) {
4✔
NEW
145
        DEBUG_PRINTLN("Could not determine type for variable " + var_name + ", cannot add to capture plan.");
×
NEW
146
        return false;
×
UNCOV
147
    }
×
148

149
    auto& innermost_type = types::peel_to_innermost_element(*type);
4✔
150

151
    types::PrimitiveType inner_type = innermost_type.primitive_type();
4✔
152

153
    if (inner_type == types::Void) {
4✔
UNCOV
154
        return false;
×
155
    }
×
156

157
    auto& arguments_analysis = analysis_manager.get<analysis::ArgumentsAnalysis>();
4✔
158
    auto arg_sizes = arguments_analysis.argument_sizes(analysis_manager, node, true);
4✔
159
    if (arg_sizes.find(var_name) == arg_sizes.end() && !region_arg.is_scalar) {
4✔
NEW
160
        DEBUG_PRINTLN("Could not determine size for variable " + var_name + ", cannot add to capture plan.");
×
NEW
161
        return false;
×
UNCOV
162
    }
×
163
    auto size = arg_sizes.at(var_name);
4✔
164

165
    plan.insert(
4✔
166
        {var_name,
4✔
167
         CaptureVarPlan(
4✔
168
             region_arg.is_input, region_arg.is_output, arg_idx, is_external, inner_type, size, region_arg.is_scalar
4✔
169
         )}
4✔
170
    );
4✔
171

172
    DEBUG_PRINTLN("Successfully added capture plan for variable " + var_name);
4✔
173
    return true;
4✔
174
}
4✔
175

176
std::unordered_map<std::string, CaptureVarPlan> ArgCapturePlan::create_capture_plan(
177
    StructuredSDFG& sdfg, analysis::AnalysisManager& analysis_manager, structured_control_flow::ControlFlowNode& node
178
) {
2✔
179
    if (auto loop_node = dynamic_cast<structured_control_flow::StructuredLoop*>(&node)) {
2✔
NEW
180
        DEBUG_PRINTLN("Creating capture plan for loop node " << loop_node->indvar()->__str__());
×
181
    } else {
2✔
182
        DEBUG_PRINTLN("Creating capture plan for node " << node.element_id());
2✔
183
    }
2✔
184
    auto& arguments_analysis = analysis_manager.get<analysis::ArgumentsAnalysis>();
2✔
185
    if (!arguments_analysis.inferred_types(analysis_manager, node)) {
2✔
NEW
186
        DEBUG_PRINTLN(
×
NEW
187
            "Could not create capture plan for node " << node.element_id()
×
NEW
188
                                                      << " because argument types could not be inferred."
×
NEW
189
        );
×
NEW
190
        return {};
×
NEW
191
    }
×
192

193
    if (!arguments_analysis.argument_size_known(analysis_manager, node, true)) {
2✔
NEW
194
        DEBUG_PRINTLN(
×
NEW
195
            "Could not create capture plan for node " << node.element_id() << " because argument sizes are not known."
×
NEW
196
        );
×
NEW
197
        return {};
×
NEW
198
    }
×
199

200
    auto& arguments = arguments_analysis.arguments(analysis_manager, node);
2✔
201
    analysis::TypeAnalysis type_analysis(sdfg, &node, analysis_manager);
2✔
202

203
    for (auto argument : arguments) {
4✔
204
        auto arg_type = type_analysis.get_outer_type(argument.first);
4✔
205
        if (!types::is_contiguous_type(*arg_type, sdfg)) {
4✔
NEW
206
            DEBUG_PRINTLN(
×
NEW
207
                "Could not create capture plan for node " << node.element_id() << " because argument " << argument.first
×
NEW
208
                                                          << " is not contiguous."
×
NEW
209
            );
×
NEW
210
            return {};
×
NEW
211
        }
×
212
    }
4✔
213

214
    // Sort arguments to have a deterministic order
215
    std::vector<std::string> args;
2✔
216
    for (auto& [arg_name, flags] : arguments) {
4✔
217
        args.push_back(arg_name);
4✔
218
    }
4✔
219
    std::sort(args.begin(), args.end());
2✔
220
    DEBUG_PRINTLN("Found " + std::to_string(args.size()) + " arguments for region " + std::to_string(node.element_id()));
2✔
221

222
    bool working = true;
2✔
223
    int arg_idx = 0;
2✔
224
    std::unordered_map<std::string, CaptureVarPlan> plan;
2✔
225
    for (auto& arg_name : args) {
4✔
226
        if (sdfg.type(arg_name).type_id() == types::TypeID::Function) {
4✔
227
            continue;
×
228
        }
×
229
        bool external = false;
4✔
230
        if (sdfg.is_external(arg_name)) {
4✔
NEW
231
            external = true;
×
UNCOV
232
        }
×
233

234
        working &=
4✔
235
            add_capture_plan(sdfg, analysis_manager, node, arg_name, arguments.at(arg_name), arg_idx, external, plan);
4✔
236
        ++arg_idx;
4✔
237
    }
4✔
238
    if (!working) {
2✔
239
        DEBUG_PRINTLN("could not create capture plan, returning empty plan");
×
240
        return std::unordered_map<std::string, CaptureVarPlan>{};
×
241
    }
×
242

243
    std::cout << "Created capture plan for " << plan.size() << " arguments." << std::endl;
2✔
244
    return plan;
2✔
245
}
2✔
246

247
} // namespace codegen
248
} // 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