diff --git a/llvm/include/llvm/Support/Debug.h b/llvm/include/llvm/Support/Debug.h index a7795d403721c..b73f2d7c8b852 100644 --- a/llvm/include/llvm/Support/Debug.h +++ b/llvm/include/llvm/Support/Debug.h @@ -44,11 +44,6 @@ class raw_ostream; /// level, return false. LLVM_ABI bool isCurrentDebugType(const char *Type, int Level = 0); -/// Overload allowing to swap the order of the Type and Level arguments. -LLVM_ABI inline bool isCurrentDebugType(int Level, const char *Type) { - return isCurrentDebugType(Type, Level); -} - /// setCurrentDebugType - Set the current debug type, as if the -debug-only=X /// option were specified. Note that DebugFlag also needs to be set to true for /// debug output to be produced. diff --git a/llvm/include/llvm/Support/DebugLog.h b/llvm/include/llvm/Support/DebugLog.h index dce706e196bde..33586dd275573 100644 --- a/llvm/include/llvm/Support/DebugLog.h +++ b/llvm/include/llvm/Support/DebugLog.h @@ -19,52 +19,55 @@ namespace llvm { #ifndef NDEBUG -// LDBG() is a macro that can be used as a raw_ostream for debugging. -// It will stream the output to the dbgs() stream, with a prefix of the -// debug type and the file and line number. A trailing newline is added to the -// output automatically. If the streamed content contains a newline, the prefix -// is added to each beginning of a new line. Nothing is printed if the debug -// output is not enabled or the debug type does not match. -// -// E.g., -// LDBG() << "Bitset contains: " << Bitset; -// is somehow equivalent to -// LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] " << __FILE__ << ":" << -// __LINE__ << " " -// << "Bitset contains: " << Bitset << "\n"); -// +/// LDBG() is a macro that can be used as a raw_ostream for debugging. +/// It will stream the output to the dbgs() stream, with a prefix of the +/// debug type and the file and line number. A trailing newline is added to the +/// output automatically. If the streamed content contains a newline, the prefix +/// is added to each beginning of a new line. Nothing is printed if the debug +/// output is not enabled or the debug type does not match. +/// +/// E.g., +/// LDBG() << "Bitset contains: " << Bitset; +/// is equivalent to +/// LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] " << __FILE__ << ":" << +/// __LINE__ << " " +/// << "Bitset contains: " << Bitset << "\n"); +/// // An optional `level` argument can be provided to control the verbosity of the -// output. The default level is 1, and is in increasing level of verbosity. -// -// The `level` argument can be a literal integer, or a macro that evaluates to -// an integer. -// -// An optional `type` argument can be provided to control the debug type. The -// default type is DEBUG_TYPE. The `type` argument can be a literal string, or a -// macro that evaluates to a string. +/// output. The default level is 1, and is in increasing level of verbosity. +/// +/// The `level` argument can be a literal integer, or a macro that evaluates to +/// an integer. +/// +/// An optional `type` argument can be provided to control the debug type. The +/// default type is DEBUG_TYPE. The `type` argument can be a literal string, or +/// a macro that evaluates to a string. +/// +/// E.g., +/// LDBG(2) << "Bitset contains: " << Bitset; +/// LDBG("debug_type") << "Bitset contains: " << Bitset; +/// LDBG("debug_type", 2) << "Bitset contains: " << Bitset; #define LDBG(...) _GET_LDBG_MACRO(__VA_ARGS__)(__VA_ARGS__) -// Helper macros to choose the correct macro based on the number of arguments. -#define LDBG_FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3 -#define LDBG_FUNC_RECOMPOSER(argsWithParentheses) \ - LDBG_FUNC_CHOOSER argsWithParentheses -#define LDBG_CHOOSE_FROM_ARG_COUNT(...) \ - LDBG_FUNC_RECOMPOSER( \ - (__VA_ARGS__, LDBG_LOG_LEVEL_WITH_TYPE, LDBG_LOG_LEVEL, )) -#define LDBG_NO_ARG_EXPANDER() , , LDBG_LOG_LEVEL_1 -#define _GET_LDBG_MACRO(...) \ - LDBG_CHOOSE_FROM_ARG_COUNT(LDBG_NO_ARG_EXPANDER __VA_ARGS__()) - -// Dispatch macros to support the `level` argument or none (default to 1) -#define LDBG_LOG_LEVEL(LEVEL) \ - DEBUGLOG_WITH_STREAM_AND_TYPE(llvm::dbgs(), LEVEL, DEBUG_TYPE) -#define LDBG_LOG_LEVEL_1() LDBG_LOG_LEVEL(1) -// This macro is a helper when LDBG() is called with 2 arguments. -// In this case we want to allow the order of the arguments to be swapped. -// We rely on the fact that the `level` argument is an integer, and the `type` -// is a string and dispatch to a C++ API that is overloaded. -#define LDBG_LOG_LEVEL_WITH_TYPE(LEVEL_OR_TYPE, TYPE_OR_LEVEL) \ - DEBUGLOG_WITH_STREAM_AND_TYPE(llvm::dbgs(), (LEVEL_OR_TYPE), (TYPE_OR_LEVEL)) +/// LDBG_OS() is a macro that behaves like LDBG() but instead of directly using +/// it to stream the output, it takes a callback function that will be called +/// with a raw_ostream. +/// This is useful when you need to pass a `raw_ostream` to a helper function to +/// be able to print (when the `<<` operator is not available). +/// +/// E.g., +/// LDBG_OS([&] (raw_ostream &Os) { +/// Os << "Pass Manager contains: "; +/// pm.printAsTextual(Os); +/// }); +/// +/// Just like LDBG(), it optionally accepts a `level` and `type` arguments. +/// E.g., +/// LDBG_OS(2, [&] (raw_ostream &Os) { ... }); +/// LDBG_OS("debug_type", [&] (raw_ostream &Os) { ... }); +/// LDBG_OS("debug_type", 2, [&] (raw_ostream &Os) { ... }); +/// +#define LDBG_OS(...) _GET_LDBG_OS_MACRO(__VA_ARGS__)(__VA_ARGS__) // We want the filename without the full path. We are using the __FILE__ macro // and a constexpr function to strip the path prefix. We can avoid the frontend @@ -76,22 +79,155 @@ namespace llvm { #define __LLVM_FILE_NAME__ ::llvm::impl::getShortFileName(__FILE__) #endif -#define DEBUGLOG_WITH_STREAM_TYPE_FILE_AND_LINE(STREAM, LEVEL, TYPE, FILE, \ - LINE) \ - for (bool _c = \ - (::llvm::DebugFlag && ::llvm::isCurrentDebugType(TYPE, LEVEL)); \ +// Everything below are implementation details of the macros above. +namespace impl { + +/// This macro expands to the stream to use for output, we use a macro to allow +/// unit-testing to override. +#define LDBG_STREAM ::llvm::dbgs() + +// ---------------------------------------------------------------------------- +// LDBG() implementation +// ---------------------------------------------------------------------------- + +// Helper macros to choose the correct LDBG() macro based on the number of +// arguments. +#define LDBG_FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3 +#define LDBG_FUNC_RECOMPOSER(argsWithParentheses) \ + LDBG_FUNC_CHOOSER argsWithParentheses +#define LDBG_CHOOSE_FROM_ARG_COUNT(...) \ + LDBG_FUNC_RECOMPOSER((__VA_ARGS__, LDBG_TYPE_AND_LEVEL, LDBG_LEVEL_OR_TYPE, )) +#define LDBG_NO_ARG_EXPANDER() , , LDBG_NO_ARG +#define _GET_LDBG_MACRO(...) \ + LDBG_CHOOSE_FROM_ARG_COUNT(LDBG_NO_ARG_EXPANDER __VA_ARGS__()) + +/// This macro is the core of the LDBG() implementation. It is used to print the +/// debug output with the given stream, level, type, file, and line number. +#define LDBG_STREAM_LEVEL_TYPE_FILE_AND_LINE(STREAM, LEVEL_OR_TYPE, \ + TYPE_OR_LEVEL, FILE, LINE) \ + for (bool _c = ::llvm::DebugFlag && ::llvm::impl::ldbgIsCurrentDebugType( \ + TYPE_OR_LEVEL, LEVEL_OR_TYPE); \ _c; _c = false) \ - for (::llvm::impl::raw_ldbg_ostream LdbgOS{ \ - ::llvm::impl::computePrefix(TYPE, FILE, LINE, LEVEL), (STREAM)}; \ - _c; _c = false) \ - ::llvm::impl::RAIINewLineStream{LdbgOS}.asLvalue() + ::llvm::impl::raw_ldbg_ostream{ \ + ::llvm::impl::computePrefix(TYPE_OR_LEVEL, FILE, LINE, LEVEL_OR_TYPE), \ + (STREAM), /*ShouldPrefixNextString=*/true, \ + /*ShouldEmitNewLineOnDestruction=*/true} \ + .asLvalue() -#define DEBUGLOG_WITH_STREAM_TYPE_AND_FILE(STREAM, LEVEL, TYPE, FILE) \ - DEBUGLOG_WITH_STREAM_TYPE_FILE_AND_LINE(STREAM, LEVEL, TYPE, FILE, __LINE__) -#define DEBUGLOG_WITH_STREAM_AND_TYPE(STREAM, LEVEL, TYPE) \ - DEBUGLOG_WITH_STREAM_TYPE_AND_FILE(STREAM, LEVEL, TYPE, __LLVM_FILE_NAME__) +/// These macros are helpers to implement LDBG() with an increasing amount of +/// optional arguments made explicit. +#define LDBG_STREAM_LEVEL_TYPE_AND_FILE(STREAM, LEVEL_OR_TYPE, TYPE_OR_LEVEL, \ + FILE) \ + LDBG_STREAM_LEVEL_TYPE_FILE_AND_LINE(STREAM, LEVEL_OR_TYPE, TYPE_OR_LEVEL, \ + FILE, __LINE__) +#define LDGB_STREAM_LEVEL_AND_TYPE(STREAM, LEVEL_OR_TYPE, TYPE_OR_LEVEL) \ + LDBG_STREAM_LEVEL_TYPE_AND_FILE(STREAM, LEVEL_OR_TYPE, TYPE_OR_LEVEL, \ + __LLVM_FILE_NAME__) +/// This macro is a helper when LDBG() is called with 2 arguments. +/// In this case we want to force the first argument to be the type for +/// consistency in the codebase. +/// We trick this by casting the first argument to a (const char *) which +/// won't compile with an int. +#define LDBG_TYPE_AND_LEVEL(TYPE, LEVEL) \ + LDGB_STREAM_LEVEL_AND_TYPE(LDBG_STREAM, static_cast(TYPE), \ + (LEVEL)) -namespace impl { +/// When a single argument is provided. This can be either a level or the debug +/// type. If a level is provided, we default the debug type to DEBUG_TYPE, if a +/// string is provided, we default the level to 1. +#define LDBG_LEVEL_OR_TYPE(LEVEL_OR_TYPE) \ + LDGB_STREAM_LEVEL_AND_TYPE(LDBG_STREAM, (LEVEL_OR_TYPE), \ + LDBG_GET_DEFAULT_TYPE_OR_LEVEL(LEVEL_OR_TYPE)) +#define LDBG_NO_ARG() LDBG_LEVEL_OR_TYPE(1) + +// ---------------------------------------------------------------------------- +// LDBG_OS() implementation +// ---------------------------------------------------------------------------- + +// Helper macros to choose the correct LDBG_OS() macro based on the number of +// arguments. +#define LDBG_OS_FUNC_CHOOSER(_f1, _f2, _f3, _f4, ...) _f4 +#define LDBG_OS_FUNC_RECOMPOSER(argsWithParentheses) \ + LDBG_OS_FUNC_CHOOSER argsWithParentheses +#define LDBG_OS_CHOOSE_FROM_ARG_COUNT(...) \ + LDBG_OS_FUNC_RECOMPOSER((__VA_ARGS__, LDBG_OS_TYPE_AND_LEVEL_AND_CALLBACK, \ + LDBG_OS_LEVEL_OR_TYPE_AND_CALLBACK, \ + LDBG_OS_CALLBACK, )) +#define LDBG_OS_NO_ARG_EXPANDER() , , , LDBG_OS_CALLBACK +#define _GET_LDBG_OS_MACRO(...) \ + LDBG_OS_CHOOSE_FROM_ARG_COUNT(LDBG_OS_NO_ARG_EXPANDER __VA_ARGS__()) + +/// This macro is the core of the LDBG_OS() macros. It is used to print the +/// debug output with the given stream, level, type, file, and line number. +#define LDBG_OS_IMPL(TYPE_OR_LEVEL, LEVEL_OR_TYPE, CALLBACK, STREAM, FILE, \ + LINE) \ + if (::llvm::DebugFlag && \ + ::llvm::impl::ldbgIsCurrentDebugType(TYPE_OR_LEVEL, LEVEL_OR_TYPE)) { \ + ::llvm::impl::raw_ldbg_ostream LdbgOS{ \ + ::llvm::impl::computePrefix(TYPE_OR_LEVEL, FILE, LINE, LEVEL_OR_TYPE), \ + (STREAM), /*ShouldPrefixNextString=*/true, \ + /*ShouldEmitNewLineOnDestruction=*/true}; \ + CALLBACK(LdbgOS); \ + } + +#define LDBG_OS_TYPE_AND_LEVEL_AND_CALLBACK(TYPE, LEVEL, CALLBACK) \ + LDBG_OS_IMPL(static_cast(TYPE), LEVEL, CALLBACK, LDBG_STREAM, \ + __LLVM_FILE_NAME__, __LINE__) +#define LDBG_OS_LEVEL_OR_TYPE_AND_CALLBACK(LEVEL_OR_TYPE, CALLBACK) \ + LDBG_OS_IMPL(LDBG_GET_DEFAULT_TYPE_OR_LEVEL(LEVEL_OR_TYPE), LEVEL_OR_TYPE, \ + CALLBACK, LDBG_STREAM, __LLVM_FILE_NAME__, __LINE__) +#define LDBG_OS_CALLBACK(CALLBACK) \ + LDBG_OS_LEVEL_OR_TYPE_AND_CALLBACK(1, CALLBACK) + +// ---------------------------------------------------------------------------- +// General Helpers for the implementation above +// ---------------------------------------------------------------------------- + +/// Return the stringified macro as a StringRef. +/// Also, strip out potential surrounding quotes: this comes from an artifact of +/// the macro stringification, if DEBUG_TYPE is undefined we get the string +/// "DEBUG_TYPE", however if it is defined we get the string with the quotes. +/// For example if DEBUG_TYPE is "foo", we get "\"foo\"" but we want to return +/// "foo" here. +constexpr ::llvm::StringRef strip_quotes(const char *Str) { + ::llvm::StringRef S(Str); + if (Str[0] == '"' && Str[S.size() - 1] == '"') + return StringRef(Str + 1, S.size() - 2); + return S; +} + +/// Helper to provide the default level (=1) or type (=DEBUG_TYPE). This is used +/// when a single argument is passed to LDBG() (or LDBG_OS()), if it is an +/// integer we return DEBUG_TYPE and if it is a string we return 1. This fails +/// with a static_assert if we pass an integer and DEBUG_TYPE is not defined. +#define LDBG_GET_DEFAULT_TYPE_OR_LEVEL(LEVEL_OR_TYPE) \ + [](auto LevelOrType) { \ + if constexpr (std::is_integral_v) { \ + constexpr const char *DebugType = LDBG_GET_DEBUG_TYPE_STR(); \ + if constexpr (DebugType[0] == '"') \ + return ::llvm::impl::strip_quotes(DebugType); \ + else \ + static_assert(false, "DEBUG_TYPE is not defined"); \ + } else { \ + return 1; \ + } \ + }(LEVEL_OR_TYPE) + +/// Helpers to get DEBUG_TYPE as a StringRef, even when DEBUG_TYPE is not +/// defined (in which case it expands to "DEBUG_TYPE") +#define LDBG_GET_DEBUG_TYPE_STR__(X) #X +#define LDBG_GET_DEBUG_TYPE_STR_(X) LDBG_GET_DEBUG_TYPE_STR__(X) +#define LDBG_GET_DEBUG_TYPE_STR() LDBG_GET_DEBUG_TYPE_STR_(DEBUG_TYPE) + +/// Helper to call isCurrentDebugType with a StringRef. +static LLVM_ATTRIBUTE_UNUSED bool ldbgIsCurrentDebugType(StringRef Type, + int Level) { + return ::llvm::isCurrentDebugType(Type.str().c_str(), Level); +} +static LLVM_ATTRIBUTE_UNUSED bool ldbgIsCurrentDebugType(int Level, + StringRef Type) { + return ::llvm::isCurrentDebugType(Type.str().c_str(), Level); +} /// A raw_ostream that tracks `\n` and print the prefix after each /// newline. @@ -99,6 +235,7 @@ class LLVM_ABI raw_ldbg_ostream final : public raw_ostream { std::string Prefix; raw_ostream &Os; bool ShouldPrefixNextString; + bool ShouldEmitNewLineOnDestruction; /// Split the line on newlines and insert the prefix before each /// newline. Forward everything to the underlying stream. @@ -131,12 +268,17 @@ class LLVM_ABI raw_ldbg_ostream final : public raw_ostream { public: explicit raw_ldbg_ostream(std::string Prefix, raw_ostream &Os, - bool ShouldPrefixNextString = true) + bool ShouldPrefixNextString = true, + bool ShouldEmitNewLineOnDestruction = false) : Prefix(std::move(Prefix)), Os(Os), - ShouldPrefixNextString(ShouldPrefixNextString) { + ShouldPrefixNextString(ShouldPrefixNextString), + ShouldEmitNewLineOnDestruction(ShouldEmitNewLineOnDestruction) { SetUnbuffered(); } - ~raw_ldbg_ostream() final {} + ~raw_ldbg_ostream() final { + if (ShouldEmitNewLineOnDestruction) + Os << '\n'; + } /// Forward the current_pos method to the underlying stream. uint64_t current_pos() const final { return Os.tell(); } @@ -173,17 +315,17 @@ getShortFileName(const char *path) { /// "[DebugType] File:Line " /// Where the File is the file name without the path prefix. static LLVM_ATTRIBUTE_UNUSED std::string -computePrefix(const char *DebugType, const char *File, int Line, int Level) { +computePrefix(StringRef DebugType, const char *File, int Line, int Level) { std::string Prefix; raw_string_ostream OsPrefix(Prefix); - if (DebugType) + if (!DebugType.empty()) OsPrefix << "[" << DebugType << ":" << Level << "] "; OsPrefix << File << ":" << Line << " "; return OsPrefix.str(); } /// Overload allowing to swap the order of the DebugType and Level arguments. static LLVM_ATTRIBUTE_UNUSED std::string -computePrefix(int Level, const char *File, int Line, const char *DebugType) { +computePrefix(int Level, const char *File, int Line, StringRef DebugType) { return computePrefix(DebugType, File, Line, Level); } @@ -194,6 +336,7 @@ computePrefix(int Level, const char *File, int Line, const char *DebugType) { #define LDBG(...) \ for (bool _c = false; _c; _c = false) \ ::llvm::nulls() +#define LDBG_OS(...) #endif } // end namespace llvm diff --git a/llvm/unittests/Support/DebugLogTest.cpp b/llvm/unittests/Support/DebugLogTest.cpp index e087705b72586..da3851ed86b35 100644 --- a/llvm/unittests/Support/DebugLogTest.cpp +++ b/llvm/unittests/Support/DebugLogTest.cpp @@ -27,7 +27,7 @@ TEST(DebugLogTest, Basic) { { std::string str; raw_string_ostream os(str); - DEBUGLOG_WITH_STREAM_AND_TYPE(os, 0, nullptr) << "NoType"; + LDGB_STREAM_LEVEL_AND_TYPE(os, "", 0) << "NoType"; EXPECT_FALSE(StringRef(os.str()).starts_with('[')); EXPECT_TRUE(StringRef(os.str()).ends_with("NoType\n")); } @@ -36,8 +36,8 @@ TEST(DebugLogTest, Basic) { { std::string str; raw_string_ostream os(str); - DEBUGLOG_WITH_STREAM_AND_TYPE(os, 0, "A") << "A"; - DEBUGLOG_WITH_STREAM_AND_TYPE(os, 0, "B") << "B"; + LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "A") << "A"; + LDGB_STREAM_LEVEL_AND_TYPE(os, "B", 0) << "B"; EXPECT_TRUE(StringRef(os.str()).starts_with('[')); EXPECT_THAT(os.str(), AllOf(HasSubstr("A\n"), HasSubstr("B\n"))); } @@ -48,18 +48,18 @@ TEST(DebugLogTest, Basic) { raw_string_ostream os(str); // Just check that the macro doesn't result in dangling else. if (true) - DEBUGLOG_WITH_STREAM_AND_TYPE(os, 0, "A") << "A"; + LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "A") << "A"; else - DEBUGLOG_WITH_STREAM_AND_TYPE(os, 0, "A") << "B"; - DEBUGLOG_WITH_STREAM_AND_TYPE(os, 0, "B") << "B"; + LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "A") << "B"; + LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "B") << "B"; EXPECT_THAT(os.str(), AllOf(HasSubstr("A\n"), Not(HasSubstr("B\n")))); int count = 0; auto inc = [&]() { return ++count; }; EXPECT_THAT(count, Eq(0)); - DEBUGLOG_WITH_STREAM_AND_TYPE(os, 0, "A") << inc(); + LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "A") << inc(); EXPECT_THAT(count, Eq(1)); - DEBUGLOG_WITH_STREAM_AND_TYPE(os, 0, "B") << inc(); + LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "B") << inc(); EXPECT_THAT(count, Eq(1)); } } @@ -75,7 +75,7 @@ TEST(DebugLogTest, BasicWithLevel) { raw_string_ostream os(str); for (auto type : {"A", "B", "C", "D"}) for (int level : llvm::seq(0, 4)) - DEBUGLOG_WITH_STREAM_TYPE_FILE_AND_LINE(os, level, type, type, level) + LDBG_STREAM_LEVEL_TYPE_FILE_AND_LINE(os, level, type, type, level) << level; EXPECT_EQ(os.str(), "[A:0] A:0 0\n[A:1] A:1 1\n[A:2] A:2 2\n[A:3] A:3 " "3\n[B:0] B:0 0\n[B:1] B:1 1\n[C:0] C:0 0\n"); @@ -92,7 +92,7 @@ TEST(DebugLogTest, NegativeLevel) { raw_string_ostream os(str); for (auto type : {"A", "B"}) for (int level : llvm::seq(0, 2)) - DEBUGLOG_WITH_STREAM_TYPE_FILE_AND_LINE(os, level, type, type, level) + LDBG_STREAM_LEVEL_TYPE_FILE_AND_LINE(os, level, type, type, level) << level; EXPECT_EQ(os.str(), "[A:0] A:0 0\n[B:0] B:0 0\n[B:1] B:1 1\n"); } @@ -128,6 +128,115 @@ TEST(DebugLogTest, DestructorPrefix) { // After destructors, nothing should have been printed. EXPECT_EQ(os.str(), ""); } + +TEST(DebugLogTest, LDBG_MACROS) { + llvm::DebugFlag = true; + static const char *DT[] = {"A:3", "B:2"}; + setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0])); + std::string Str; + raw_string_ostream DebugOs(Str); + std::string StrExpected; + raw_string_ostream ExpectedOs(StrExpected); +#undef LDBG_STREAM +#define LDBG_STREAM DebugOs +#define DEBUG_TYPE "A" + LDBG() << "Hello, world!"; + ExpectedOs << "[A:1] " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1) + << " Hello, world!\n"; + EXPECT_EQ(DebugOs.str(), ExpectedOs.str()); + Str.clear(); + StrExpected.clear(); + + // Test with a level, no type. + LDBG(2) << "Hello, world!"; + ExpectedOs << "[A:2] " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1) + << " Hello, world!\n"; + EXPECT_EQ(DebugOs.str(), ExpectedOs.str()); + Str.clear(); + StrExpected.clear(); + +// Now the type will be explicit, check we don't use DEBUG_TYPE. +#undef DEBUG_TYPE + + // Test with a type + LDBG("B") << "Hello, world!"; + ExpectedOs << "[B:1] " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1) + << " Hello, world!\n"; + EXPECT_EQ(DebugOs.str(), ExpectedOs.str()); + Str.clear(); + StrExpected.clear(); + + // Test with a type and a level + LDBG("B", 2) << "Hello, world!"; + ExpectedOs << "[B:2] " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1) + << " Hello, world!\n"; + EXPECT_EQ(DebugOs.str(), ExpectedOs.str()); + Str.clear(); + StrExpected.clear(); + + // Test with a type not enabled. + LDBG("C", 1) << "Hello, world!"; + EXPECT_EQ(DebugOs.str(), ""); + + // Test with a level not enabled. + LDBG("B", 3) << "Hello, world!"; + EXPECT_EQ(DebugOs.str(), ""); +} + +TEST(DebugLogTest, LDBG_OS_MACROS) { + llvm::DebugFlag = true; + static const char *DT[] = {"A:3", "B:2"}; + setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0])); + std::string Str; + raw_string_ostream DebugOs(Str); + std::string StrExpected; + raw_string_ostream ExpectedOs(StrExpected); +#undef LDBG_STREAM +#define LDBG_STREAM DebugOs +#define DEBUG_TYPE "A" + LDBG_OS([](raw_ostream &Os) { Os << "Hello, world!"; }); + ExpectedOs << "[A:1] " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1) + << " Hello, world!\n"; + EXPECT_EQ(DebugOs.str(), ExpectedOs.str()); + Str.clear(); + StrExpected.clear(); + + // Test with a level, no type. + LDBG_OS(2, [](raw_ostream &Os) { Os << "Hello, world!"; }); + ExpectedOs << "[A:2] " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1) + << " Hello, world!\n"; + EXPECT_EQ(DebugOs.str(), ExpectedOs.str()); + Str.clear(); + StrExpected.clear(); + +// Now the type will be explicit, check we don't use DEBUG_TYPE. +#undef DEBUG_TYPE + + // Test with a type. + LDBG_OS("B", [](raw_ostream &Os) { Os << "Hello, world!"; }); + ExpectedOs << "[B:1] " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1) + << " Hello, world!\n"; + EXPECT_EQ(DebugOs.str(), ExpectedOs.str()); + Str.clear(); + StrExpected.clear(); + + // Test with a type and a level + LDBG_OS("B", 2, [](raw_ostream &Os) { Os << "Hello, world!"; }); + ExpectedOs << "[B:2] " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1) + << " Hello, world!\n"; + EXPECT_EQ(DebugOs.str(), ExpectedOs.str()); + Str.clear(); + StrExpected.clear(); + + // Test with a type not enabled. + LDBG_OS("C", 1, [](raw_ostream &Os) { Os << "Hello, world!"; }); + EXPECT_EQ(DebugOs.str(), ""); + + // Test with a level not enabled. + LDBG_OS("B", 3, [](raw_ostream &Os) { Os << "Hello, world!"; }); + EXPECT_EQ(DebugOs.str(), ""); +} + #else TEST(DebugLogTest, Basic) { // LDBG should be compiled out in NDEBUG, so just check it compiles and has diff --git a/mlir/lib/Dialect/Transform/IR/TransformOps.cpp b/mlir/lib/Dialect/Transform/IR/TransformOps.cpp index aba6178a2ea6c..132ed815c354e 100644 --- a/mlir/lib/Dialect/Transform/IR/TransformOps.cpp +++ b/mlir/lib/Dialect/Transform/IR/TransformOps.cpp @@ -1151,7 +1151,7 @@ transform::CollectMatchingOp::apply(transform::TransformRewriter &rewriter, std::optional maybeFailure; for (Operation *root : state.getPayloadOps(getRoot())) { WalkResult walkResult = root->walk([&](Operation *op) { - LDBG(1, DEBUG_TYPE_MATCHER) + LDBG(DEBUG_TYPE_MATCHER, 1) << "matching " << OpWithFlags(op, OpPrintingFlags().assumeVerified().skipRegions()) << " @" << op; @@ -1166,7 +1166,7 @@ transform::CollectMatchingOp::apply(transform::TransformRewriter &rewriter, if (diag.isDefiniteFailure()) return WalkResult::interrupt(); if (diag.isSilenceableFailure()) { - LDBG(1, DEBUG_TYPE_MATCHER) << "matcher " << matcher.getName() + LDBG(DEBUG_TYPE_MATCHER, 1) << "matcher " << matcher.getName() << " failed: " << diag.getMessage(); return WalkResult::advance(); } @@ -1298,7 +1298,7 @@ transform::ForeachMatchOp::apply(transform::TransformRewriter &rewriter, if (!getRestrictRoot() && op == root) return WalkResult::advance(); - LDBG(1, DEBUG_TYPE_MATCHER) + LDBG(DEBUG_TYPE_MATCHER, 1) << "matching " << OpWithFlags(op, OpPrintingFlags().assumeVerified().skipRegions()) << " @" << op; @@ -1314,7 +1314,7 @@ transform::ForeachMatchOp::apply(transform::TransformRewriter &rewriter, if (diag.isDefiniteFailure()) return WalkResult::interrupt(); if (diag.isSilenceableFailure()) { - LDBG(1, DEBUG_TYPE_MATCHER) << "matcher " << matcher.getName() + LDBG(DEBUG_TYPE_MATCHER, 1) << "matcher " << matcher.getName() << " failed: " << diag.getMessage(); continue; } @@ -2165,10 +2165,10 @@ DiagnosedSilenceableFailure transform::MatchOperationEmptyOp::matchOperation( ::std::optional<::mlir::Operation *> maybeCurrent, transform::TransformResults &results, transform::TransformState &state) { if (!maybeCurrent.has_value()) { - LDBG(1, DEBUG_TYPE_MATCHER) << "MatchOperationEmptyOp success"; + LDBG(DEBUG_TYPE_MATCHER, 1) << "MatchOperationEmptyOp success"; return DiagnosedSilenceableFailure::success(); } - LDBG(1, DEBUG_TYPE_MATCHER) << "MatchOperationEmptyOp failure"; + LDBG(DEBUG_TYPE_MATCHER, 1) << "MatchOperationEmptyOp failure"; return emitSilenceableError() << "operation is not empty"; }