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

daisytuner / sdfglib / 15717109772

17 Jun 2025 08:16PM UTC coverage: 64.66% (+0.08%) from 64.576%
15717109772

push

github

web-flow
Merge pull request #89 from daisytuner/leftover-logs

removes leftover logs

7992 of 12360 relevant lines covered (64.66%)

142.43 hits per line

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

74.34
/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) {}
65✔
12

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

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

30
        if (dynamic_cast<structured_control_flow::Block*>(current)) {
325✔
31
            continue;
85✔
32
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
240✔
33
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
325✔
34
                queue.push_back(&sequence_stmt->at(i).first);
172✔
35
            }
172✔
36
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
240✔
37
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
3✔
38
                queue.push_back(&if_else_stmt->at(i).first);
2✔
39
            }
2✔
40
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
87✔
41
            this->run(while_stmt->root(), while_stmt);
×
42
        } else if (auto for_stmt =
86✔
43
                       dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
86✔
44
            this->run(for_stmt->root(), for_stmt);
86✔
45
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
86✔
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
}
151✔
56

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

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

67
bool LoopAnalysis::is_monotonic(structured_control_flow::StructuredLoop* loop) const {
76✔
68
    AnalysisManager manager(this->sdfg_);
76✔
69
    auto& assums_analysis = manager.get<AssumptionsAnalysis>();
76✔
70
    auto assums = assums_analysis.get(*loop, true);
76✔
71

72
    return symbolic::is_monotonic(loop->update(), loop->indvar(), assums);
76✔
73
}
76✔
74

75
bool LoopAnalysis::is_contiguous(structured_control_flow::StructuredLoop* loop) const {
25✔
76
    AnalysisManager manager(this->sdfg_);
25✔
77
    auto& assums_analysis = manager.get<AssumptionsAnalysis>();
25✔
78
    auto assums = assums_analysis.get(*loop, true);
25✔
79

80
    return symbolic::is_contiguous(loop->update(), loop->indvar(), assums);
25✔
81
}
25✔
82

83
symbolic::Expression LoopAnalysis::canonical_bound(
12✔
84
    structured_control_flow::StructuredLoop* loop) const {
85
    if (!this->is_contiguous(loop)) {
12✔
86
        return SymEngine::null;
×
87
    }
88

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

96
    bool has_complex_clauses = false;
12✔
97
    for (auto& clause : cnf) {
28✔
98
        if (clause.size() > 1) {
16✔
99
            has_complex_clauses = true;
×
100
            break;
×
101
        }
102
    }
103
    if (has_complex_clauses) {
12✔
104
        return SymEngine::null;
×
105
    }
106

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

143
    return bound;
11✔
144
}
12✔
145

146
const std::unordered_map<structured_control_flow::ControlFlowNode*,
147
                         structured_control_flow::ControlFlowNode*>&
148
LoopAnalysis::loop_tree() const {
×
149
    return this->loop_tree_;
×
150
}
151

152
structured_control_flow::ControlFlowNode* LoopAnalysis::parent_loop(
×
153
    structured_control_flow::ControlFlowNode* loop) const {
154
    return this->loop_tree_.at(loop);
×
155
}
156

157
const std::vector<structured_control_flow::ControlFlowNode*> LoopAnalysis::outermost_loops() const {
×
158
    std::vector<structured_control_flow::ControlFlowNode*> outermost_loops_;
×
159
    for (const auto& [loop, parent] : this->loop_tree_) {
×
160
        if (parent == nullptr) {
×
161
            outermost_loops_.push_back(loop);
×
162
        }
×
163
    }
164
    return outermost_loops_;
×
165
}
×
166

167
}  // namespace analysis
168
}  // 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