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
29namespace glow {
30
31template <class T> using VecVec = std::vector<std::vector<T>>;
32template <class T> using VecVecRef = llvm::ArrayRef<std::vector<T>>;
33template <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..."
36llvm::raw_ostream &operator<<(llvm::raw_ostream &os, void *ptr);
37
38/// \returns output stream for stdout.
39llvm::raw_ostream &outs();
40
41/// \returns output stream for stderr.
42llvm::raw_ostream &errs();
43
44/// \returns output stream for debug messages.
45llvm::raw_ostream &dbgs();
46
47/// Stream LLVM's ArrayRef into the given output stream.
48template <typename Stream, typename E>
49Stream &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.
71std::string separateString(const std::string &str, size_t length,
72 const std::string &delimiter = "\n");
73std::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.
77std::string escapeDottyString(const std::string &str);
78
79/// \returns the node color based on \p index which is used in dot file.
80const char *getDotFileNodeColor(size_t index);
81
82/// Add quotes to the string \p in.
83inline std::string quote(const std::string &in) { return '"' + in + '"'; }
84
85/// \returns the content of the string \p in after conversion to lower case.
86inline 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.
93class DescriptionBuilder {
94 std::string buffer_;
95 llvm::raw_string_ostream repr_;
96
97public:
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.
131void report(const char *msg);
132inline void report(const std::string &str) { report(str.c_str()); }
133inline 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.
141std::string legalizeName(llvm::StringRef name, size_t maxLength = 500);
142
143/// Data structure for multi string format used in yaml file.
144struct MultiLineStr {
145 std::string str;
146};
147
148/// Data structure used to read the yaml file for Device Configs.
149struct 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 &parameters)
161 : name_(name), backendName_(backendName), parameters_(parameters) {}
162};
163
164/// Deserialize quantization infos from the file \p fileName.
165std::vector<DeviceConfigHelper>
166deserializeDeviceConfigFromYaml(llvm::StringRef fileName);
167
168/// Deserialize string to string map from the file \p fileName.
169std::map<std::string, std::string>
170deserializeStrStrMapFromYaml(llvm::StringRef fileName);
171
172/// Printf-like formatting for std::string.
173const 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.
181const 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.
189template <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.
228constexpr char startChar = '$';
229/// Char used for separating attribute name from attribute value.
230constexpr char sepChar = ':';
231
232/// Signifier used to separate C2 loader name from unique offset mapping.
233constexpr const char *offsetSepSig = "@";
234/// Signifier used to separate C2 end of a loader name to unique offset mapping.
235constexpr const char *offsetEndSig = "@@";
236
237/// Convert a string to int. \returns the int or Error if problem parsing.
238Expected<int> getIntFromStr(llvm::StringRef input);
239
240/// Convert a string to float. \returns the float or Error if problem parsing.
241Expected<float> getFloatFromStr(llvm::StringRef input);
242
243/// A helper type for creating compile-time strings.
244template <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.
254template <class T>
255void 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.
267class ScopeGuard {
268 /// Function to call when the destructor is called.
269 std::function<void()> endFun_;
270
271protected:
272 /// Whether the guard has been dismissed.
273 bool dismissed_{false};
274
275public:
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.
307template <typename ElemTy>
308static 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