bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ffsl: optimization for non-GCC


From: Bruno Haible
Subject: ffsl: optimization for non-GCC
Date: Fri, 14 Oct 2011 02:19:59 +0200
User-agent: KMail/1.13.6 (Linux/2.6.37.6-0.5-desktop; KDE/4.6.0; x86_64; ; )

Before I added the previous optimization, I got this warning and code
on mingw:


$ gcc-3 -mno-cygwin -DHAVE_CONFIG_H -I. -I..  -DGNULIB_STRICT_CHECKING=1 
-I/usr/local/mingw/include -Wall -S -O2 ffsl.c
In file included from ffsl.c:3:
ffsl.h: In function `ffsl':
ffsl.h:44: warning: right shift count >= width of type

$ cat ffsl.s
        .file   "ffsl.c"
        .text
        .p2align 4,,15
.globl _ffsl
        .def    _ffsl;  .scl    2;      .type   32;     .endef
_ffsl:
        pushl   %ebp
        xorl    %eax, %eax
        movl    %esp, %ebp
        movl    8(%ebp), %edx
        testl   %edx, %edx
        je      L1
        xorl    %ecx, %ecx
        bsfl    %edx, %eax
        sete    %cl
        negl    %ecx
        orl     %ecx, %eax
        incl    %eax
L1:
        popl    %ebp
        ret

This is considerably longer than necessary. With the patch below, the
code boils down to

$ cat ffsl.s
        .file   "ffsl.c"
        .text
        .p2align 4,,15
.globl _ffsl
        .def    _ffsl;  .scl    2;      .type   32;     .endef
_ffsl:
        pushl   %ebp
        xorl    %edx, %edx
        movl    %esp, %ebp
        bsfl    8(%ebp), %eax
        sete    %dl
        negl    %edx
        popl    %ebp
        orl     %edx, %eax
        incl    %eax
        ret

Also, the warning goes away by use of a valid shift count, even in dead code.

And let me add a comment about a tempting code change that would provoke a
test failure on Solaris 10/x86 with "cc -O" (only when -O is present - a
clear indication for a compiler bug).


2011-10-13  Bruno Haible  <address@hidden>

        ffsl: Optimize on 32-bit platforms.
        * lib/ffsl.h (FUNC): If TYPE has the same representation as 'int', just
        use ffs() without a loop.

*** lib/ffsl.h.orig     Fri Oct 14 02:10:41 2011
--- lib/ffsl.h  Fri Oct 14 02:09:43 2011
***************
*** 34,51 ****
  #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined 
GCC_BUILTIN
    return GCC_BUILTIN (i);
  #else
!   int result = 0;
!   unsigned TYPE j = i;
! 
!   /* GCC has __builtin_ffs, but it is limited to int.  */
!   if (!i)
!     return 0;
!   while (1)
      {
!       if ((unsigned int) j)
!         return result + ffs ((unsigned int) j);
!       j >>= CHAR_BIT * sizeof (unsigned int);
!       result += CHAR_BIT * sizeof (unsigned int);
      }
  #endif
  }
--- 34,67 ----
  #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined 
GCC_BUILTIN
    return GCC_BUILTIN (i);
  #else
!   if (sizeof (TYPE) == sizeof (int))
!     return ffs (i);
!   else
      {
!       unsigned TYPE j = i;
!       /* Split j into chunks, and look at one chunk after the other.  */
!       /* Define chunk_bits so as to avoid a GCC warning
!            "right shift count >= width of type"
!          if sizeof (TYPE) == sizeof (int).  */
!       enum
!         {
!           chunk_bits = (sizeof (TYPE) != sizeof (int)
!                         ? CHAR_BIT * sizeof (unsigned int)
!                         : 0)
!         };
!       int result = 0;
! 
!       /* It is tempting to write  if (!j)  here, but if we do this,
!          Solaris 10/x86 "cc -O" miscompiles the code.  */
!       if (!i)
!         return 0;
!       while (1)
!         {
!           if ((unsigned int) j)
!             return result + ffs ((unsigned int) j);
!           j >>= chunk_bits;
!           result += chunk_bits;
!         }
      }
  #endif
  }
-- 
In memoriam Bekir Çoban-zade <http://en.wikipedia.org/wiki/Bekir_Çoban-zade>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]