aboutsummaryrefslogtreecommitdiffstats
path: root/common/opthelpers.h
diff options
context:
space:
mode:
Diffstat (limited to 'common/opthelpers.h')
-rw-r--r--common/opthelpers.h92
1 files changed, 73 insertions, 19 deletions
diff --git a/common/opthelpers.h b/common/opthelpers.h
index 58578c15..596c2455 100644
--- a/common/opthelpers.h
+++ b/common/opthelpers.h
@@ -1,39 +1,93 @@
#ifndef OPTHELPERS_H
#define OPTHELPERS_H
+#include <cstdint>
+#include <utility>
+#include <memory>
+
#ifdef __has_builtin
#define HAS_BUILTIN __has_builtin
#else
#define HAS_BUILTIN(x) (0)
#endif
+#ifdef __has_cpp_attribute
+#define HAS_ATTRIBUTE __has_cpp_attribute
+#else
+#define HAS_ATTRIBUTE(x) (0)
+#endif
+
#ifdef __GNUC__
-/* LIKELY optimizes the case where the condition is true. The condition is not
- * required to be true, but it can result in more optimal code for the true
- * path at the expense of a less optimal false path.
- */
-#define LIKELY(x) (__builtin_expect(!!(x), !false))
-/* The opposite of LIKELY, optimizing the case where the condition is false. */
-#define UNLIKELY(x) (__builtin_expect(!!(x), false))
-/* Unlike LIKELY, ASSUME requires the condition to be true or else it invokes
- * undefined behavior. It's essentially an assert without actually checking the
- * condition at run-time, allowing for stronger optimizations than LIKELY.
+#define force_inline [[gnu::always_inline]] inline
+#elif defined(_MSC_VER)
+#define force_inline __forceinline
+#else
+#define force_inline inline
+#endif
+
+/* Unlike the likely attribute, ASSUME requires the condition to be true or
+ * else it invokes undefined behavior. It's essentially an assert without
+ * actually checking the condition at run-time, allowing for stronger
+ * optimizations than the likely attribute.
*/
#if HAS_BUILTIN(__builtin_assume)
#define ASSUME __builtin_assume
+#elif defined(_MSC_VER)
+#define ASSUME __assume
+#elif __has_attribute(assume)
+#define ASSUME(x) [[assume(x)]]
+#elif HAS_BUILTIN(__builtin_unreachable)
+#define ASSUME(x) do { if(x) break; __builtin_unreachable(); } while(0)
+#else
+#define ASSUME(x) ((void)0)
+#endif
+
+/* This shouldn't be needed since unknown attributes are ignored, but older
+ * versions of GCC choke on the attribute syntax in certain situations.
+ */
+#if HAS_ATTRIBUTE(likely)
+#define LIKELY [[likely]]
+#define UNLIKELY [[unlikely]]
#else
-#define ASSUME(x) do { if(!(x)) __builtin_unreachable(); } while(0)
+#define LIKELY
+#define UNLIKELY
#endif
-#else /* __GNUC__ */
+namespace al {
-#define LIKELY(x) (!!(x))
-#define UNLIKELY(x) (!!(x))
-#ifdef _MSC_VER
-#define ASSUME __assume
+template<typename T>
+constexpr std::underlying_type_t<T> to_underlying(T e) noexcept
+{ return static_cast<std::underlying_type_t<T>>(e); }
+
+[[noreturn]] inline void unreachable()
+{
+#if HAS_BUILTIN(__builtin_unreachable)
+ __builtin_unreachable();
#else
-#define ASSUME(x) ((void)0)
-#endif /* _MSC_VER */
-#endif /* __GNUC__ */
+ ASSUME(false);
+#endif
+}
+
+template<std::size_t alignment, typename T>
+force_inline constexpr auto assume_aligned(T *ptr) noexcept
+{
+#ifdef __cpp_lib_assume_aligned
+ return std::assume_aligned<alignment,T>(ptr);
+#elif HAS_BUILTIN(__builtin_assume_aligned)
+ return static_cast<T*>(__builtin_assume_aligned(ptr, alignment));
+#elif defined(_MSC_VER)
+ constexpr std::size_t alignment_mask{(1<<alignment) - 1};
+ if((reinterpret_cast<std::uintptr_t>(ptr)&alignment_mask) == 0)
+ return ptr;
+ __assume(0);
+#elif defined(__ICC)
+ __assume_aligned(ptr, alignment);
+ return ptr;
+#else
+ return ptr;
+#endif
+}
+
+} // namespace al
#endif /* OPTHELPERS_H */