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

daisytuner / docc / 26556322966

27 May 2026 03:45PM UTC coverage: 60.869% (-0.02%) from 60.886%
26556322966

push

github

web-flow
Libnode ptr edges (#719)

Migrating SDFGs to treat pointers as inputs to libNodes / Calls as scalars.
A pointer will only appear in an output edge if its actually returned from the function (like malloc).

* Stdlib, Blas and Tensor Matmul nodes were migrated to this new format. Other, currently transitory Tensor Nodes are not yet migrated.
* DOCC version was bumped to incorporate previous docc-llvm versions (up to 0.4.0) that had been counted separately.
! Until all passes consider the use / leak of pointers as uncertainty / hiding potential writes, TensorNodes are declared as general side-effect.
* Lots of utility functions to centralize the creation (and edges) of various libNodes that needed to be changed.
* Fixed & unified docc paths across python and llvm front-ends.
* Skip BlockFusion test that fails to its libNodes currently having side effects
~ Prevent a crash in DotViz when using symbolic offsets into structs
* Removing old ConstProp pass, it is not safe for the new pointer representation and should not be all too critical

961 of 1749 new or added lines in 52 files covered. (54.95%)

87 existing lines in 28 files now uncovered.

35225 of 57870 relevant lines covered (60.87%)

11046.32 hits per line

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

65.24
/sdfg/src/visualizer/visualizer.cpp
1
#include "sdfg/visualizer/visualizer.h"
2

3
#include <cassert>
4
#include <sstream>
5
#include <stdexcept>
6
#include <string>
7
#include <utility>
8
#include <vector>
9

10
#include "sdfg/data_flow/tasklet.h"
11
#include "sdfg/helpers/helpers.h"
12
#include "sdfg/structured_control_flow/block.h"
13
#include "sdfg/structured_control_flow/control_flow_node.h"
14
#include "sdfg/structured_control_flow/for.h"
15
#include "sdfg/structured_control_flow/if_else.h"
16
#include "sdfg/structured_control_flow/return.h"
17
#include "sdfg/structured_control_flow/sequence.h"
18
#include "sdfg/structured_control_flow/while.h"
19
#include "sdfg/symbolic/symbolic.h"
20
#include "sdfg/types/type.h"
21
#include "symengine/basic.h"
22

23
namespace sdfg {
24
namespace visualizer {
25

26
constexpr const char* code_to_string(data_flow::TaskletCode c) {
26✔
27
    switch (c) {
26✔
28
        case data_flow::TaskletCode::assign:
16✔
29
            return "=";
16✔
30
        case data_flow::TaskletCode::int_add:
2✔
31
        case data_flow::TaskletCode::fp_add:
4✔
32
            return "+";
4✔
33
        case data_flow::TaskletCode::int_sub:
×
34
        case data_flow::TaskletCode::fp_sub:
1✔
35
            return "-";
1✔
36
        case data_flow::TaskletCode::int_mul:
×
37
        case data_flow::TaskletCode::fp_mul:
4✔
38
            return "*";
4✔
39
        case data_flow::TaskletCode::int_udiv:
×
40
        case data_flow::TaskletCode::int_sdiv:
×
41
        case data_flow::TaskletCode::fp_div:
×
42
            return "/";
×
43
        case data_flow::TaskletCode::int_urem:
×
44
        case data_flow::TaskletCode::int_srem:
×
45
        case data_flow::TaskletCode::fp_rem:
×
46
            return "%";
×
47
        case data_flow::TaskletCode::fp_fma:
1✔
48
            return "fma";
1✔
49
        case data_flow::TaskletCode::fp_one:
×
50
            return "of!=";
×
51
        default:
×
52
            return "?";
×
53
    };
26✔
54
};
×
55

56
std::string Visualizer::expression(const std::string expr) {
121✔
57
    if (this->replacements_.empty()) return expr;
121✔
58
    std::string res = expr;
×
59
    size_t pos1 = 0, pos2 = 0;
×
60
    for (std::pair<const std::string, const std::string> replace : this->replacements_) {
×
61
        pos2 = res.find(replace.first);
×
62
        if (pos2 == res.npos) continue;
×
63
        pos1 = 0;
×
64
        std::stringstream res_tmp;
×
65
        while (pos2 < res.npos) {
×
66
            res_tmp << res.substr(pos1, pos2 - pos1) << replace.second;
×
67
            pos1 = pos2 + replace.first.size();
×
68
            pos2 = res.find(replace.first, pos1);
×
69
        }
×
70
        if (pos1 < res.npos) res_tmp << res.substr(pos1);
×
71
        res = res_tmp.str();
×
72
    }
×
73
    return res;
×
74
}
121✔
75

76
void Visualizer::visualizeNode(const StructuredSDFG& sdfg, const structured_control_flow::ControlFlowNode& node) {
49✔
77
    if (auto block = dynamic_cast<const structured_control_flow::Block*>(&node)) {
49✔
78
        this->visualizeBlock(sdfg, *block);
27✔
79
        return;
27✔
80
    }
27✔
81
    if (auto sequence = dynamic_cast<const structured_control_flow::Sequence*>(&node)) {
22✔
82
        this->visualizeSequence(sdfg, *sequence);
×
83
        return;
×
84
    }
×
85
    if (auto if_else = dynamic_cast<const structured_control_flow::IfElse*>(&node)) {
22✔
86
        this->visualizeIfElse(sdfg, *if_else);
3✔
87
        return;
3✔
88
    }
3✔
89
    if (auto while_loop = dynamic_cast<const structured_control_flow::While*>(&node)) {
19✔
90
        this->visualizeWhile(sdfg, *while_loop);
2✔
91
        return;
2✔
92
    }
2✔
93
    if (auto loop = dynamic_cast<const structured_control_flow::For*>(&node)) {
17✔
94
        this->visualizeFor(sdfg, *loop);
10✔
95
        return;
10✔
96
    }
10✔
97
    if (auto return_node = dynamic_cast<const structured_control_flow::Return*>(&node)) {
7✔
98
        this->visualizeReturn(sdfg, *return_node);
2✔
99
        return;
2✔
100
    }
2✔
101
    if (auto break_node = dynamic_cast<const structured_control_flow::Break*>(&node)) {
5✔
102
        this->visualizeBreak(sdfg, *break_node);
1✔
103
        return;
1✔
104
    }
1✔
105
    if (auto continue_node = dynamic_cast<const structured_control_flow::Continue*>(&node)) {
4✔
106
        this->visualizeContinue(sdfg, *continue_node);
1✔
107
        return;
1✔
108
    }
1✔
109
    if (auto map_node = dynamic_cast<const structured_control_flow::Map*>(&node)) {
3✔
110
        this->visualizeMap(sdfg, *map_node);
3✔
111
        return;
3✔
112
    }
3✔
113
    throw std::runtime_error("Unsupported control flow node");
×
114
}
3✔
115

116
void Visualizer::visualizeTasklet(data_flow::Tasklet const& tasklet) {
26✔
117
    std::string op = code_to_string(tasklet.code());
26✔
118
    std::vector<std::string> arguments;
26✔
119
    for (size_t i = 0; i < tasklet.inputs().size(); ++i) {
63✔
120
        arguments.push_back(this->expression(tasklet.input(i)));
37✔
121
    }
37✔
122

123
    if (tasklet.code() == data_flow::TaskletCode::assign) {
26✔
124
        this->stream_ << arguments.at(0);
16✔
125
    } else if (tasklet.code() == data_flow::TaskletCode::fp_fma) {
16✔
126
        if (arguments.size() != 3) throw std::runtime_error("FMA requires 3 arguments");
1✔
127
        this->stream_ << arguments.at(0) << " * " << arguments.at(1) << " + " << arguments.at(2);
1✔
128
    } else {
9✔
129
        this->stream_ << op << "(" << helpers::join(arguments, ", ") << ")";
9✔
130
    }
9✔
131
}
26✔
132

133
void Visualizer::visualizeForBounds(
134
    symbolic::Symbol const& indvar,
135
    symbolic::Expression const& init,
136
    symbolic::Condition const& condition,
137
    symbolic::Expression const& update
138
) {
13✔
139
    this->stream_ << indvar->get_name() << " = " << this->expression(init->__str__()) << "; "
13✔
140
                  << this->expression(condition->__str__()) << "; " << indvar->get_name() << " = "
13✔
141
                  << this->expression(update->__str__());
13✔
142
}
13✔
143

144
std::string Visualizer::subsetRangeString(data_flow::Subset const& subset, int subIdx) {
39✔
145
    auto& dim = subset.at(subIdx);
39✔
146
    return this->expression(dim->__str__());
39✔
147
}
39✔
148

149
/// @brief If known, use the type to better visualize structures. Then track the type as far as it goes.
150
void Visualizer::
151
    visualizeSubset(Function const& function, data_flow::Subset const& sub, types::IType const* type, int subIdx) {
96✔
152
    if (static_cast<int>(sub.size()) <= subIdx) {
96✔
153
        return;
57✔
154
    }
57✔
155
    if (auto structure_type = dynamic_cast<const types::Structure*>(type)) {
39✔
156
        types::StructureDefinition const& definition = function.structure(structure_type->name());
×
157

NEW
158
        auto& memberIdx = sub.at(subIdx);
×
NEW
159
        if (!memberIdx.is_null() && SymEngine::is_a<SymEngine::Integer>(*memberIdx)) {
×
160
            this->stream_ << ".member_" << this->expression(memberIdx->__str__());
×
NEW
161
            auto& member_type = definition.member_type(SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(memberIdx)
×
NEW
162
            );
×
163
            this->visualizeSubset(function, sub, &member_type, subIdx + 1);
×
164
        } else {
×
165
            this->stream_ << ".member[" << subsetRangeString(sub, subIdx) << "]";
×
166
            this->visualizeSubset(function, sub, nullptr, subIdx + 1);
×
167
        }
×
168
    } else if (auto tensor_type = dynamic_cast<const types::Tensor*>(type)) {
39✔
169
        auto& shape = tensor_type->shape();
×
170
        int tensor_dims = shape.size();
×
171
        int i = 0;
×
172
        while (i < tensor_dims && subIdx < sub.size()) {
×
173
            this->stream_ << "[" << subsetRangeString(sub, i) << ":" << subsetRangeString(shape, i) << "]";
×
174
            ++subIdx;
×
175
            ++i;
×
176
        }
×
177
        if (subIdx < sub.size()) {
×
178
            this->visualizeSubset(function, sub, &tensor_type->element_type(), subIdx);
×
179
        }
×
180
    } else if (auto array_type = dynamic_cast<const types::Array*>(type)) {
39✔
181
        this->stream_ << "[" << subsetRangeString(sub, subIdx) << "]";
16✔
182
        types::IType const& element_type = array_type->element_type();
16✔
183
        this->visualizeSubset(function, sub, &element_type, subIdx + 1);
16✔
184
    } else if (auto pointer_type = dynamic_cast<const types::Pointer*>(type)) {
23✔
185
        this->stream_ << "[" << subsetRangeString(sub, subIdx) << "]";
22✔
186
        const types::IType* pointee_type;
22✔
187
        if (pointer_type->has_pointee_type()) {
22✔
188
            pointee_type = &pointer_type->pointee_type();
19✔
189
        } else {
19✔
190
            auto z = symbolic::zero();
3✔
191
            if (!symbolic::eq(sub.at(subIdx), z)) {
3✔
192
                this->stream_ << "#illgl";
1✔
193
            }
1✔
194
            pointee_type = nullptr;
3✔
195
        }
3✔
196
        this->visualizeSubset(function, sub, pointee_type, subIdx + 1);
22✔
197
    } else {
22✔
198
        if (type == nullptr) {
1✔
199
            this->stream_ << "(rogue)";
1✔
200
        }
1✔
201
        this->stream_ << "[" << subsetRangeString(sub, subIdx) << "]";
1✔
202
        visualizeSubset(function, sub, nullptr, subIdx + 1);
1✔
203
    }
1✔
204
}
39✔
205

206
} // namespace visualizer
207
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc