The following fixes one of the most annoying parts of non-working -ftrapv, namely that we only support >= word_mode trappings (quite annoying on 64bit archs where 'int' is not handled). At least on x86_64 libgcc has all the libfuncs available for SImode so the following patch arranges for them to be used. RFC because I don't know whether they are there by accident... (and thus the patch adds a requirement that is not met by other targets - but a link error is better than -ftrapv failure?)
The testcase relies on fork() to be able to capture both inline and out-of-line trapv sequences. dg-require-fork is unused but present, so I use it. I suppose we can restrict the testcase to a few targets manually as well - not sure, any preferences? At least the obvious testcase from PR52478 now works (until you hit constant folding ... see PR61893 I just opened). Bootstrap and regtest running on x86_64-unknown-linux-gnu, ok for trunk? Thanks, Richard. 2014-07-24 Richard Biener <[email protected]> PR middle-end/52478 * optabs.c (gen_int_libfunc): For -ftrapv libfuncs make sure to register SImode ones, not only >= word_mode ones. * expr.c (expand_expr_real_2): When expanding -ftrapv binops do not use OPTAB_LIB_WIDEN. * gcc.dg/torture/ftrapv-1.c: New testcase. Index: gcc/optabs.c =================================================================== *** gcc/optabs.c (revision 212970) --- gcc/optabs.c (working copy) *************** gen_int_libfunc (optab optable, const ch *** 5559,5571 **** enum machine_mode mode) { int maxsize = 2 * BITS_PER_WORD; if (GET_MODE_CLASS (mode) != MODE_INT) return; if (maxsize < LONG_LONG_TYPE_SIZE) maxsize = LONG_LONG_TYPE_SIZE; ! if (GET_MODE_CLASS (mode) != MODE_INT ! || GET_MODE_BITSIZE (mode) < BITS_PER_WORD || GET_MODE_BITSIZE (mode) > maxsize) return; gen_libfunc (optable, opname, suffix, mode); --- 5559,5575 ---- enum machine_mode mode) { int maxsize = 2 * BITS_PER_WORD; + int minsize = BITS_PER_WORD; if (GET_MODE_CLASS (mode) != MODE_INT) return; if (maxsize < LONG_LONG_TYPE_SIZE) maxsize = LONG_LONG_TYPE_SIZE; ! if (minsize > INT_TYPE_SIZE ! && (trapv_binoptab_p (optable) ! || trapv_unoptab_p (optable))) ! minsize = INT_TYPE_SIZE; ! if (GET_MODE_BITSIZE (mode) < minsize || GET_MODE_BITSIZE (mode) > maxsize) return; gen_libfunc (optable, opname, suffix, mode); Index: gcc/expr.c =================================================================== *** gcc/expr.c (revision 212970) --- gcc/expr.c (working copy) *************** expand_expr_real_2 (sepops ops, rtx targ *** 9212,9218 **** if (modifier == EXPAND_STACK_PARM) target = 0; temp = expand_binop (mode, this_optab, op0, op1, target, ! unsignedp, OPTAB_LIB_WIDEN); gcc_assert (temp); /* Bitwise operations do not need bitfield reduction as we expect their operands being properly truncated. */ --- 9212,9220 ---- if (modifier == EXPAND_STACK_PARM) target = 0; temp = expand_binop (mode, this_optab, op0, op1, target, ! unsignedp, ! trapv_binoptab_p (this_optab) ! ? OPTAB_LIB : OPTAB_LIB_WIDEN); gcc_assert (temp); /* Bitwise operations do not need bitfield reduction as we expect their operands being properly truncated. */ Index: gcc/testsuite/gcc.dg/torture/ftrapv-1.c =================================================================== *** gcc/testsuite/gcc.dg/torture/ftrapv-1.c (revision 0) --- gcc/testsuite/gcc.dg/torture/ftrapv-1.c (working copy) *************** *** 0 **** --- 1,37 ---- + /* { dg-do run } */ + /* { dg-additional-options "-ftrapv" } */ + /* { dg-require-effective-target trapping } */ + /* { dg-require-fork } */ + + #include <stdlib.h> + #include <unistd.h> + #include <sys/types.h> + #include <sys/wait.h> + + /* Verify SImode operations properly trap. PR middle-end/52478 */ + + /* Disallow inlining/cloning which would constant propagate and trigger + unrelated bugs. */ + + int __attribute__((noinline,noclone)) + iaddv (int a, int b) + { + return a + b; + } + + int main(void) + { + pid_t child = fork (); + int status = 0; + if (child == 0) + { + volatile int x = iaddv (__INT_MAX__, 1); + exit (0); + } + else if (child == -1) + return 0; + if (wait (&status) == child + && status == 0) + abort (); + return 0; + }
