1 | /** |
2 | * Copyright (c) Glow Contributors. See CONTRIBUTORS file. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | #ifndef GLOW_SUPPORT_SUPPORT_H |
17 | #define GLOW_SUPPORT_SUPPORT_H |
18 | |
19 | #include "glow/Support/Error.h" |
20 | |
21 | #include "llvm/ADT/ArrayRef.h" |
22 | #include "llvm/Support/raw_ostream.h" |
23 | |
24 | #include <chrono> |
25 | #include <iostream> |
26 | #include <map> |
27 | #include <sstream> |
28 | |
29 | namespace glow { |
30 | |
31 | template <class T> using VecVec = std::vector<std::vector<T>>; |
32 | template <class T> using VecVecRef = llvm::ArrayRef<std::vector<T>>; |
33 | template <class T> using UniquePtrVec = std::vector<std::unique_ptr<T>>; |
34 | |
35 | /// Convert the ptr \p ptr into an ascii representation in the format "0xFFF..." |
36 | llvm::raw_ostream &operator<<(llvm::raw_ostream &os, void *ptr); |
37 | |
38 | /// \returns output stream for stdout. |
39 | llvm::raw_ostream &outs(); |
40 | |
41 | /// \returns output stream for stderr. |
42 | llvm::raw_ostream &errs(); |
43 | |
44 | /// \returns output stream for debug messages. |
45 | llvm::raw_ostream &dbgs(); |
46 | |
47 | /// Stream LLVM's ArrayRef into the given output stream. |
48 | template <typename Stream, typename E> |
49 | Stream &operator<<(Stream &os, const llvm::ArrayRef<E> list) { |
50 | os << '['; |
51 | // Print the array without a trailing comma. |
52 | // Only up to `limit` elements will be printed. |
53 | for (size_t i = 0, e = list.size(), limit = 4; i < e && i <= limit; i++) { |
54 | if (i) { |
55 | os << ", " ; |
56 | } |
57 | if (i == limit) { |
58 | os << "..." ; |
59 | } else { |
60 | os << list[i]; |
61 | } |
62 | } |
63 | os << ']'; |
64 | |
65 | return os; |
66 | } |
67 | |
68 | /// \returns a string obtained from the input string \p str by adding a |
69 | /// delimiter string \p delimiter after each block of \p length characters. |
70 | /// After the last block no delimiter is added. |
71 | std::string separateString(const std::string &str, size_t length, |
72 | const std::string &delimiter = "\n" ); |
73 | std::string separateString(llvm::StringRef str, size_t length, |
74 | const std::string &delimiter = "\n" ); |
75 | /// \returns the escaped content of string \p str. |
76 | /// The char '\n' becomes '\'+'n' and quotes are handled correctly. |
77 | std::string escapeDottyString(const std::string &str); |
78 | |
79 | /// \returns the node color based on \p index which is used in dot file. |
80 | const char *getDotFileNodeColor(size_t index); |
81 | |
82 | /// Add quotes to the string \p in. |
83 | inline std::string quote(const std::string &in) { return '"' + in + '"'; } |
84 | |
85 | /// \returns the content of the string \p in after conversion to lower case. |
86 | inline std::string tolower(const std::string &in) { |
87 | std::string data = in; |
88 | std::transform(data.begin(), data.end(), data.begin(), ::tolower); |
89 | return data; |
90 | } |
91 | |
92 | /// A helper class that builds a textual descriptor of a group of parameters. |
93 | class DescriptionBuilder { |
94 | std::string buffer_; |
95 | llvm::raw_string_ostream repr_; |
96 | |
97 | public: |
98 | explicit DescriptionBuilder(const char *name) : repr_(buffer_) { |
99 | repr_ << name << '\n'; |
100 | } |
101 | |
102 | DescriptionBuilder &addParam(const std::string &name, const char *value) { |
103 | repr_ << name << " : " << value << '\n'; |
104 | return *this; |
105 | } |
106 | |
107 | template <typename E> |
108 | DescriptionBuilder &addParam(const std::string &name, llvm::ArrayRef<E> L) { |
109 | repr_ << name << " : " << L << '\n'; |
110 | return *this; |
111 | } |
112 | |
113 | template <typename T_, |
114 | typename = typename std::enable_if<std::is_scalar<T_>::value>::type> |
115 | DescriptionBuilder &addParam(const std::string &name, T_ value) { |
116 | repr_ << name << " : " << value << '\n'; |
117 | return *this; |
118 | } |
119 | |
120 | template <typename T_, typename = typename std::enable_if< |
121 | !std::is_scalar<T_>::value>::type> |
122 | DescriptionBuilder &addParam(const std::string &name, const T_ &value) { |
123 | repr_ << name << " : " << value << '\n'; |
124 | return *this; |
125 | } |
126 | |
127 | operator std::string() { return repr_.str(); } |
128 | }; |
129 | |
130 | /// Print \p msg on the error stream. |
131 | void report(const char *msg); |
132 | inline void report(const std::string &str) { report(str.c_str()); } |
133 | inline void report(llvm::StringRef str) { report(str.data()); } |
134 | |
135 | /// Legalize \p name used in Module. In Glow module, the name of placeholders |
136 | /// and constants should look like valid C identifiers. Therefore, those symbols |
137 | /// can be inspected under debugger. |
138 | /// \p maxLength argument is used as the upper limit on name length. If it is |
139 | /// zero, then there is no limit. The default value is chosen to allow some |
140 | /// extra room for string concatenations for NNPI. |
141 | std::string legalizeName(llvm::StringRef name, size_t maxLength = 500); |
142 | |
143 | /// Data structure for multi string format used in yaml file. |
144 | struct MultiLineStr { |
145 | std::string str; |
146 | }; |
147 | |
148 | /// Data structure used to read the yaml file for Device Configs. |
149 | struct DeviceConfigHelper { |
150 | /// Device Name. |
151 | std::string name_; |
152 | /// Backend name. |
153 | std::string backendName_; |
154 | /// A string with multi lines. Each line represents a param. |
155 | MultiLineStr parameters_; |
156 | DeviceConfigHelper() = default; |
157 | DeviceConfigHelper(std::string &name, std::string &backendName) |
158 | : name_(name), backendName_(backendName) {} |
159 | DeviceConfigHelper(std::string &backendName, std::string &name, |
160 | MultiLineStr ¶meters) |
161 | : name_(name), backendName_(backendName), parameters_(parameters) {} |
162 | }; |
163 | |
164 | /// Deserialize quantization infos from the file \p fileName. |
165 | std::vector<DeviceConfigHelper> |
166 | deserializeDeviceConfigFromYaml(llvm::StringRef fileName); |
167 | |
168 | /// Deserialize string to string map from the file \p fileName. |
169 | std::map<std::string, std::string> |
170 | deserializeStrStrMapFromYaml(llvm::StringRef fileName); |
171 | |
172 | /// Printf-like formatting for std::string. |
173 | const std::string strFormat(const char *format, ...) |
174 | #ifndef _MSC_VER |
175 | __attribute__((__format__(__printf__, 1, 2))); |
176 | #endif |
177 | ; |
178 | |
179 | /// Printf-like formatting for std::string. The returned string lives until the |
180 | /// end of the program execution. |
181 | const std::string &staticStrFormat(const char *format, ...) |
182 | #ifndef _MSC_VER |
183 | __attribute__((__format__(__printf__, 1, 2))); |
184 | #endif |
185 | ; |
186 | |
187 | /// Helper that converts and \returns an enum class to an unsigned. Useful when |
188 | /// using an enum class in a bitset. |
189 | template <class T> inline constexpr unsigned convertEnumToUnsigned(T e) { |
190 | static_assert(std::is_enum<T>::value, "Can only pass enums." ); |
191 | return static_cast<unsigned>(e); |
192 | } |
193 | |
194 | /// Add helpers for custom location logging. Heavily based on glog/logging.h. |
195 | #if GOOGLE_STRIP_LOG == 0 |
196 | #define COMPACT_GOOGLE_LOG_CUSTOM_LOC_INFO(FILE_, LINE_) \ |
197 | google::LogMessage(FILE_, LINE_) |
198 | #else |
199 | #define COMPACT_GOOGLE_LOG_CUSTOM_LOC_INFO(FILE_, LINE_) google::NullStream() |
200 | #endif |
201 | |
202 | #if GOOGLE_STRIP_LOG <= 1 |
203 | #define COMPACT_GOOGLE_LOG_CUSTOM_LOC_WARNING(FILE_, LINE_) \ |
204 | google::LogMessage(FILE_, LINE_, google::GLOG_WARNING) |
205 | #else |
206 | #define COMPACT_GOOGLE_LOG_CUSTOM_LOC_WARNING(FILE_, LINE_) google::NullStream() |
207 | #endif |
208 | |
209 | #if GOOGLE_STRIP_LOG <= 2 |
210 | #define COMPACT_GOOGLE_LOG_CUSTOM_LOC_ERROR(FILE_, LINE_) \ |
211 | google::LogMessage(FILE_, LINE_, google::GLOG_ERROR) |
212 | #else |
213 | #define COMPACT_GOOGLE_LOG_CUSTOM_LOC_ERROR(FILE_, LINE_) google::NullStream() |
214 | #endif |
215 | |
216 | #if GOOGLE_STRIP_LOG <= 3 |
217 | #define COMPACT_GOOGLE_LOG_CUSTOM_LOC_FATAL(FILE_, LINE_) \ |
218 | google::LogMessageFatal(FILE_, LINE_) |
219 | #else |
220 | #define COMPACT_GOOGLE_LOG_CUSTOM_LOC_FATAL(FILE_, LINE_) \ |
221 | google::NullStreamFatal() |
222 | #endif |
223 | |
224 | #define LOG_CUSTOM_LOC(severity, FILE_, LINE_) \ |
225 | COMPACT_GOOGLE_LOG_CUSTOM_LOC_##severity(FILE_, LINE_).stream() |
226 | |
227 | /// Char used for signifying the start of an attribute name to value mapping. |
228 | constexpr char startChar = '$'; |
229 | /// Char used for separating attribute name from attribute value. |
230 | constexpr char sepChar = ':'; |
231 | |
232 | /// Signifier used to separate C2 loader name from unique offset mapping. |
233 | constexpr const char *offsetSepSig = "@" ; |
234 | /// Signifier used to separate C2 end of a loader name to unique offset mapping. |
235 | constexpr const char *offsetEndSig = "@@" ; |
236 | |
237 | /// Convert a string to int. \returns the int or Error if problem parsing. |
238 | Expected<int> getIntFromStr(llvm::StringRef input); |
239 | |
240 | /// Convert a string to float. \returns the float or Error if problem parsing. |
241 | Expected<float> getFloatFromStr(llvm::StringRef input); |
242 | |
243 | /// A helper type for creating compile-time strings. |
244 | template <char... letters> struct string_t { |
245 | static char const *str() { |
246 | static constexpr char string[] = {letters..., '\0'}; |
247 | return string; |
248 | } |
249 | }; |
250 | |
251 | /// Reorder vector \p v according to the indices in \p order. Value at index |
252 | /// idx in \p v will end up at the position indicated by the value in \p order |
253 | /// at index idx. |
254 | template <class T> |
255 | void vectorReorder(std::vector<T> &v, std::vector<size_t> const &order) { |
256 | for (size_t s = 1, d; s < order.size(); ++s) { |
257 | for (d = order[s]; d < s; d = order[d]) |
258 | ; |
259 | if (d == s) |
260 | while (d = order[d], d != s) { |
261 | std::swap(v[s], v[d]); |
262 | } |
263 | } |
264 | } |
265 | |
266 | /// Simple scope guard implementation. |
267 | class ScopeGuard { |
268 | /// Function to call when the destructor is called. |
269 | std::function<void()> endFun_; |
270 | |
271 | protected: |
272 | /// Whether the guard has been dismissed. |
273 | bool dismissed_{false}; |
274 | |
275 | public: |
276 | /// Ctor that takes the function to call in destructor. |
277 | ScopeGuard(std::function<void()> &&fun) |
278 | : endFun_(std::move(fun)), dismissed_(false) {} |
279 | |
280 | /// Make not copyable. |
281 | ScopeGuard(const ScopeGuard &) = delete; |
282 | |
283 | /// Make not assignable. |
284 | ScopeGuard &operator=(const ScopeGuard &) = delete; |
285 | |
286 | /// Dtor that calls \ref endFun_ if \ref dismissed_. |
287 | ~ScopeGuard() { |
288 | if (!dismissed_) { |
289 | endFun_(); |
290 | } |
291 | } |
292 | |
293 | /// Disables the guard. |
294 | void dismiss() { dismissed_ = true; } |
295 | |
296 | /// Runs the function for the guard and dismissed. If already dismissed then |
297 | /// this is a no-op. |
298 | void runAndDismiss() { |
299 | if (!dismissed_) { |
300 | endFun_(); |
301 | dismiss(); |
302 | } |
303 | }; |
304 | }; |
305 | |
306 | /// Helper function to return true if every element in array \p a is \p x. |
307 | template <typename ElemTy> |
308 | static bool isUniformArray(llvm::ArrayRef<ElemTy> a, ElemTy x) { |
309 | return std::all_of(a.begin(), a.end(), [x](ElemTy e) { return e == x; }); |
310 | } |
311 | |
312 | } // namespace glow |
313 | |
314 | #endif // GLOW_SUPPORT_SUPPORT_H |
315 | |