Commit: a621f332d809b2d77f327c4ae7bfb6e28c2e74b2
Parent: df3f879fbdd93cb79673b3031d13ceda1552aba1
Author: Randy Palamar
Date: Mon, 17 Feb 2025 05:19:47 -0700
intrinsics: avoid UB when using CLZ/CTZ
Despite using the compiler builtins and the underlying assembly
instruction not caring if the value is 0 it is still undefined
behaviour in C to call these functions with an argument of 0.
Add a little check to workaround this which will be optimized out
and any optimization level other that 0. See: https://godbolt.org/z/aoGx7PP5K
Diffstat:
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/intrinsics.c b/intrinsics.c
@@ -1,11 +1,25 @@
#define FORCE_INLINE inline __attribute__((always_inline))
/* TODO(rnp): msvc probably won't build this but there are other things preventing that as well */
-#define clz_u32(a) __builtin_clz(a)
-#define ctz_u32(a) __builtin_ctz(a)
#define sqrt_f32(a) __builtin_sqrtf(a)
#define atan2_f32(y, x) __builtin_atan2f(y, x)
+static FORCE_INLINE u32
+clz_u32(u32 a)
+{
+ u32 result = 32;
+ if (a) result = __builtin_clz(a);
+ return result;
+}
+
+static FORCE_INLINE u32
+ctz_u32(u32 a)
+{
+ u32 result = 32;
+ if (a) result = __builtin_ctz(a);
+ return result;
+}
+
#ifdef __ARM_ARCH_ISA_A64
/* TODO? debuggers just loop here forever and need a manual PC increment (step over) */
#define debugbreak() asm volatile ("brk 0xf000")
diff --git a/util.h b/util.h
@@ -21,8 +21,6 @@
#endif
#endif
-#include "intrinsics.c"
-
#ifdef _DEBUG
#ifdef _WIN32
#define DEBUG_EXPORT __declspec(dllexport)
@@ -70,6 +68,8 @@ typedef ptrdiff_t size;
typedef ptrdiff_t iptr;
typedef size_t uptr;
+#include "intrinsics.c"
+
typedef struct { u8 *beg, *end; } Arena;
typedef struct { Arena *arena; u8 *old_beg; } TempArena;