The following code generates the wrong result: -------------------- #include <stdio.h> int f(unsigned int x) { printf("%x %d\n", x, (int)x); return ((int)x) % 4; } int main(int argc, char *argv[]) { printf("%d\n", f((unsigned int)(-1))); return 0; } -------------------- I expect this: $ gcc-3.4.3 ctest33.c -Wall && ./a.out ffffffff -1 -1 and with gcc-4 and greater I get this: $ gcc-4.2.1 ctest33.c -Wall && ./a.out ffffffff -1 3 Why do I think this is a bug? Well, initially I thought I'd run into undefined behaviour, but on closer reading of the C spec it seems the behaviour should be implementation-defined, and gcc is not implementing the documented behaviour. Furthermore, gcc's behaviour is not consistent, as implementation-defined behaviour should be. The bug appears to be centered around conversion from unsigned to signed integers. We convert from unsigned to signed in f(), and the value passed is 0xffffffff. The result is therefore implementation-defined (C99 6.3.1.3), and gcc defines it (section 4.5 of the gcc docs) as: "For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type". I presume this means that the value is truncated to N bits and the result interpreted as twos-complement, which in this case should mean that (int)x is -1, and the expression is (-1 % 4), which has value -1. We can see from the printf output that (int)x has value -1. Since this is its implementation-defined value, it should have the same value in the expression (int)x % 4. Indeed, several minor variations of this code give the expected output. Substituting 0xffffffffU for x in the definition of f(), for example. Optimisation level has no effect. Bug also observed on i686-unknown-linux.
The difference is that we now generate f: .LFB2: andl $3, %edi movl %edi, %eax ret while previously we'd get the correct f: .LFB3: leal 3(%rdi), %eax cmpl $-1, %edi cmovg %edi, %eax andl $-4, %eax subl %eax, %edi movl %edi, %eax ret for int f(unsigned int x) { return ((int)x) % 4; } This is a problem in fold, as we get initially: ;; Function f (f) ;; enabled by -tree-original { return (int) x & 3; } which is wrong.
Mine.
Subject: Bug 34070 Author: rguenth Date: Mon Nov 12 14:16:05 2007 New Revision: 130098 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=130098 Log: 2007-11-12 Richard Guenther <rguenther@suse.de> PR middle-end/34070 * fold-const.c (fold_binary): If testing for non-negative operands with tree_expr_nonnegative_warnv_p make sure to use op0 which has all (sign) conversions retained. * gcc.c-torture/execute/pr34070-1.c: New testcase. * gcc.c-torture/execute/pr34070-2.c: Likewise. Added: trunk/gcc/testsuite/gcc.c-torture/execute/pr34070-1.c trunk/gcc/testsuite/gcc.c-torture/execute/pr34070-2.c Modified: trunk/gcc/ChangeLog trunk/gcc/fold-const.c trunk/gcc/testsuite/ChangeLog
Fixed for 4.3.0.
Subject: Bug 34070 Author: rguenth Date: Tue Jan 22 14:45:56 2008 New Revision: 131723 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=131723 Log: 2008-01-22 Richard Guenther <rguenther@suse.de> PR middle-end/34739 Backport from mainline 2008-01-16 Richard Guenther <rguenther@suse.de> PR c/34768 * c-typeck.c (common_pointer_type): Do not merge inconsistent type qualifiers for function types. 2007-11-12 Richard Guenther <rguenther@suse.de> PR middle-end/34070 * fold-const.c (fold_binary): If testing for non-negative operands with tree_expr_nonnegative_warnv_p make sure to use op0 which has all (sign) conversions retained. 2006-10-24 Richard Guenther <rguenther@suse.de> PR middle-end/28796 * builtins.c (fold_builtin_classify): Use HONOR_INFINITIES and HONOR_NANS instead of MODE_HAS_INFINITIES and MODE_HAS_NANS for deciding optimizations in consistency with fold-const.c (fold_builtin_unordered_cmp): Likewise. Added: branches/gcc-4_2-branch/gcc/testsuite/gcc.c-torture/execute/pr34070-1.c - copied unchanged from r130098, trunk/gcc/testsuite/gcc.c-torture/execute/pr34070-1.c branches/gcc-4_2-branch/gcc/testsuite/gcc.c-torture/execute/pr34070-2.c - copied unchanged from r130098, trunk/gcc/testsuite/gcc.c-torture/execute/pr34070-2.c branches/gcc-4_2-branch/gcc/testsuite/gcc.c-torture/execute/pr34768-1.c - copied unchanged from r131568, trunk/gcc/testsuite/gcc.c-torture/execute/pr34768-1.c branches/gcc-4_2-branch/gcc/testsuite/gcc.c-torture/execute/pr34768-2.c - copied unchanged from r131568, trunk/gcc/testsuite/gcc.c-torture/execute/pr34768-2.c branches/gcc-4_2-branch/gcc/testsuite/gcc.dg/pr28796-1.c - copied unchanged from r118001, trunk/gcc/testsuite/gcc.dg/pr28796-1.c branches/gcc-4_2-branch/gcc/testsuite/gcc.dg/pr28796-2.c - copied unchanged from r118001, trunk/gcc/testsuite/gcc.dg/pr28796-2.c Modified: branches/gcc-4_2-branch/gcc/ChangeLog branches/gcc-4_2-branch/gcc/builtins.c branches/gcc-4_2-branch/gcc/c-typeck.c branches/gcc-4_2-branch/gcc/fold-const.c branches/gcc-4_2-branch/gcc/testsuite/ChangeLog
Fixed on the 4.2 branch.
Closing 4.1 branch.