Halide
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 
13 namespace Halide {
14 namespace Internal {
15 namespace Autoscheduler {
16 
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  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 
102 public:
103  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 
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
Halide::Internal::aslog
Definition: ASLog.h:16
Halide::Internal::Autoscheduler::LoopNestParser::is_in_partial_schedule
bool is_in_partial_schedule(const FunctionDAG::Node *node) const
Definition: LoopNestParser.h:136
Halide::Internal::Autoscheduler::LoopNestParser
Definition: LoopNestParser.h:17
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
Halide::Internal::Autoscheduler::LoopNestParser::LoopNestParser
LoopNestParser(const std::vector< std::string > &loop_nest)
Definition: LoopNestParser.h:103
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
FunctionDAG.h
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::dump
void dump() const
Definition: LoopNestParser.h:108
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
ASLog.h
Halide::Internal::Autoscheduler::LoopNestParser::from_string
static LoopNestParser from_string(const std::string &str)
Definition: LoopNestParser.h:181
Halide::Internal::Autoscheduler::FunctionDAG::Node::func
Function func
Definition: FunctionDAG.h:384
Halide::Internal::Autoscheduler::FunctionDAG::Node
Definition: FunctionDAG.h:379
Halide::Internal::Function::name
const std::string & name() const
Get the name of the function.