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

daisytuner / sdfglib / 20770413849

06 Jan 2026 10:50PM UTC coverage: 62.168% (+21.4%) from 40.764%
20770413849

push

github

web-flow
Merge pull request #433 from daisytuner/clang-coverage

updates clang coverage flags

14988 of 24109 relevant lines covered (62.17%)

88.57 hits per line

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

68.31
/src/passes/dataflow/byte_reference_elimination.cpp
1
#include "sdfg/passes/dataflow/byte_reference_elimination.h"
2

3
#include "sdfg/analysis/dominance_analysis.h"
4
#include "sdfg/analysis/users.h"
5
#include "sdfg/types/utils.h"
6

7
namespace sdfg {
8
namespace passes {
9

10
ByteReferenceElimination::ByteReferenceElimination()
11
    : Pass() {
5✔
12

13
      };
5✔
14

15
std::string ByteReferenceElimination::name() { return "ByteReferenceElimination"; };
×
16

17
bool ByteReferenceElimination::
18
    run_pass(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
5✔
19
    bool applied = false;
5✔
20

21
    auto& sdfg = builder.subject();
5✔
22
    auto& users_analysis = analysis_manager.get<analysis::Users>();
5✔
23
    auto& dominance_analysis = analysis_manager.get<analysis::DominanceAnalysis>();
5✔
24

25
    std::unordered_set<data_flow::AccessNode*> replaced_nodes;
5✔
26
    for (auto& name : sdfg.containers()) {
11✔
27
        if (!sdfg.is_transient(name)) {
11✔
28
            continue;
5✔
29
        }
5✔
30
        if (sdfg.type(name).type_id() != types::TypeID::Pointer) {
6✔
31
            continue;
×
32
        }
×
33
        auto moves = users_analysis.moves(name);
6✔
34
        if (moves.size() != 1) {
6✔
35
            continue;
×
36
        }
×
37

38
        // Find Move
39
        auto move = *moves.begin();
6✔
40
        auto move_node = dynamic_cast<data_flow::AccessNode*>(move->element());
6✔
41
        auto& move_graph = move_node->get_parent();
6✔
42
        auto& move_edge = *move_graph.in_edges(*move_node).begin();
6✔
43
        auto& move_src = static_cast<data_flow::AccessNode&>(move_edge.src());
6✔
44

45
        // Criterion: Move must be a constant offset in bytes
46
        auto& move_type = move_edge.base_type();
6✔
47
        if (move_type.type_id() != types::TypeID::Pointer) {
6✔
48
            continue;
×
49
        }
×
50
        auto& move_pointer_type = static_cast<const types::Pointer&>(move_type);
6✔
51
        if (!move_pointer_type.has_pointee_type()) {
6✔
52
            continue;
×
53
        }
×
54
        auto& move_pointee_type = move_pointer_type.pointee_type();
6✔
55
        if (move_pointee_type.type_id() != types::TypeID::Scalar) {
6✔
56
            continue;
×
57
        }
×
58
        auto& move_pointee_type_bytes = static_cast<const types::Scalar&>(move_pointee_type);
6✔
59
        if (move_pointee_type_bytes.primitive_type() != types::PrimitiveType::Int8 &&
6✔
60
            move_pointee_type_bytes.primitive_type() != types::PrimitiveType::UInt8) {
6✔
61
            continue;
1✔
62
        }
1✔
63

64
        auto& move_subset = move_edge.subset();
5✔
65
        if (move_subset.size() != 1) {
5✔
66
            continue;
×
67
        }
×
68
        auto move_offset = move_subset.at(0);
5✔
69
        if (!SymEngine::is_a<SymEngine::Integer>(*move_offset)) {
5✔
70
            continue;
×
71
        }
×
72
        auto move_offset_int = SymEngine::rcp_static_cast<const SymEngine::Integer>(move_offset);
5✔
73
        int move_offset_bytes = move_offset_int->as_int();
5✔
74

75
        // Replace uses of byte-offseted pointer
76
        auto uses = users_analysis.uses(name);
5✔
77
        for (auto& use : uses) {
12✔
78
            if (use->use() != analysis::Use::VIEW && use->use() != analysis::Use::READ &&
12✔
79
                use->use() != analysis::Use::WRITE) {
12✔
80
                continue;
5✔
81
            }
5✔
82

83
            auto access_node = dynamic_cast<data_flow::AccessNode*>(use->element());
7✔
84
            if (!access_node) {
7✔
85
                continue;
×
86
            }
×
87
            auto& use_graph = access_node->get_parent();
7✔
88
            if (use_graph.out_degree(*access_node) + use_graph.in_degree(*access_node) != 1) {
7✔
89
                continue;
×
90
            }
×
91
            data_flow::Memlet* use_edge = nullptr;
7✔
92
            if (use_graph.in_degree(*access_node) == 1) {
7✔
93
                use_edge = &*use_graph.in_edges(*access_node).begin();
2✔
94
            } else {
5✔
95
                use_edge = &*use_graph.out_edges(*access_node).begin();
5✔
96
            }
5✔
97
            if (use_edge->type() == data_flow::MemletType::Dereference_Dst ||
7✔
98
                use_edge->type() == data_flow::MemletType::Dereference_Src) {
7✔
99
                continue;
×
100
            }
×
101
            if (use_edge->subset().empty()) {
7✔
102
                continue;
×
103
            }
×
104

105
            if (!dominance_analysis.dominates(*move, *use)) {
7✔
106
                continue;
×
107
            }
×
108

109
            // Criterion: No reassignment of pointer or view in between
110
            if (users_analysis.moves(move_src.data()).size() > 0) {
7✔
111
                auto uses_between = users_analysis.all_uses_between(*move, *use);
2✔
112
                bool unsafe = false;
2✔
113
                for (auto& use : uses_between) {
2✔
114
                    if (use->use() != analysis::Use::MOVE) {
×
115
                        continue;
×
116
                    }
×
117
                    // Pointer is not constant
118
                    if (use->container() == move_src.data()) {
×
119
                        unsafe = true;
×
120
                        break;
×
121
                    }
×
122
                }
×
123
                if (unsafe) {
2✔
124
                    continue;
×
125
                }
×
126
            }
2✔
127

128
            // Criterion: View must be a pointer
129
            auto& base_type = use_edge->base_type();
7✔
130
            if (base_type.type_id() != types::TypeID::Pointer) {
7✔
131
                continue;
×
132
            }
×
133
            auto& base_pointer_type = static_cast<const types::Pointer&>(base_type);
7✔
134
            if (!base_pointer_type.has_pointee_type()) {
7✔
135
                continue;
×
136
            }
×
137
            auto& pointee_type = base_pointer_type.pointee_type();
7✔
138
            auto pointee_type_size = types::get_type_size(pointee_type, false);
7✔
139
            if (pointee_type_size.is_null()) {
7✔
140
                continue;
×
141
            }
×
142
            if (!SymEngine::is_a<SymEngine::Integer>(*pointee_type_size)) {
7✔
143
                continue;
×
144
            }
×
145
            int pointee_type_int = SymEngine::rcp_static_cast<const SymEngine::Integer>(pointee_type_size)->as_int();
7✔
146
            if (move_offset_bytes % pointee_type_int != 0) {
7✔
147
                continue;
×
148
            }
×
149
            int elements = move_offset_bytes / pointee_type_int;
7✔
150

151
            data_flow::Subset new_subset = use_edge->subset();
7✔
152
            auto offset = use_edge->subset().at(0);
7✔
153
            new_subset[0] = symbolic::add(offset, symbolic::integer(elements));
7✔
154
            use_edge->set_subset(new_subset);
7✔
155
            access_node->data(move_src.data());
7✔
156
            replaced_nodes.insert(access_node);
7✔
157

158
            applied = true;
7✔
159
        }
7✔
160
    }
5✔
161

162
    // Post-processing: Merge access nodes and remove dangling nodes
163
    // Avoid removing elements while iterating above
164
    for (auto* node : replaced_nodes) {
7✔
165
        builder.merge_siblings(*node);
7✔
166
    }
7✔
167
    for (auto* node : replaced_nodes) {
7✔
168
        auto& graph = node->get_parent();
7✔
169
        auto* block = static_cast<structured_control_flow::Block*>(graph.get_parent());
7✔
170
        for (auto& dnode : graph.data_nodes()) {
15✔
171
            if (graph.in_degree(*dnode) == 0 && graph.out_degree(*dnode) == 0) {
15✔
172
                builder.remove_node(*block, *dnode);
1✔
173
            }
1✔
174
        }
15✔
175
    }
7✔
176

177
    return applied;
5✔
178
};
5✔
179

180
} // namespace passes
181
} // 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