From 49c0ed297f7ced606d44830b3626e8aa9e9996a0 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Tue, 14 Jun 2022 07:18:12 -0400 Subject: [PATCH 1/2] common_funcs: Add CITRA_NO_INLINE --- src/common/common_funcs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 1420675d4..446965e90 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -28,6 +28,12 @@ #define FORCE_INLINE inline __attribute__((always_inline)) #endif +#ifdef _MSC_VER +#define CITRA_NO_INLINE __declspec(noinline) +#else +#define CITRA_NO_INLINE __attribute__((noinline)) +#endif + #ifndef _MSC_VER #ifdef ARCHITECTURE_x86_64 From edbe7600f588638a39655b64c3390944c752911a Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Tue, 14 Jun 2022 07:21:34 -0400 Subject: [PATCH 2/2] common/assert: Use noinline lambda instead of a wrapper template MSVC now supports specifying __declspec on lambda functions --- src/common/assert.h | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/common/assert.h b/src/common/assert.h index 2c7216464..1533cb569 100644 --- a/src/common/assert.h +++ b/src/common/assert.h @@ -10,41 +10,43 @@ // For asserts we'd like to keep all the junk executed when an assert happens away from the // important code in the function. One way of doing this is to put all the relevant code inside a -// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to -// specify __declspec on lambda functions, so what we do instead is define a noinline wrapper -// template that calls the lambda. This seems to generate an extra instruction at the call-site -// compared to the ideal implementation (which wouldn't support ASSERT_MSG parameters), but is good -// enough for our purposes. -template -#if defined(_MSC_VER) -[[msvc::noinline, noreturn]] -#elif defined(__GNUC__) -[[gnu::cold, gnu::noinline, noreturn]] -#endif -static void -assert_noinline_call(const Fn& fn) { - fn(); - Crash(); - exit(1); // Keeps GCC's mouth shut about this actually returning -} +// lambda and force the compiler to not inline it. #define ASSERT(_a_) \ do \ if (!(_a_)) { \ - assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \ + []() CITRA_NO_INLINE { \ + LOG_CRITICAL(Debug, "Assertion Failed!"); \ + Crash(); \ + exit(1); \ + }(); \ } \ while (0) #define ASSERT_MSG(_a_, ...) \ do \ if (!(_a_)) { \ - assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \ + [&]() CITRA_NO_INLINE { \ + LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \ + Crash(); \ + exit(1); \ + }(); \ } \ while (0) -#define UNREACHABLE() assert_noinline_call([] { LOG_CRITICAL(Debug, "Unreachable code!"); }) +#define UNREACHABLE() \ + ([]() CITRA_NO_INLINE { \ + LOG_CRITICAL(Debug, "Unreachable code!"); \ + Crash(); \ + exit(1); \ + }()) + #define UNREACHABLE_MSG(...) \ - assert_noinline_call([&] { LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); }) + ([&]() CITRA_NO_INLINE { \ + LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); \ + Crash(); \ + exit(1); \ + }()) #ifdef _DEBUG #define DEBUG_ASSERT(_a_) ASSERT(_a_)