[PATCH 4/4] bufhelp: use aligned type on all targets when alignment is known

Jussi Kivilinna <[email protected]> Wed, 29 Jul 2026 19:34:24 +0300
Newsgroups gmane.comp.encryption.gpg.libgcrypt.devel
Message-ID <[email protected]>
* cipher/bufhelp.h (buf_load32_maybe_unaligned)
(buf_store32_maybe_unaligned, buf_load64_maybe_unaligned)
(buf_store64_maybe_unaligned): New.
(buf_load32, buf_store32, buf_load64, buf_store64): Move compile-time
alignment check out of RISC-V specific path.
--

Compile-time alignment check was only used on RISC-V with Zicclsm.
Move check to common code, so that other targets also get access
through naturally aligned type when compiler can prove alignment.

Signed-off-by: Jussi Kivilinna <[email protected]>
---
 cipher/bufhelp.h | 133 +++++++++++++++++++++++++----------------------
 1 file changed, 72 insertions(+), 61 deletions(-)

diff --git a/cipher/bufhelp.h b/cipher/bufhelp.h
index 53516508..7b8ef209 100644
--- a/cipher/bufhelp.h
+++ b/cipher/bufhelp.h
@@ -145,96 +145,107 @@ typedef struct bufhelp_u64_aligned_s
     (defined(__riscv_zicclsm) && (__riscv_zicclsm >= 1000000)) && \
     defined(HAVE_GCC_INLINE_ASM_RISCV)
 
-static inline u32 buf_load32(const void *_buf)
-{
-  if (CONSTANT_P(((uintptr_t)_buf & 3) == 0) && ((uintptr_t)_buf & 3) == 0)
-    {
-      /* Compiler could determinate that this pointer is always aligned. */
-      return ((const bufhelp_u32_aligned_t *)_buf)->a;
-    }
-  else
-    {
-      u64 val;
-      asm ("lw %0, %1"
-	   : "=r" (val)
-	   : "m" (*((const bufhelp_u32_t *)_buf)));
-      return val;
-    }
+/* Functions for loading and storing potentially unaligned u64/u32 values on
+   RISC-V with Zicclsm extension.  */
+static inline u32 buf_load32_maybe_unaligned(const void *buf)
+{
+  u64 val;
+  asm ("lw %0, %1"
+       : "=r" (val)
+       : "m" (*((const bufhelp_u32_t *)buf)));
+  return val;
 }
 
-static inline void buf_store32(void *_buf, u32 val)
+static inline void buf_store32_maybe_unaligned(void *buf, u32 val)
 {
-  if (CONSTANT_P(((uintptr_t)_buf & 3) == 0) && ((uintptr_t)_buf & 3) == 0)
-    {
-      /* Compiler could determinate that this pointer is always aligned. */
-      ((bufhelp_u32_aligned_t *)_buf)->a = val;
-    }
-  else
-    {
-      asm ("sw %1, %0"
-	   : "=m" (*((bufhelp_u32_t *)_buf))
-	   : "r" (val));
-    }
+  asm ("sw %1, %0"
+       : "=m" (*((bufhelp_u32_t *)buf))
+       : "r" (val));
 }
 
-static inline u64 buf_load64(const void *_buf)
+static inline u64 buf_load64_maybe_unaligned(const void *buf)
 {
-  if (CONSTANT_P(((uintptr_t)_buf & 7) == 0) && ((uintptr_t)_buf & 7) == 0)
-    {
-      /* Compiler could determinate that this pointer is always aligned. */
-      return ((const bufhelp_u64_aligned_t *)_buf)->a;
-    }
-  else
-    {
-      u64 val;
-      asm ("ld %0, %1"
-	   : "=r" (val)
-	   : "m" (*((const bufhelp_u64_t *)_buf)));
-      return val;
-    }
+  u64 val;
+  asm ("ld %0, %1"
+       : "=r" (val)
+       : "m" (*((const bufhelp_u64_t *)buf)));
+  return val;
 }
 
-static inline void buf_store64(void *_buf, u64 val)
+static inline void buf_store64_maybe_unaligned(void *buf, u64 val)
 {
-  if (CONSTANT_P(((uintptr_t)_buf & 7) == 0) && ((uintptr_t)_buf & 7) == 0)
-    {
-      /* Compiler could determinate that this pointer is always aligned. */
-      ((bufhelp_u64_aligned_t *)_buf)->a = val;
-    }
-  else
-    {
-      asm ("sd %1, %0"
-	  : "=m" (*((bufhelp_u64_t *)_buf))
-	  : "r" (val));
-    }
+  asm ("sd %1, %0"
+       : "=m" (*((bufhelp_u64_t *)buf))
+       : "r" (val));
 }
 
 #else
 
-static inline u32 buf_load32(const void *_buf)
+/* Functions for loading and storing potentially unaligned u64/u32 values.  */
+static inline u32 buf_load32_maybe_unaligned(const void *buf)
 {
-  return ((const bufhelp_u32_t *)_buf)->a;
+  return ((const bufhelp_u32_t *)buf)->a;
 }
 
-static inline void buf_store32(void *_buf, u32 val)
+static inline void buf_store32_maybe_unaligned(void *buf, u32 val)
 {
-  bufhelp_u32_t *out = _buf;
+  bufhelp_u32_t *out = buf;
   out->a = val;
 }
 
-static inline u64 buf_load64(const void *_buf)
+static inline u64 buf_load64_maybe_unaligned(const void *buf)
 {
-  return ((const bufhelp_u64_t *)_buf)->a;
+  return ((const bufhelp_u64_t *)buf)->a;
 }
 
-static inline void buf_store64(void *_buf, u64 val)
+static inline void buf_store64_maybe_unaligned(void *buf, u64 val)
 {
-  bufhelp_u64_t *out = _buf;
+  bufhelp_u64_t *out = buf;
   out->a = val;
 }
 
 #endif
 
+
+/* Functions for loading and storing u64/u32 values, with aligned path
+   when pointer alignment can be detected at compile time.  */
+static inline u32 buf_load32(const void *buf)
+{
+  /* Check if pointer alignment is known at compile time. */
+  if (CONSTANT_P(((uintptr_t)buf & 3) == 0) && ((uintptr_t)buf & 3) == 0)
+    return ((const bufhelp_u32_aligned_t *)buf)->a;
+  else
+    return buf_load32_maybe_unaligned(buf);
+}
+
+static inline void buf_store32(void *buf, u32 val)
+{
+  /* Check if pointer alignment is known at compile time. */
+  if (CONSTANT_P(((uintptr_t)buf & 3) == 0) && ((uintptr_t)buf & 3) == 0)
+    ((bufhelp_u32_aligned_t *)buf)->a = val;
+  else
+    buf_store32_maybe_unaligned(buf, val);
+}
+
+static inline u64 buf_load64(const void *buf)
+{
+  /* Check if pointer alignment is known at compile time. */
+  if (CONSTANT_P(((uintptr_t)buf & 7) == 0) && ((uintptr_t)buf & 7) == 0)
+    return ((const bufhelp_u64_aligned_t *)buf)->a;
+  else
+    return buf_load64_maybe_unaligned(buf);
+}
+
+static inline void buf_store64(void *buf, u64 val)
+{
+  /* Check if pointer alignment is known at compile time. */
+  if (CONSTANT_P(((uintptr_t)buf & 7) == 0) && ((uintptr_t)buf & 7) == 0)
+    ((bufhelp_u64_aligned_t *)buf)->a = val;
+  else
+    buf_store64_maybe_unaligned(buf, val);
+}
+
+
 /* Functions for loading and storing unaligned u32 values of different
    endianness.  */
 static inline u32 buf_get_be32(const void *_buf)
-- 
2.53.0