diff --git a/base/macros.hpp b/base/macros.hpp index 222a405301..d965266fe4 100644 --- a/base/macros.hpp +++ b/base/macros.hpp @@ -9,6 +9,15 @@ namespace base { #define STRINGIFY(X) #X #define STRINGIFY_EXPANSION(X) STRINGIFY(X) +#define PRINCIPIA_CONCATENATE_SENTINEL(X) X##0x4C##45##4E##49##54##4E##45##53 +// True if X is #defined to nothing, false if X is #defined to an identifier or +// is not defined. This macro should not be used with macros that expand to +// something other than an identifier. +#define PRINCIPIA_MACRO_IS_EMPTY(X) \ + (PRINCIPIA_CONCATENATE_SENTINEL(X) == \ + ('S' << 000 | 'E' << 010 | 'N' << 020 | 'T' << 030 | 'I' << 040 | \ + 'N' << 050 | 'E' << 060 | 'L' << 070)) + // See http://goo.gl/2EVxN4 for a partial overview of compiler detection and // version macros. #if defined(_MSC_VER) && defined(__clang__) diff --git a/functions/sin_cos_test.cpp b/functions/sin_cos_test.cpp index 9a605e8980..9a1d524567 100644 --- a/functions/sin_cos_test.cpp +++ b/functions/sin_cos_test.cpp @@ -33,15 +33,13 @@ class SinCosTest : public ::testing::Test { }; // Defined in sin_cos.hpp -#if PRINCIPIA_USE_OSACA_SIN || PRINCIPIA_USE_OSACA_COS +#if PRINCIPIA_USE_OSACA // A convenient skeleton for analysing code with OSACA. Note that to speed-up // analysis, we disable all the other tests when using OSACA. TEST_F(SinCosTest, DISABLED_OSACA) { static_assert(PRINCIPIA_INLINE_SIN_COS == 1, "Must force inlining to use OSACA"); - static_assert(PRINCIPIA_USE_OSACA_SIN + PRINCIPIA_USE_OSACA_COS <= 1, - "Must use OSACA for at most one function"); auto osaca_sin = [](double const a) { return Sin(a); }; diff --git a/numerics/sin_cos.cpp b/numerics/sin_cos.cpp index b256da352e..b79dda44df 100644 --- a/numerics/sin_cos.cpp +++ b/numerics/sin_cos.cpp @@ -14,8 +14,6 @@ #include "numerics/polynomial_evaluators.hpp" #include "quantities/elementary_functions.hpp" -#define PRINCIPIA_USE_OSACA PRINCIPIA_USE_OSACA_SIN || PRINCIPIA_USE_OSACA_COS - #if PRINCIPIA_USE_OSACA #include "intel/iacaMarks.h" @@ -78,6 +76,7 @@ } } // To analyse it near x = 5: +#define OSACA_ANALYSED_FUNCTION f #define UNDER_OSACA_HYPOTHESES(expression) \ [&] { \ constexpr double x = 5; \ @@ -114,21 +113,34 @@ static bool OSACA_loop_terminator = false; -#define OSACA_FUNCTION_BEGIN(arg) \ - double OSACA_INPUT_QUALIFIER OSACA_input = arg; \ - IACA_VC64_START; \ - double OSACA_loop_carry = OSACA_input; \ - OSACA_loop: \ +#define OSACA_FUNCTION_BEGIN(arg) \ + double OSACA_INPUT_QUALIFIER OSACA_input = arg; \ + if constexpr (std::string_view(__func__) == \ + STRINGIFY_EXPANSION(OSACA_ANALYSED_FUNCTION)) { \ + IACA_VC64_START; \ + } \ + double OSACA_loop_carry = OSACA_input; \ + _Pragma("warning(push)"); \ + _Pragma("warning(disable : 4102)"); \ + OSACA_loop: \ + _Pragma("warning(pop)"); \ arg = OSACA_loop_carry -#define OSACA_RETURN(result) \ - OSACA_loop_carry = (result); \ - if (!OSACA_loop_terminator) { \ - goto OSACA_loop; \ - } \ - double volatile OSACA_result = OSACA_loop_carry; \ - IACA_VC64_END; \ - return OSACA_result +#define OSACA_RETURN(result) \ + do { \ + if constexpr (std::string_view(__func__) == \ + STRINGIFY_EXPANSION(OSACA_ANALYSED_FUNCTION)) { \ + OSACA_loop_carry = (result); \ + if (!OSACA_loop_terminator) { \ + goto OSACA_loop; \ + } \ + double volatile OSACA_result = OSACA_loop_carry; \ + IACA_VC64_END; \ + return OSACA_result; \ + } else { \ + return (result); \ + } \ + } while (false) #if OSACA_CARRY_LOOP_THROUGH_REGISTER #define OSACA_INPUT_QUALIFIER @@ -157,6 +169,8 @@ static bool OSACA_loop_terminator = false; #else // if !PRINCIPIA_USE_OSACA +#define OSACA_FUNCTION_BEGIN(arg) +#define OSACA_RETURN(result) return (result) #define OSACA_IF(condition) if (condition) #endif // PRINCIPIA_USE_OSACA @@ -165,22 +179,6 @@ static bool OSACA_loop_terminator = false; // Sin- and Cos-specific definitions: -#if PRINCIPIA_USE_OSACA_SIN -#define OSACA_SIN_BEGIN OSACA_FUNCTION_BEGIN -#define OSACA_RETURN_SIN OSACA_RETURN -#else -#define OSACA_SIN_BEGIN(arg) -#define OSACA_RETURN_SIN(result) return (result) -#endif - -#if PRINCIPIA_USE_OSACA_COS -#define OSACA_COS_BEGIN OSACA_FUNCTION_BEGIN -#define OSACA_RETURN_COS OSACA_RETURN -#else -#define OSACA_COS_BEGIN(arg) -#define OSACA_RETURN_COS(result) return (result) -#endif - #define UNDER_OSACA_HYPOTHESES(expression) \ [&] { \ constexpr bool UseHardwareFMA = true; \ @@ -444,7 +442,7 @@ Value CosImplementation(DoublePrecision const θ_reduced) { FORCE_INLINE(inline) #endif Value __cdecl Sin(Argument θ) { - OSACA_SIN_BEGIN(θ); + OSACA_FUNCTION_BEGIN(θ); DoublePrecision θ_reduced; std::int64_t quadrant; Reduce(θ, θ_reduced, quadrant); @@ -463,11 +461,11 @@ Value __cdecl Sin(Argument θ) { } } OSACA_IF(value != value) { - OSACA_RETURN_SIN(cr_sin(θ)); + OSACA_RETURN(cr_sin(θ)); } OSACA_ELSE_IF(quadrant & 0b10) { - OSACA_RETURN_SIN(-value); + OSACA_RETURN(-value); } else { - OSACA_RETURN_SIN(value); + OSACA_RETURN(value); } } @@ -475,7 +473,7 @@ Value __cdecl Sin(Argument θ) { FORCE_INLINE(inline) #endif Value __cdecl Cos(Argument θ) { - OSACA_COS_BEGIN(θ); + OSACA_FUNCTION_BEGIN(θ); DoublePrecision θ_reduced; std::int64_t quadrant; Reduce(θ, θ_reduced, quadrant); @@ -494,11 +492,11 @@ Value __cdecl Cos(Argument θ) { } } OSACA_IF(value != value) { - OSACA_RETURN_COS(cr_cos(θ)); + OSACA_RETURN(cr_cos(θ)); } OSACA_ELSE_IF(quadrant == 1 || quadrant == 2) { - OSACA_RETURN_COS(-value); + OSACA_RETURN(-value); } else { - OSACA_RETURN_COS(value); + OSACA_RETURN(value); } } diff --git a/numerics/sin_cos.hpp b/numerics/sin_cos.hpp index c4a4b6fc4a..7d3a7eeb01 100644 --- a/numerics/sin_cos.hpp +++ b/numerics/sin_cos.hpp @@ -8,8 +8,11 @@ namespace _sin_cos { namespace internal { #define PRINCIPIA_INLINE_SIN_COS 0 -#define PRINCIPIA_USE_OSACA_SIN 0 -#define PRINCIPIA_USE_OSACA_COS 0 +#define OSACA_ANALYSED_FUNCTION + +#if defined(OSACA_ANALYSED_FUNCTION) +#define PRINCIPIA_USE_OSACA !PRINCIPIA_MACRO_IS_EMPTY(OSACA_ANALYSED_FUNCTION) +#endif #if PRINCIPIA_INLINE_SIN_COS FORCE_INLINE(inline)