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

daisytuner / sdfglib / 21026754920

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

Pull #446

github

web-flow
Merge 8638fa3d4 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

49.68
/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;
×
114
            if (varPlan.is_external) {
×
115
                safe_name = language_extension.external_prefix() + argName;
×
116
            } else {
×
117
                safe_name = argName;
×
118
            }
×
119

120

NEW
121
            stream << "\t__daisy_capture_raw(" << "__capture_ctx, " << argIdx << ", " << (varPlan.is_scalar ? "&" : "")
×
NEW
122
                   << safe_name << ", " << language_extension.expression(varPlan.size) << ", " << varPlan.inner_type
×
NEW
123
                   << ", " << afterBoolStr << ", " << element_id << ");" << std::endl;
×
UNCOV
124
        }
×
UNCOV
125
    }
×
126
}
×
127

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

145
    auto& innermost_type = types::peel_to_innermost_element(*type);
4✔
146

147
    types::PrimitiveType inner_type = innermost_type.primitive_type();
4✔
148

149
    if (inner_type == types::Void) {
4✔
UNCOV
150
        return false;
×
151
    }
×
152

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

161
    plan.insert(
4✔
162
        {var_name,
4✔
163
         CaptureVarPlan(
4✔
164
             region_arg.is_input, region_arg.is_output, arg_idx, is_external, inner_type, size, region_arg.is_scalar
4✔
165
         )}
4✔
166
    );
4✔
167

168
    DEBUG_PRINTLN("Successfully added capture plan for variable " + var_name);
4✔
169
    return true;
4✔
170
}
4✔
171

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

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

196
    auto& arguments = arguments_analysis.arguments(analysis_manager, node);
2✔
197
    analysis::TypeAnalysis type_analysis(sdfg, &node, analysis_manager);
2✔
198

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

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

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

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

239
    std::cout << "Created capture plan for " << plan.size() << " arguments." << std::endl;
2✔
240
    return plan;
2✔
241
}
2✔
242

243
} // namespace codegen
244
} // 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