LLVM: include/llvm/Support/DebugLog.h Source File (original) (raw)
84
85
86
87#define LDBG_STREAM ::llvm::dbgs()
88
89
90
91
92
93
94
95#define LDBG_FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
96#define LDBG_FUNC_RECOMPOSER(argsWithParentheses) \
97 LDBG_FUNC_CHOOSER argsWithParentheses
98#define LDBG_CHOOSE_FROM_ARG_COUNT(...) \
99 LDBG_FUNC_RECOMPOSER((__VA_ARGS__, LDBG_TYPE_AND_LEVEL, LDBG_LEVEL_OR_TYPE, ))
100#define LDBG_NO_ARG_EXPANDER() , , LDBG_NO_ARG
101#define _GET_LDBG_MACRO(...) \
102 LDBG_CHOOSE_FROM_ARG_COUNT(LDBG_NO_ARG_EXPANDER __VA_ARGS__())
103
104
105
106#define LDBG_STREAM_LEVEL_TYPE_FILE_AND_LINE(STREAM, LEVEL_OR_TYPE, \
107 TYPE_OR_LEVEL, FILE, LINE) \
108 for (bool _c = ::llvm::DebugFlag && ::llvm::impl::ldbgIsCurrentDebugType( \
109 TYPE_OR_LEVEL, LEVEL_OR_TYPE); \
110 _c; _c = false) \
111 ::llvm::impl::raw_ldbg_ostream{ \
112 ::llvm::impl::computePrefix(TYPE_OR_LEVEL, FILE, LINE, LEVEL_OR_TYPE), \
113 (STREAM), true, \
114 true} \
115 .asLvalue()
116
117
118
119#define LDBG_STREAM_LEVEL_TYPE_AND_FILE(STREAM, LEVEL_OR_TYPE, TYPE_OR_LEVEL, \
120 FILE) \
121 LDBG_STREAM_LEVEL_TYPE_FILE_AND_LINE(STREAM, LEVEL_OR_TYPE, TYPE_OR_LEVEL, \
122 FILE, __LINE__)
123#define LDGB_STREAM_LEVEL_AND_TYPE(STREAM, LEVEL_OR_TYPE, TYPE_OR_LEVEL) \
124 LDBG_STREAM_LEVEL_TYPE_AND_FILE(STREAM, LEVEL_OR_TYPE, TYPE_OR_LEVEL, \
125 __LLVM_FILE_NAME__)
126
127
128
129
130
131#define LDBG_TYPE_AND_LEVEL(TYPE, LEVEL) \
132 LDGB_STREAM_LEVEL_AND_TYPE(LDBG_STREAM, static_cast<const char *>(TYPE), \
133 (LEVEL))
134
135
136
137
138#define LDBG_LEVEL_OR_TYPE(LEVEL_OR_TYPE) \
139 LDGB_STREAM_LEVEL_AND_TYPE(LDBG_STREAM, (LEVEL_OR_TYPE), \
140 LDBG_GET_DEFAULT_TYPE_OR_LEVEL(LEVEL_OR_TYPE))
141#define LDBG_NO_ARG() LDBG_LEVEL_OR_TYPE(1)
142
143
144
145
146
147
148
149#define LDBG_OS_FUNC_CHOOSER(_f1, _f2, _f3, _f4, ...) _f4
150#define LDBG_OS_FUNC_RECOMPOSER(argsWithParentheses) \
151 LDBG_OS_FUNC_CHOOSER argsWithParentheses
152#define LDBG_OS_CHOOSE_FROM_ARG_COUNT(...) \
153 LDBG_OS_FUNC_RECOMPOSER((__VA_ARGS__, LDBG_OS_TYPE_AND_LEVEL_AND_CALLBACK, \
154 LDBG_OS_LEVEL_OR_TYPE_AND_CALLBACK, \
155 LDBG_OS_CALLBACK, ))
156#define LDBG_OS_NO_ARG_EXPANDER() , , , LDBG_OS_CALLBACK
157#define _GET_LDBG_OS_MACRO(...) \
158 LDBG_OS_CHOOSE_FROM_ARG_COUNT(LDBG_OS_NO_ARG_EXPANDER __VA_ARGS__())
159
160
161
162#define LDBG_OS_IMPL(TYPE_OR_LEVEL, LEVEL_OR_TYPE, CALLBACK, STREAM, FILE, \
163 LINE) \
164 if (::llvm::DebugFlag && \
165 ::llvm::impl::ldbgIsCurrentDebugType(TYPE_OR_LEVEL, LEVEL_OR_TYPE)) { \
166 ::llvm::impl::raw_ldbg_ostream LdbgOS{ \
167 ::llvm::impl::computePrefix(TYPE_OR_LEVEL, FILE, LINE, LEVEL_OR_TYPE), \
168 (STREAM), true, \
169 true}; \
170 CALLBACK(LdbgOS); \
171 }
172
173#define LDBG_OS_TYPE_AND_LEVEL_AND_CALLBACK(TYPE, LEVEL, CALLBACK) \
174 LDBG_OS_IMPL(static_cast<const char *>(TYPE), LEVEL, CALLBACK, LDBG_STREAM, \
175 __LLVM_FILE_NAME__, __LINE__)
176#define LDBG_OS_LEVEL_OR_TYPE_AND_CALLBACK(LEVEL_OR_TYPE, CALLBACK) \
177 LDBG_OS_IMPL(LDBG_GET_DEFAULT_TYPE_OR_LEVEL(LEVEL_OR_TYPE), LEVEL_OR_TYPE, \
178 CALLBACK, LDBG_STREAM, __LLVM_FILE_NAME__, __LINE__)
179#define LDBG_OS_CALLBACK(CALLBACK) \
180 LDBG_OS_LEVEL_OR_TYPE_AND_CALLBACK(1, CALLBACK)
181
182
183
184
185
186
187
188
189
190
191
192constexpr ::llvm::StringRef strip_quotes(const char *Str) {
194 if (Str[0] == '"' && Str[S.size() - 1] == '"')
196 return S;
197}
198
199
200
201
202
203#define LDBG_GET_DEFAULT_TYPE_OR_LEVEL(LEVEL_OR_TYPE) \
204 [](auto LevelOrType) { \
205 if constexpr (std::is_integral_v<decltype(LevelOrType)>) { \
206 constexpr const char *DebugType = LDBG_GET_DEBUG_TYPE_STR(); \
207 if constexpr (DebugType[0] == '"') { \
208 return ::llvm::impl::strip_quotes(DebugType); \
209 } else { \
210 return __LLVM_FILE_NAME__; \
211 } \
212 } else { \
213 return 1; \
214 } \
215 }(LEVEL_OR_TYPE)
216
217
218
219#define LDBG_GET_DEBUG_TYPE_STR__(X) #X
220#define LDBG_GET_DEBUG_TYPE_STR_(X) LDBG_GET_DEBUG_TYPE_STR__(X)
221#define LDBG_GET_DEBUG_TYPE_STR() LDBG_GET_DEBUG_TYPE_STR_(DEBUG_TYPE)
222
223
224[[maybe_unused]] static bool ldbgIsCurrentDebugType(StringRef Type, int Level) {
225 return ::llvm::isCurrentDebugType(Type.str().c_str(), Level);
226}
227[[maybe_unused]] static bool ldbgIsCurrentDebugType(int Level, StringRef Type) {
228 return ::llvm::isCurrentDebugType(Type.str().c_str(), Level);
229}
230
231
232
233class LLVM_ABI raw_ldbg_ostream final : public raw_ostream {
234 std::string Prefix;
235 raw_ostream &Os;
236 bool ShouldPrefixNextString;
237 bool ShouldEmitNewLineOnDestruction;
238
239
240
241 void write_impl(const char *Ptr, size_t Size) final {
242 auto Str = StringRef(Ptr, Size);
243 auto Eol = Str.find('\n');
244 // Handle `\n` occurring in the string, ensure to print the prefix at the
245 // beginning of each line.
246 while (Eol != StringRef::npos) {
247 // Take the line up to the newline (including the newline).
248 StringRef Line = Str.take_front(Eol + 1);
249 if (!Line.empty())
250 writeWithPrefix(Line);
251 // We printed a newline, record here to print a prefix.
252 ShouldPrefixNextString = true;
253 Str = Str.drop_front(Eol + 1);
254 Eol = Str.find('\n');
255 }
256 if (!Str.empty())
257 writeWithPrefix(Str);
258 }
259 void emitPrefix() { Os.write(Prefix.c_str(), Prefix.size()); }
260 void writeWithPrefix(StringRef Str) {
261 if (ShouldPrefixNextString) {
262 emitPrefix();
263 ShouldPrefixNextString = false;
264 }
265 Os.write(Str.data(), Str.size());
266 }
267
268public:
269 explicit raw_ldbg_ostream(std::string Prefix, raw_ostream &Os,
270 bool ShouldPrefixNextString = true,
271 bool ShouldEmitNewLineOnDestruction = false)
272 : Prefix(std::move(Prefix)), Os(Os),
273 ShouldPrefixNextString(ShouldPrefixNextString),
274 ShouldEmitNewLineOnDestruction(ShouldEmitNewLineOnDestruction) {
275 SetUnbuffered();
276 }
277 ~raw_ldbg_ostream() final {
278 if (ShouldEmitNewLineOnDestruction)
279 Os << '\n';
280 }
281
282
283 uint64_t current_pos() const final { return Os.tell(); }
284
285
286
287 raw_ldbg_ostream &asLvalue() { return *this; }
288};
289
290
291class RAIINewLineStream final : public raw_ostream {
292 raw_ostream &Os;
293
294public:
295 RAIINewLineStream(raw_ostream &Os) : Os(Os) { SetUnbuffered(); }
296 ~RAIINewLineStream() override { Os << '\n'; }
297 void write_impl(const char *Ptr, size_t Size) final { Os.write(Ptr, Size); }
298 uint64_t current_pos() const final { return Os.tell(); }
299 RAIINewLineStream &asLvalue() { return *this; }
300};
301
302
303[[maybe_unused]] static constexpr const char *
304getShortFileName(const char *path) {
305 const char *filename = path;
306 for (const char *p = path; *p != '\0'; ++p) {
307 if (*p == '/' || *p == '\\')
308 filename = p + 1;
309 }
310 return filename;
311}
312
313
314
315
316[[maybe_unused]] static std::string
317computePrefix(StringRef DebugType, const char *File, int Line, int Level) {
318 std::string Prefix;
319 raw_string_ostream OsPrefix(Prefix);
320 OsPrefix << "[";
321 if (!DebugType.empty() && DebugType != File)
322 OsPrefix << DebugType << " ";
323 OsPrefix << File << ":" << Line << " " << Level << "] ";
324 return OsPrefix.str();
325}
326
327[[maybe_unused]] static std::string
328computePrefix(int Level, const char *File, int Line, StringRef DebugType) {
329 return computePrefix(DebugType, File, Line, Level);
330}
331
332} // end namespace impl
334// As others in Debug, When compiling without assertions, the -debug-* options
335// and all inputs too LDBG() are ignored.