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

daisytuner / sdfglib / 20147202960

11 Dec 2025 08:57PM UTC coverage: 40.181% (-0.09%) from 40.268%
20147202960

push

github

lukastruemper
removes timing outputs of passes

13596 of 43795 branches covered (31.04%)

Branch coverage included in aggregate %.

11609 of 18933 relevant lines covered (61.32%)

93.45 hits per line

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

61.33
/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()
6✔
11
    : Pass() {
6✔
12

13
      };
6✔
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()) {
16!
27
        if (!sdfg.is_transient(name)) {
11!
28
            continue;
5✔
29
        }
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 &&
7!
60
            move_pointee_type_bytes.primitive_type() != types::PrimitiveType::UInt8) {
1!
61
            continue;
1✔
62
        }
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) {
17✔
78
            if (use->use() != analysis::Use::VIEW && use->use() != analysis::Use::READ &&
19!
79
                use->use() != analysis::Use::WRITE) {
7!
80
                continue;
5✔
81
            }
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 {
2✔
95
                use_edge = &*use_graph.out_edges(*access_node).begin();
5!
96
            }
97
            if (use_edge->type() == data_flow::MemletType::Dereference_Dst ||
14!
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
    }
6✔
161

162
    // Post-processing: Merge access nodes and remove dangling nodes
163
    // Avoid removing elements while iterating above
164
    for (auto* node : replaced_nodes) {
12✔
165
        builder.merge_siblings(*node);
7!
166
    }
167
    for (auto* node : replaced_nodes) {
12✔
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()) {
22!
171
            if (graph.in_degree(*dnode) == 0 && graph.out_degree(*dnode) == 0) {
15!
172
                builder.remove_node(*block, *dnode);
1!
173
            }
1✔
174
        }
175
    }
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