Halide 22.0.0 Halide compiler and libraries

LoopNestParser.h
Go to the documentation of this file.
1#ifndef LOOP_NEST_PARSER_H
2#define LOOP_NEST_PARSER_H
3
4#include <fstream>
5#include <sstream>
6#include <string>
7#include <unordered_map>
8#include <unordered_set>
9
10#include "ASLog.h"
11#include "FunctionDAG.h"
12
13namespace Halide {
14namespace Internal {
15namespace Autoscheduler {
16
17 class LoopNestParser {
18 void parse(const std::vector<std::string> &loop_nest) {
19 std::unordered_map<std::string, std::vector<std::string>> stage_to_loop_nest;
20 for (const auto &line : loop_nest) {
21 if (line.empty()) {
22 continue;
23 }
24
25 if (line.at(0) == '#') {
26 continue;
27 }
28
29 std::istringstream iss(line);
30 std::vector<std::string> tokens{
31 std::istream_iterator<std::string>(iss),
32 std::istream_iterator<std::string>()};
33
34 std::string stage = tokens.at(0);
35 bool is_inlined = tokens.at(0) == "inlined:";
36
37 if (tokens.at(0) == "realize:" || is_inlined) {
38 stage = tokens.at(1);
39 }
40
41 if (stage == "gpu_none") {
42 continue;
43 }
44
45 all_stages.insert(stage);
46
47 if (is_inlined) {
48 inlined.insert(stage);
49 continue;
50 }
51
52 if (tokens.back() == "gpu_none") {
53 partially_scheduled.insert(stage);
54 }
55
56 if (line.at(0) != ' ' && compute_root_stages.count(stage) == 0) {
57 compute_root_stages[stage] = -1;
58 }
59
60 if (tokens.back() == "gpu_simd" && compute_root_stages.count(stage) == 1 && compute_root_stages[stage] == -1) {
61 const std::string &vector_dim = tokens[tokens.size() - 3];
62 compute_root_stages[stage] = std::stoi(vector_dim.substr(0, vector_dim.size() - 1));
63 }
64
65 if (partially_scheduled.count(stage) == 0) {
66 stage_to_loop_nest[stage].push_back(line);
67 }
68 }
69
70 for (const auto &entry : stage_to_loop_nest) {
71 std::string loop_nest = "";
72 for (const auto &line : entry.second) {
73 loop_nest += line + "\n";
74 }
75
76 per_stage_loop_nests[entry.first] = loop_nest;
77 }
78
79 // If a stage appears in a 'realize: ' line but nowhere else, remove it
80 std::vector<std::string> to_remove;
81 for (const auto &entry : compute_root_stages) {
82 if (entry.second == -1) {
83 to_remove.push_back(entry.first);
84 }
85 }
86
87 for (const auto &key : to_remove) {
88 compute_root_stages.erase(key);
89 partially_scheduled.erase(key);
90 all_stages.erase(key);
91 per_stage_loop_nests.erase(key);
92 }
93 }
94
95 std::vector<std::string> loop_nest;
96 std::unordered_map<std::string, std::string> per_stage_loop_nests;
97 std::unordered_set<std::string> inlined;
98 std::unordered_set<std::string> partially_scheduled;
99 std::unordered_map<std::string, int> compute_root_stages;
100 std::unordered_set<std::string> all_stages;
101
102public:
103 explicit LoopNestParser(const std::vector<std::string> &loop_nest)
104 : loop_nest{loop_nest} {
105 parse(loop_nest);
106 }
107
108 void dump() const {
109 aslog(1) << "All stages:\n";
110 for (const auto &s : all_stages) {
111 aslog(1) << s << "\n";
112 }
113
114 aslog(1) << "\ncompute_root stages:\n";
115 for (const auto &s : compute_root_stages) {
116 aslog(1) << s.first << " with vector_dim = " << s.second << "\n";
117 }
118
119 aslog(1) << "\nPartially scheduled stages:\n";
120 for (const auto &s : partially_scheduled) {
121 aslog(1) << s << " with vector_dim = " << compute_root_stages.at(s) << "\n";
122 }
123
124 aslog(1) << "\nInlined stages:\n";
125 for (const auto &s : inlined) {
126 aslog(1) << s << "\n";
127 }
128
129 aslog(1) << "\nFull loop nest:\n";
130 for (const auto &s : loop_nest) {
131 aslog(1) << s << "\n";
132 }
133 aslog(1) << "\n";
134 }
135
136 bool is_in_partial_schedule(const FunctionDAG::Node *node) const {
137 return node && all_stages.count(node->func.name()) > 0;
138 }
139
140 bool contains_sub_loop_nest_for_shared_stages(const LoopNestParser &other) const {
141 return contains_sub_loop_nest(other, true);
142 }
143
144 // 'only_consider_shared_stages': check if 'other' is contained in this loop
145 // nest, but ignore stages that are present in 'other' but not present in
146 // this loop nest
147 bool contains_sub_loop_nest(const LoopNestParser &other, bool only_consider_shared_stages = false) const {
148 for (const auto &stage : other.all_stages) {
149 if (all_stages.count(stage) == 0) {
150 if (only_consider_shared_stages) {
151 continue;
152 }
153 return false;
154 }
155
156 if (other.partially_scheduled.count(stage) == 1) {
157 if (compute_root_stages.count(stage) == 0) {
158 return false;
159 }
160
161 return other.compute_root_stages.at(stage) == compute_root_stages.at(stage);
162 }
163
164 if (other.inlined.count(stage) > 0) {
165 if (inlined.count(stage) == 0) {
166 return false;
167 }
168 continue;
169 } else if (inlined.count(stage) > 0) {
170 return false;
171 }
172
173 if (other.per_stage_loop_nests.at(stage) != per_stage_loop_nests.at(stage)) {
174 return false;
175 }
176 }
177
178 return true;
179 }
180
181 static LoopNestParser from_string(const std::string &str) {
182 std::istringstream in(str);
183 std::string line;
184 std::vector<std::string> loop_nest;
185
186 while (std::getline(in, line)) {
187 loop_nest.push_back(line);
188 }
189
190 return LoopNestParser(loop_nest);
191 }
192
193 static std::unique_ptr<LoopNestParser> from_file(const std::string &filename) {
194 std::ifstream file(filename);
195 std::string line;
196 std::vector<std::string> loop_nest;
197
198 while (std::getline(file, line)) {
199 loop_nest.push_back(line);
200 }
201
202 return std::make_unique<LoopNestParser>(loop_nest);
203 }
204};
205
206} // namespace Autoscheduler
207} // namespace Internal
208} // namespace Halide
209
210#endif
ASLog.h
FunctionDAG.h
Halide::Internal::Autoscheduler::LoopNestParser
Definition: LoopNestParser.h:17
Halide::Internal::Autoscheduler::LoopNestParser::dump
void dump() const
Definition: LoopNestParser.h:108
Halide::Internal::Autoscheduler::LoopNestParser::LoopNestParser
LoopNestParser(const std::vector< std::string > &loop_nest)
Definition: LoopNestParser.h:103
Halide::Internal::Autoscheduler::LoopNestParser::contains_sub_loop_nest_for_shared_stages
bool contains_sub_loop_nest_for_shared_stages(const LoopNestParser &other) const
Definition: LoopNestParser.h:140
Halide::Internal::Autoscheduler::LoopNestParser::from_string
static LoopNestParser from_string(const std::string &str)
Definition: LoopNestParser.h:181
Halide::Internal::Autoscheduler::LoopNestParser::contains_sub_loop_nest
bool contains_sub_loop_nest(const LoopNestParser &other, bool only_consider_shared_stages=false) const
Definition: LoopNestParser.h:147
Halide::Internal::Autoscheduler::LoopNestParser::from_file
static std::unique_ptr< LoopNestParser > from_file(const std::string &filename)
Definition: LoopNestParser.h:193
Halide::Internal::Autoscheduler::LoopNestParser::is_in_partial_schedule
bool is_in_partial_schedule(const FunctionDAG::Node *node) const
Definition: LoopNestParser.h:136
Halide::Internal::Function::name
const std::string & name() const
Get the name of the function.
Halide::Internal::aslog
Definition: ASLog.h:16
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
Halide::Internal::Autoscheduler::FunctionDAG::Node
Definition: FunctionDAG.h:378
Halide::Internal::Autoscheduler::FunctionDAG::Node::func
Function func
Definition: FunctionDAG.h:383