The following fixes the second bug you'll hit very fast when writing
testcases for -ftrapv (maybe not so often in "real" scenarios).  There
are several places in the optimization pipeline where after constant 
folding we fail to generate trapping instructions.

The simplest solution as implemented below is to avoid constant-folding
trapping instructions.

Another solution would be to make sure to fold to
(__builtin_trap (), value), but I didn't try that (and it's not
what the existing mitigation in folding of negates does).

For bit-ccp I decided to say it's not its business to re-invent
constant folding (so only handle partially constant values).

For CSE and simplify-rtx.c we need to make sure to _not_ record
non-trapping REG_EQUAL variants, that is, when expanding
a + b with overflow trapping we may not attach a simple
(plus:SI reg1 reg2) REG_EQUAL note to the libcall.  (similar
to signed vs. unsigned ops there doesn't seem to be a way
to make this plus "trapping")

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Note that bootstrap with -ftrapv currently fails (not because
of trapping but because ICEing in expr.c:9218 - probably a fallout
of my earlier patch ... bah).

Ok for trunk?

Thanks,
Richard.

2014-07-29  Richard Biener  <rguent...@suse.de>

        PR middle-end/61893
        * fold-const.c (const_binop): For trapping overflow types return
        NULL_TREE if the operation overflowed.
        * tree-ssa-ccp.c (bit_value_unop): Do not do constant folding.
        (bit_value_binop): Likewise.
        * optabs.c (emit_libcall_block_1): Allow a NULL_RTX equiv.
        (expand_binop): For -ftrapv optabs do not record an REG_EQUAL
        note.
        (expand_unop): Likewise.

Index: gcc/fold-const.c
===================================================================
*** gcc/fold-const.c    (revision 213119)
--- gcc/fold-const.c    (working copy)
*************** const_binop (enum tree_code code, tree a
*** 1122,1128 ****
    STRIP_NOPS (arg2);
  
    if (TREE_CODE (arg1) == INTEGER_CST)
!     return int_const_binop (code, arg1, arg2);
  
    if (TREE_CODE (arg1) == REAL_CST)
      {
--- 1122,1136 ----
    STRIP_NOPS (arg2);
  
    if (TREE_CODE (arg1) == INTEGER_CST)
!     {
!       tree res = int_const_binop (code, arg1, arg2);
!       if (res
!         && TYPE_OVERFLOW_TRAPS (TREE_TYPE (arg1))
!         && TREE_OVERFLOW (res)
!         && !TREE_OVERFLOW (arg1) && !TREE_OVERFLOW (arg2))
!       return NULL_TREE;
!       return res;
!     }
  
    if (TREE_CODE (arg1) == REAL_CST)
      {
Index: gcc/tree-ssa-ccp.c
===================================================================
*** gcc/tree-ssa-ccp.c  (revision 213119)
--- gcc/tree-ssa-ccp.c  (working copy)
*************** bit_value_unop (enum tree_code code, tre
*** 1456,1463 ****
    widest_int value, mask;
    prop_value_t val;
  
!   if (rval.lattice_val == UNDEFINED)
!     return rval;
  
    gcc_assert ((rval.lattice_val == CONSTANT
               && TREE_CODE (rval.value) == INTEGER_CST)
--- 1456,1474 ----
    widest_int value, mask;
    prop_value_t val;
  
!   if (rval.lattice_val == UNDEFINED
!       /* If the value is fully known constants assume that
!        earlier simplification failed for a reason, for example
!        due to -ftrapv.  */
!       || (rval.lattice_val == CONSTANT
!         && TREE_CODE (rval.value) == INTEGER_CST
!         && rval.mask == -1))
!     {
!       val.lattice_val = VARYING;
!       val.value = NULL_TREE;
!       val.mask = -1;
!       return val;
!     }
  
    gcc_assert ((rval.lattice_val == CONSTANT
               && TREE_CODE (rval.value) == INTEGER_CST)
*************** bit_value_binop (enum tree_code code, tr
*** 1492,1498 ****
    prop_value_t val;
  
    if (r1val.lattice_val == UNDEFINED
!       || r2val.lattice_val == UNDEFINED)
      {
        val.lattice_val = VARYING;
        val.value = NULL_TREE;
--- 1503,1518 ----
    prop_value_t val;
  
    if (r1val.lattice_val == UNDEFINED
!       || r2val.lattice_val == UNDEFINED
!       /* If both values are fully known constants assume that
!        earlier simplification failed for a reason, for example
!        due to -ftrapv.  */
!       || (r1val.lattice_val == CONSTANT
!         && TREE_CODE (r1val.value) == INTEGER_CST
!         && r1val.mask == 0
!         && r2val.lattice_val == CONSTANT
!         && TREE_CODE (r2val.value) == INTEGER_CST
!         && r2val.mask == 0))
      {
        val.lattice_val = VARYING;
        val.value = NULL_TREE;
*************** bit_value_binop (enum tree_code code, tr
*** 1506,1511 ****
--- 1526,1532 ----
    gcc_assert ((r2val.lattice_val == CONSTANT
               && TREE_CODE (r2val.value) == INTEGER_CST)
              || r2val.mask == -1);
+ 
    bit_value_binop_1 (code, type, &value, &mask,
                     TREE_TYPE (rhs1), value_to_wide_int (r1val), r1val.mask,
                     TREE_TYPE (rhs2), value_to_wide_int (r2val), r2val.mask);
Index: gcc/optabs.c
===================================================================
*** gcc/optabs.c        (revision 213119)
--- gcc/optabs.c        (working copy)
*************** expand_binop (enum machine_mode mode, op
*** 2174,2184 ****
        insns = get_insns ();
        end_sequence ();
  
        target = gen_reg_rtx (mode);
        emit_libcall_block_1 (insns, target, value,
!                           gen_rtx_fmt_ee (optab_to_code (binoptab),
!                                           mode, op0, op1),
!                           trapv_binoptab_p (binoptab));
  
        return target;
      }
--- 2174,2185 ----
        insns = get_insns ();
        end_sequence ();
  
+       bool trapv = trapv_binoptab_p (binoptab);
        target = gen_reg_rtx (mode);
        emit_libcall_block_1 (insns, target, value,
!                           trapv ? NULL_RTX
!                           : gen_rtx_fmt_ee (optab_to_code (binoptab),
!                                             mode, op0, op1), trapv);
  
        return target;
      }
*************** expand_unop (enum machine_mode mode, opt
*** 3297,3309 ****
        end_sequence ();
  
        target = gen_reg_rtx (outmode);
!       eq_value = gen_rtx_fmt_e (optab_to_code (unoptab), mode, op0);
!       if (GET_MODE_SIZE (outmode) < GET_MODE_SIZE (mode))
!       eq_value = simplify_gen_unary (TRUNCATE, outmode, eq_value, mode);
!       else if (GET_MODE_SIZE (outmode) > GET_MODE_SIZE (mode))
!       eq_value = simplify_gen_unary (ZERO_EXTEND, outmode, eq_value, mode);
!       emit_libcall_block_1 (insns, target, value, eq_value,
!                           trapv_unoptab_p (unoptab));
  
        return target;
      }
--- 3298,3316 ----
        end_sequence ();
  
        target = gen_reg_rtx (outmode);
!       bool trapv = trapv_unoptab_p (unoptab);
!       if (trapv)
!       eq_value = NULL_RTX;
!       else
!       {
!         eq_value = gen_rtx_fmt_e (optab_to_code (unoptab), mode, op0);
!         if (GET_MODE_SIZE (outmode) < GET_MODE_SIZE (mode))
!           eq_value = simplify_gen_unary (TRUNCATE, outmode, eq_value, mode);
!         else if (GET_MODE_SIZE (outmode) > GET_MODE_SIZE (mode))
!           eq_value = simplify_gen_unary (ZERO_EXTEND,
!                                          outmode, eq_value, mode);
!       }
!       emit_libcall_block_1 (insns, target, value, eq_value, trapv);
  
        return target;
      }
*************** emit_libcall_block_1 (rtx insns, rtx tar
*** 3985,3991 ****
      }
  
    last = emit_move_insn (target, result);
!   set_dst_reg_note (last, REG_EQUAL, copy_rtx (equiv), target);
  
    if (final_dest != target)
      emit_move_insn (final_dest, target);
--- 3992,3999 ----
      }
  
    last = emit_move_insn (target, result);
!   if (equiv)
!     set_dst_reg_note (last, REG_EQUAL, copy_rtx (equiv), target);
  
    if (final_dest != target)
      emit_move_insn (final_dest, target);
Index: gcc/testsuite/gcc.dg/torture/ftrapv-2.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/ftrapv-2.c     (revision 0)
--- gcc/testsuite/gcc.dg/torture/ftrapv-2.c     (working copy)
***************
*** 0 ****
--- 1,28 ----
+ /* { 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 constant operations properly trap.  PR middle-end/61893 */
+ 
+ int main(void)
+ {
+   pid_t child = fork ();
+   int status = 0;
+   if (child == 0)
+     {
+       volatile int x = __INT_MAX__ + 1;
+       exit (0);
+     }
+   else if (child == -1)
+     return 0;
+   if (wait (&status) == child 
+       && status == 0)
+     abort ();
+   return 0;
+ }

Reply via email to