Hello, Apologies if this has already been covered; I've searched the archives and not found anything.
I have some code that needs to perform signed division by a power of two with rounding towards minus infinity, i.e. it requires an arithmetic right shift. Now in the C specification, right shifting a signed integer is implementation defined. gcc's behaviour is implement this as a right shift, but it's possible that the code will be compiled on different platforms where the implemented behaviour is different. What I'm looking for is a way of expressing myself that will always give the correct behaviour on all c99 implementations, but that gcc will recognise as being equivalent to an arithmetic right shift, and hence implement as such. The most concise form that I've found so far is: const int d = 8; // 16, 32 etc x = y / d - ((y % d < 0) ? 1 : 0) although this still produces rather longer code (see example below). On a similar point, is there a good way get floats rounded to the nearest integer value rather than truncated. The following give the correct rounding behaviour (I'm only interested in +ve values), x = (int) (f + 0.5) although gets compiled as an addition of 0.5 followed by a truncation (again, see example). Please note that I'm not expecting gcc to recognise these specific cases, I'm just wondering if logic has been built in to recognise certain specific constructs and optimise them appropriately. Regards, Chris Example follows: # gcc -v Using built-in specs. Target: i586-suse-linux Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib --libexecdir=/usr/lib --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.1.2 --enable-ssp --disable-libssp --disable-libgcj --with-slibdir=/lib --with-system-zlib --enable-shared --enable-__cxa_atexit --enable-libstdcxx-allocator=new --program-suffix=-4.1 --enable-version-specific-runtime-libs --without-system-libunwind --with-cpu=generic --host=i586-suse-linux Thread model: posix gcc version 4.1.2 20061115 (prerelease) (SUSE Linux) # cat div.c #include <stdio.h> int div8(int x) { return (x / 8) - ((x % 8 < 0) ? 1 : 0); } int sft3(int x) { return x>>3; } int trnc(double d) { return (int) d; } int rnd(double d) { return (int) (d + 0.5); } int main (void) { int x = -5; fprintf(stderr, "%d\n", div8(x)); fprintf(stderr, "%d\n", div8(x)); fprintf(stderr, "%d\n", trnc(42.6)); fprintf(stderr, "%d\n", rnd(42.6)); return 0; } # gcc -O3 --save-temps div.c #cat div.s .file "div.c" .text .p2align 4,,15 .globl div8 .type div8, @function div8: pushl %ebp movl %esp, %ebp movl 8(%ebp), %edx popl %ebp movl %edx, %ecx sarl $31, %ecx shrl $29, %ecx leal (%ecx,%edx), %edx movl %edx, %eax andl $7, %edx subl %ecx, %edx sarl $3, %eax shrl $31, %edx subl %edx, %eax ret .size div8, .-div8 .p2align 4,,15 .globl sft3 .type sft3, @function sft3: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax popl %ebp sarl $3, %eax ret .size sft3, .-sft3 .p2align 4,,15 .globl trnc .type trnc, @function trnc: pushl %ebp movl %esp, %ebp subl $8, %esp fnstcw -2(%ebp) fldl 8(%ebp) movzwl -2(%ebp), %eax movb $12, %ah movw %ax, -4(%ebp) fldcw -4(%ebp) fistpl -8(%ebp) fldcw -2(%ebp) movl -8(%ebp), %eax leave ret .size trnc, .-trnc .section .rodata.cst4,"aM",@progbits,4 .align 4 .LC1: .long 1056964608 .text .p2align 4,,15 .globl rnd .type rnd, @function rnd: pushl %ebp movl %esp, %ebp subl $8, %esp fnstcw -2(%ebp) flds .LC1 faddl 8(%ebp) movzwl -2(%ebp), %eax movb $12, %ah movw %ax, -4(%ebp) fldcw -4(%ebp) fistpl -8(%ebp) fldcw -2(%ebp) movl -8(%ebp), %eax leave ret .size rnd, .-rnd .section .rodata.str1.1,"aMS",@progbits,1 .LC3: .string "%d\n" .text .p2align 4,,15 .globl main .type main, @function main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $20, %esp movl $-1, 8(%esp) movl $.LC3, 4(%esp) movl stderr, %eax movl %eax, (%esp) call fprintf movl $-1, 8(%esp) movl $.LC3, 4(%esp) movl stderr, %eax movl %eax, (%esp) call fprintf movl $42, 8(%esp) movl $.LC3, 4(%esp) movl stderr, %eax movl %eax, (%esp) call fprintf movl $43, 8(%esp) movl $.LC3, 4(%esp) movl stderr, %eax movl %eax, (%esp) call fprintf addl $20, %esp xorl %eax, %eax popl %ecx popl %ebp leal -4(%ecx), %esp ret .size main, .-main .ident "GCC: (GNU) 4.1.2 20061115 (prerelease) (SUSE Linux)" .section .note.GNU-stack,"",@progbits