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

daisytuner / sdfglib / 15827874660

23 Jun 2025 03:03PM UTC coverage: 64.193% (+0.4%) from 63.824%
15827874660

push

github

web-flow
Merge pull request #100 from daisytuner/transformations

new definition of map and adapts transformations

148 of 194 new or added lines in 13 files covered. (76.29%)

45 existing lines in 4 files now uncovered.

8193 of 12763 relevant lines covered (64.19%)

136.04 hits per line

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

58.91
/src/analysis/loop_analysis.cpp
1
#include "sdfg/analysis/loop_analysis.h"
2

3
#include "sdfg/analysis/assumptions_analysis.h"
4
#include "sdfg/structured_control_flow/structured_loop.h"
5
#include "sdfg/symbolic/conjunctive_normal_form.h"
6
#include "sdfg/symbolic/series.h"
7

8
namespace sdfg {
9
namespace analysis {
10

11
LoopAnalysis::LoopAnalysis(StructuredSDFG& sdfg) : Analysis(sdfg) {}
34✔
12

13
void LoopAnalysis::run(structured_control_flow::ControlFlowNode& scope,
83✔
14
                       structured_control_flow::ControlFlowNode* parent_loop) {
15
    std::list<structured_control_flow::ControlFlowNode*> queue = {&scope};
83✔
16
    while (!queue.empty()) {
272✔
17
        auto current = queue.front();
189✔
18
        queue.pop_front();
189✔
19

20
        // Loop detected
21
        if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
189✔
22
            this->loops_.insert(while_stmt);
×
23
            this->loop_tree_[while_stmt] = parent_loop;
×
24
        } else if (auto loop_stmt =
189✔
25
                       dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
189✔
26
            this->loops_.insert(loop_stmt);
49✔
27
            this->loop_tree_[loop_stmt] = parent_loop;
49✔
28
        }
49✔
29

30
        if (dynamic_cast<structured_control_flow::Block*>(current)) {
189✔
31
            continue;
57✔
32
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
132✔
33
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
189✔
34
                queue.push_back(&sequence_stmt->at(i).first);
106✔
35
            }
106✔
36
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
132✔
37
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
38
                queue.push_back(&if_else_stmt->at(i).first);
×
39
            }
×
40
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
49✔
41
            this->run(while_stmt->root(), while_stmt);
×
42
        } else if (auto for_stmt =
49✔
43
                       dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
49✔
44
            this->run(for_stmt->root(), for_stmt);
49✔
45
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
49✔
46
            continue;
×
47
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
×
48
            continue;
×
49
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
×
50
            continue;
×
51
        } else {
52
            throw std::runtime_error("Unsupported control flow node type");
×
53
        }
54
    }
55
}
83✔
56

57
void LoopAnalysis::run(AnalysisManager& analysis_manager) {
34✔
58
    this->loops_.clear();
34✔
59
    this->loop_tree_.clear();
34✔
60
    this->run(this->sdfg_.root(), nullptr);
34✔
61
}
34✔
62

63
const std::unordered_set<structured_control_flow::ControlFlowNode*> LoopAnalysis::loops() const {
34✔
64
    return this->loops_;
34✔
65
}
66

67
bool LoopAnalysis::is_monotonic(structured_control_flow::StructuredLoop* loop,
93✔
68
                                AssumptionsAnalysis& assumptions_analysis) {
69
    auto assums = assumptions_analysis.get(*loop, true);
93✔
70

71
    return symbolic::series::is_monotonic(loop->update(), loop->indvar(), assums);
93✔
72
}
93✔
73

74
bool LoopAnalysis::is_contiguous(structured_control_flow::StructuredLoop* loop,
17✔
75
                                 AssumptionsAnalysis& assumptions_analysis) {
76
    auto assums = assumptions_analysis.get(*loop, true);
17✔
77

78
    return symbolic::series::is_contiguous(loop->update(), loop->indvar(), assums);
17✔
79
}
17✔
80

81
symbolic::Expression LoopAnalysis::canonical_bound(structured_control_flow::StructuredLoop* loop,
3✔
82
                                                   AssumptionsAnalysis& assumptions_analysis) {
83
    if (!LoopAnalysis::is_monotonic(loop, assumptions_analysis)) {
3✔
84
        return SymEngine::null;
×
85
    }
86

87
    symbolic::CNF cnf;
3✔
88
    try {
89
        cnf = symbolic::conjunctive_normal_form(loop->condition());
3✔
90
    } catch (const std::runtime_error& e) {
3✔
91
        return SymEngine::null;
×
92
    }
×
93

94
    bool has_complex_clauses = false;
3✔
95
    for (auto& clause : cnf) {
8✔
96
        if (clause.size() > 1) {
5✔
97
            has_complex_clauses = true;
×
98
            break;
×
99
        }
100
    }
101
    if (has_complex_clauses) {
3✔
102
        return SymEngine::null;
×
103
    }
104

105
    auto indvar = loop->indvar();
3✔
106
    symbolic::Expression bound = SymEngine::null;
3✔
107
    for (auto& clause : cnf) {
8✔
108
        for (auto& literal : clause) {
10✔
109
            if (SymEngine::is_a<SymEngine::StrictLessThan>(*literal)) {
5✔
110
                auto lt = SymEngine::rcp_dynamic_cast<const SymEngine::StrictLessThan>(literal);
3✔
111
                auto lhs = lt->get_args()[0];
3✔
112
                auto rhs = lt->get_args()[1];
3✔
113
                if (SymEngine::eq(*lhs, *indvar)) {
3✔
114
                    if (bound == SymEngine::null) {
3✔
115
                        bound = rhs;
2✔
116
                    } else {
2✔
117
                        bound = symbolic::min(bound, rhs);
1✔
118
                    }
119
                } else {
3✔
120
                    return SymEngine::null;
×
121
                }
122
            } else if (SymEngine::is_a<SymEngine::LessThan>(*literal)) {
5✔
123
                auto le = SymEngine::rcp_dynamic_cast<const SymEngine::LessThan>(literal);
2✔
124
                auto lhs = le->get_args()[0];
2✔
125
                auto rhs = le->get_args()[1];
2✔
126
                if (SymEngine::eq(*lhs, *indvar)) {
2✔
127
                    if (bound == SymEngine::null) {
2✔
128
                        bound = symbolic::add(rhs, symbolic::one());
1✔
129
                    } else {
1✔
130
                        bound = symbolic::min(bound, symbolic::add(rhs, symbolic::one()));
1✔
131
                    }
132
                } else {
2✔
UNCOV
133
                    return SymEngine::null;
×
134
                }
135
            } else {
2✔
136
                return SymEngine::null;
×
137
            }
138
        }
139
    }
140

141
    return bound;
3✔
142
}
3✔
143

NEW
144
symbolic::Integer LoopAnalysis::stride(structured_control_flow::StructuredLoop* loop) {
×
NEW
145
    auto expr = loop->update();
×
NEW
146
    auto indvar = loop->indvar();
×
147

NEW
148
    if (SymEngine::is_a<SymEngine::Add>(*expr)) {
×
NEW
149
        auto add_expr = SymEngine::rcp_static_cast<const SymEngine::Add>(expr);
×
NEW
150
        if (add_expr->get_args().size() != 2) {
×
NEW
151
            return SymEngine::null;
×
152
        }
NEW
153
        auto arg1 = add_expr->get_args()[0];
×
NEW
154
        auto arg2 = add_expr->get_args()[1];
×
NEW
155
        if (symbolic::eq(arg1, indvar)) {
×
NEW
156
            if (SymEngine::is_a<SymEngine::Integer>(*arg2)) {
×
NEW
157
                return SymEngine::rcp_static_cast<const SymEngine::Integer>(arg2);
×
158
            }
NEW
159
        }
×
NEW
160
        if (symbolic::eq(arg2, indvar)) {
×
NEW
161
            if (SymEngine::is_a<SymEngine::Integer>(*arg1)) {
×
NEW
162
                return SymEngine::rcp_static_cast<const SymEngine::Integer>(arg1);
×
163
            }
NEW
164
        }
×
NEW
165
    }
×
NEW
166
    return SymEngine::null;
×
NEW
167
}
×
168

169
const std::unordered_map<structured_control_flow::ControlFlowNode*,
170
                         structured_control_flow::ControlFlowNode*>&
171
LoopAnalysis::loop_tree() const {
×
172
    return this->loop_tree_;
×
173
}
174

175
structured_control_flow::ControlFlowNode* LoopAnalysis::parent_loop(
×
176
    structured_control_flow::ControlFlowNode* loop) const {
177
    return this->loop_tree_.at(loop);
×
178
}
179

180
const std::vector<structured_control_flow::ControlFlowNode*> LoopAnalysis::outermost_loops() const {
×
181
    std::vector<structured_control_flow::ControlFlowNode*> outermost_loops_;
×
182
    for (const auto& [loop, parent] : this->loop_tree_) {
×
183
        if (parent == nullptr) {
×
184
            outermost_loops_.push_back(loop);
×
185
        }
×
186
    }
187
    return outermost_loops_;
×
188
}
×
189

190
}  // namespace analysis
191
}  // 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