]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Add support for giving compilers (and static analyzers) hints about
authorHans Kristian Rosbach <hk-git@circlestorm.org>
Sun, 3 Nov 2024 19:27:19 +0000 (20:27 +0100)
committerHans Kristian Rosbach <hk-git@circlestorm.org>
Tue, 11 Feb 2025 22:21:32 +0000 (23:21 +0100)
value ranges of variables, allowing them to better optimize the code.
Adds Assume() and AssertHint() macros.

zbuild.h

index 157ab6ffedc1ae8b4693350f3dfd4e7b034082b4..33a4058765f2d456700664510e46663c4fe36f17 100644 (file)
--- a/zbuild.h
+++ b/zbuild.h
 #  include <stdio.h>
    extern int Z_INTERNAL z_verbose;
    extern void Z_INTERNAL z_error(const char *m);
-#  define Assert(cond, msg) {int _cond = (cond); if (!_cond) z_error(msg);}
 #  define Trace(x) {if (z_verbose >= 0) fprintf x;}
 #  define Tracev(x) {if (z_verbose > 0) fprintf x;}
 #  define Tracevv(x) {if (z_verbose > 1) fprintf x;}
 #  define Tracec(c, x) {if (z_verbose > 0 && (c)) fprintf x;}
 #  define Tracecv(c, x) {if (z_verbose > 1 && (c)) fprintf x;}
 #else
-#  define Assert(cond, msg)
 #  define Trace(x)
 #  define Tracev(x)
 #  define Tracevv(x)
 #  define Tracecv(c, x)
 #endif
 
+/* Prepare compiler-specific assume intrinsics */
+#if defined(__clang__) && __clang_major__ >= 4
+  #define z_assume(...) do { __builtin_assume(__VA_ARGS__); } while(0)
+#elif defined(__GNUC__) && __GNUC__ >= 13
+  #define z_assume(...) __attribute__((__assume__(__VA_ARGS__)))
+#elif defined(_MSC_VER) && _MSC_VER >= 1700
+  #define z_assume(...) do { __assume(__VA_ARGS__); } while(0)
+#else
+  #define z_assume(...)
+#endif
+/*
+   Assume     - Run check in Debug builds, send hint to compiler in Release builds.
+   Assert     - Run check in Debug builds
+   AssertHint - Run check in Debug builds, send hint to compiler in Release builds.
+   Both Assert types require a second parameter msg containing an error message.
+
+   The Assume(cond) and AssertHint(cond,msg) macros provides hints to compiler and
+   static analyzers about what value range is valid for a variable, helping them
+   better understand and optimize for real use.
+   To ensure this does not hide bugs, compilation in debug mode will replace hinting
+   with assert checks of the hint, and will throw an error on failed checks.
+
+   Example:
+    void process_buffer(char* buf, size_t len) {
+      Assume(len <= 1024);  // Hint to compiler about maximum size
+      ...
+    }
+*/
+#ifdef ZLIB_DEBUG
+#  define Assert(cond, msg)     {int _cond = (cond); if (!_cond) z_error(msg);}
+#  define AssertHint(cond, msg) Assert(cond,msg)
+#  define Assume(cond)          Assert(cond, "Value assumption failed")
+#else
+#  define Assert(cond, msg)
+#  define AssertHint(cind, msg) z_assume(cond)
+#  define Assume(cond)          z_assume(cond)
+#endif
+
 /* OPTIMAL_CMP values determine the comparison width:
  * 64: Best for 64-bit architectures with unaligned access
  * 32: Best for 32-bit architectures with unaligned access