From 3d8c84e17c71fb38e3769a9ea9d64ec4157a3c0b Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Mallo Date: Fri, 21 Jun 2024 16:58:04 +0200 Subject: [PATCH] Fix heap when size_t is not unsigned long long When the width of size_t doesn't match the width of the unsigned long long type, the number of leading zeros doesn't match, making the heap_get_move() function return incorrect values. This is the case on ARMv7 with 32 bits, where size_t is 32 bits but unsigned long long is 64 bits. We check the size of size_t to select which builtin we need. The sizeof operator cannot be used at preprocessing, so we rely on the optimizations to only leave the proper assembly instruction. Fixes: https://pm.bsc.es/gitlab/rarias/ovni/-/issues/193 --- src/include/heap.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/include/heap.h b/src/include/heap.h index 4f68a62..d88932e 100644 --- a/src/include/heap.h +++ b/src/include/heap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) +/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC) * SPDX-License-Identifier: GPL-3.0-or-later */ /* Author: David Alvarez @@ -112,6 +112,20 @@ heap_max(heap_head_t *head) return head->root; } +static inline int +leading_zeros(size_t x) +{ + /* Call and if()'s optimized by the compiler with -O2 */ + if (sizeof(size_t) == sizeof(unsigned int)) + return __builtin_clz(x); + else if (sizeof(size_t) == sizeof(unsigned long)) + return __builtin_clzl(x); + else if (sizeof(size_t) == sizeof(unsigned long long)) + return __builtin_clzll(x); + else + die("cannot find suitable size for __builtin_clz*"); +} + /* Get a move to reach a leaf */ static inline int heap_get_move(size_t *node /*out*/) @@ -119,8 +133,8 @@ heap_get_move(size_t *node /*out*/) size_t aux_node = *node; // Round to previous po2 - size_t base = (1ULL) << (sizeof(size_t) * 8 - - __builtin_clzll(aux_node) - 1); + int shift = sizeof(size_t) * 8 - leading_zeros(aux_node) - 1; + size_t base = 1ULL << shift; aux_node -= base / 2;