[patch] Lno branch merge part 8 -- canonical induction variable creation

Zdenek Dvorak rakdver@atrey.karlin.mff.cuni.cz
Fri Aug 27 15:57:00 GMT 2004


Hello,

> > There is the third alternative -- to abandon the whole system, for that
> > you yourself admit that it probably does not work on many places,
> > and we are not likely to ever be able to get it working.
> >
> > My proposal is:  Add for each operation flag(s) telling whether it is
> > 1) Wrapping -- i.e. the compiler cannot assume anything about it.
> > 2) Wrap undefined -- i.e. compiler can assume it does not wrap if it
> >                      wants to.
> > 3) Trapping -- i.e. the compiler not only assumes it does not wrap,
> >                but also adds check for it.
> >
> > This allows for greater flexibility, as frontends/optimization that
> > from some reason know that a particular operation does not wrap can
> > indicate it, regardless of what it the type of operands.
> 
> I've absolutely nothing against such an overhaul of GCC's tree and RTL
> codes.  The only reason that I suggested flag_wrapv was that I assumed
> that timing was an issue.  Such a change may not be suitable even for
> stage2, and we're a very short time away from stage3.
> 
> 
> Again your points "1)" and "2)" above show the confusion.  We really,
> need a way to say
> 
> 	1) doesn't overflow.
> 	2) undefined on overflow.
> 	3) overflow wraps around using 2's complement arithmetic.
> 	4) trap on overflow.
> 
> Of course, if LNO knows that an expression is type "1)" if doesn't
> matter whether the tree code is actually 2), 3) or 4).

here is the patch that implements the proposal.  Some remarks:

-- It should be safer than the current system in case of -fno-wrapv,
   since all expressions are by default produced with modulo semantics
   (i.e. it should not happen that an optimizer would produce an operation
   with undefined behavior by mistake).
-- There may be some minor differences in behavior with -ftrapv.  Fold
   is updated to preserve trap flags, but the new operations produced by
   other optimizers are still produced with modulo semantics.  This
   should not occur too often -- optimizers usually do not produce new
   expressions from scratch; and those that do should probably anyway be
   reviewed to see whether their handling of trapping overflows is
   correct.
-- Of course with -fwrapv the behavior should be completely unchanged.

OB_UNDEFINED and OB_NO_OVERFLOW (which correspond to 2) and 1) in your
list, resp. to 2) in mine) are IMHO equivalent for any practical purpose.
I have included them both since I am not entirely sure that I do not
miss something, since you probably had some reason for listing both.

The overflow behavior flags are set only for the C frontend, the reason
being that I have no idea how the overflow behavior is defined in other
languages.

Bootstrapped & regtested on i686.

Zdenek

	* builtins.c (expand_powi_1, builtin_memset_gen_str,
	expand_builtin_fabs, expand_builtin_cabs):
	Pass overflow behavior flag to expander calls.
	* explow.c (round_push, allocate_dynamic_stack_space): Ditto.
	* expr.c (force_operand, expand_expr_real_1): Ditto.
	* ifcvt.c (noce_try_abs): Ditto.
	* c-typeck.c (set_c_overflow_behavior): New function.
	(build_unary_op, build_binary_op): Set overflow behavior flags.
	* expmed.c (expand_mult, expand_divmod): Add trap_on_overflow 
	argument and produce operations according to it.
	* expr.h (expand_divmod, expand_mult): Declaration added.
	* fold-const.c (curr_op_traps_on_overflow, curr_op_does_not_overflow,
	ignore_overflow_traps): New static variables.
	(fold): Made a wrapper around fold_2, set the overflow behavior
	variables.
	(fold_2): Split from fold.  Handle overflow behavior flags.
	(negate_expr_p, negate_expr): Added overflow behavior argument.
	(extract_muldiv_1): Handle overflow behavior flags.
	(fold_initializer): Set/restore ignore_overflow_traps.
	(tree_expr_nonzero_p): Handle overflow behavior flags.
	* gimplify.c (gimplify_self_mod_expr): Copy overflow behavior flags.
	* loop.c (basic_induction_var): Add a comment.
	(product_cheap_p): Pass overflow behavior flag to expander calls.
	* optabs.c (expand_cmplxdiv_straight, expand_cmplxdiv_wide,
	expand_binop, expand_vector_binop): Pass overflow behavior flag
	to expander calls.
	(optab_for_tree_code): Added overflow behavior argument, choose
	an optab according to it.
	(expand_abs_nojump, expand_abs, expand_complex_abs): Added overflow
	behavior argument.
	* optabs.h (expand_abs_nojump, expand_abs, expand_complex_abs,
	optab_for_tree_code): Declaration changed.
	* simplify-rtx.c (simplify_const_relational_operation): Add a comment.
	* tree-complex.c (expand_vector_operations_1): Take overflow behavior
	into account.
	* tree-dump.c (dump_options): Add TDF_WRAPS option.
	* tree-eh.c (tree_could_trap_p): Take overflow behavior flags into
	account.
	* tree-pretty-print.c (dump_overflow_behavior): New function.
	(dump_generic_node): Use it.
	* tree-vectorizer.c (vectorizable_operation): Use overflow behavior
	flags.
	* tree.c (default_overflow_behavior): New variable.
	(build1_stat, build2_stat): Set default overflow behavior.
	(affected_by_overflow_behavior_p, traps_on_overflow_p,
	does_not_overflow_p, copy_overflow_behavior): New functions.
	* tree.h (TYPE_TRAP_SIGNED): Removed.
	(enum overflow_behavior): New.
	(default_overflow_behavior): Declare.
	(GET_TREE_OVERFLOW_BEHAVIOR, SET_TREE_OVERFLOW_BEHAVIOR): New macros.
	(affected_by_overflow_behavior_p, traps_on_overflow_p,
	does_not_overflow_p, copy_overflow_behavior): Declare.
	(TDF_WRAPS): New constant.

Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.373
diff -c -3 -p -r1.373 builtins.c
*** builtins.c	25 Aug 2004 09:51:17 -0000	1.373
--- builtins.c	27 Aug 2004 11:47:45 -0000
*************** expand_powi_1 (enum machine_mode mode, u
*** 2250,2256 ****
        op1 = op0;
      }
  
!   result = expand_mult (mode, op0, op1, target, 0);
    if (result != target)
      emit_move_insn (target, result);
    return target;
--- 2250,2256 ----
        op1 = op0;
      }
  
!   result = expand_mult (mode, op0, op1, target, 0, 0);
    if (result != target)
      emit_move_insn (target, result);
    return target;
*************** builtin_memset_gen_str (void *data, HOST
*** 3278,3284 ****
    coeff = c_readstr (p, mode);
  
    target = convert_to_mode (mode, (rtx) data, 1);
!   target = expand_mult (mode, target, coeff, NULL_RTX, 1);
    return force_reg (mode, target);
  }
  
--- 3278,3284 ----
    coeff = c_readstr (p, mode);
  
    target = convert_to_mode (mode, (rtx) data, 1);
!   target = expand_mult (mode, target, coeff, NULL_RTX, 1, 0);
    return force_reg (mode, target);
  }
  
*************** expand_builtin_fabs (tree arglist, rtx t
*** 4901,4907 ****
    arg = TREE_VALUE (arglist);
    mode = TYPE_MODE (TREE_TYPE (arg));
    op0 = expand_expr (arg, subtarget, VOIDmode, 0);
!   return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
  }
  
  /* Expand a call to cabs, cabsf or cabsl with arguments ARGLIST.
--- 4901,4908 ----
    arg = TREE_VALUE (arglist);
    mode = TYPE_MODE (TREE_TYPE (arg));
    op0 = expand_expr (arg, subtarget, VOIDmode, 0);
!   return expand_abs (mode, op0, target, 0, 0,
! 		     safe_from_p (target, arg, 1));
  }
  
  /* Expand a call to cabs, cabsf or cabsl with arguments ARGLIST.
*************** expand_builtin_cabs (tree arglist, rtx t
*** 4925,4931 ****
  
    mode = TYPE_MODE (TREE_TYPE (arg));
    op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0);
!   return expand_complex_abs (mode, op0, target, 0);
  }
  
  /* Create a new constant string literal and return a char* pointer to it.
--- 4926,4932 ----
  
    mode = TYPE_MODE (TREE_TYPE (arg));
    op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0);
!   return expand_complex_abs (mode, op0, target, 0, flag_trapv);
  }
  
  /* Create a new constant string literal and return a char* pointer to it.
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.363
diff -c -3 -p -r1.363 c-typeck.c
*** c-typeck.c	27 Aug 2004 00:37:48 -0000	1.363
--- c-typeck.c	27 Aug 2004 11:47:45 -0000
*************** static void set_nonincremental_init_from
*** 83,88 ****
--- 83,113 ----
  static tree find_init_member (tree);
  static int lvalue_or_else (tree, const char *);
  
+ /* Set overflow behavior flags of EXPR according to flag_wrapv and
+    flag_trapw.  */
+ 
+ static void
+ set_c_overflow_behavior (tree expr)
+ {
+   tree type = TREE_TYPE (expr);
+   enum overflow_behavior behavior = flag_trapv ? OB_TRAP : OB_UNDEFINED;
+ 
+   /* With flag_wrapv all arithmetics has the modulo semantics.  */ 
+   if (!flag_trapv && flag_wrapv)
+     return;
+ 
+   /* The wrap behavior only affects some expressions.  */
+   if (!affected_by_overflow_behavior_p (TREE_CODE (expr)))
+     return;
+ 
+   /* And only signed integer arithmetics (rest defaults to the modulo
+      semantics).  */
+   if (!INTEGRAL_TYPE_P (type) || TYPE_UNSIGNED (type))
+     return;
+ 
+   SET_TREE_OVERFLOW_BEHAVIOR (expr, behavior);
+ }
+ 
  /* Do `exp = require_complete_type (exp);' to make sure exp
     does not have an incomplete type.  (That includes void types.)  */
  
*************** build_unary_op (enum tree_code code, tre
*** 2466,2472 ****
  	if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
  	  val = boolean_increment (code, arg);
  	else
! 	  val = build2 (code, TREE_TYPE (arg), arg, inc);
  	TREE_SIDE_EFFECTS (val) = 1;
  	val = convert (result_type, val);
  	if (TREE_CODE (val) != code)
--- 2491,2500 ----
  	if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
  	  val = boolean_increment (code, arg);
  	else
! 	  {
! 	    val = build2 (code, TREE_TYPE (arg), arg, inc);
! 	    set_c_overflow_behavior (val);
! 	  }
  	TREE_SIDE_EFFECTS (val) = 1;
  	val = convert (result_type, val);
  	if (TREE_CODE (val) != code)
*************** build_unary_op (enum tree_code code, tre
*** 2560,2565 ****
--- 2588,2595 ----
    if (argtype == 0)
      argtype = TREE_TYPE (arg);
    val = build1 (code, argtype, arg);
+   set_c_overflow_behavior (val);
+ 
    return require_constant_value ? fold_initializer (val) : fold (val);
  }
  
*************** build_binary_op (enum tree_code code, tr
*** 7573,7578 ****
--- 7603,7609 ----
  
    {
      tree result = build2 (resultcode, build_type, op0, op1);
+     set_c_overflow_behavior (result);
  
      /* Treat expressions in initializers specially as they can't trap.  */
      result = require_constant_value ? fold_initializer (result)
Index: explow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/explow.c,v
retrieving revision 1.138
diff -c -3 -p -r1.138 explow.c
*** explow.c	18 Aug 2004 08:23:42 -0000	1.138
--- explow.c	27 Aug 2004 11:47:45 -0000
*************** round_push (rtx size)
*** 900,907 ****
        size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),
  			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
        size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),
! 			    NULL_RTX, 1);
!       size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1);
      }
  
    return size;
--- 900,907 ----
        size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),
  			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
        size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),
! 			    NULL_RTX, 1, 0);
!       size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1, 0);
      }
  
    return size;
*************** allocate_dynamic_stack_space (rtx size, 
*** 1385,1394 ****
  			     NULL_RTX, 1, OPTAB_LIB_WIDEN);
        target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
  			      GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
! 			      NULL_RTX, 1);
        target = expand_mult (Pmode, target,
  			    GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
! 			    NULL_RTX, 1);
      }
  
    /* Record the new stack level for nonlocal gotos.  */
--- 1385,1394 ----
  			     NULL_RTX, 1, OPTAB_LIB_WIDEN);
        target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
  			      GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
! 			      NULL_RTX, 1, 0);
        target = expand_mult (Pmode, target,
  			    GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
! 			    NULL_RTX, 1, 0);
      }
  
    /* Record the new stack level for nonlocal gotos.  */
Index: expmed.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expmed.c,v
retrieving revision 1.193
diff -c -3 -p -r1.193 expmed.c
*** expmed.c	25 Aug 2004 09:51:22 -0000	1.193
--- expmed.c	27 Aug 2004 11:47:46 -0000
*************** expand_mult_const (enum machine_mode mod
*** 2663,2673 ****
  
     We check specially for a constant integer as OP1.
     If you want this check for OP0 as well, then before calling
!    you should swap the two operands if OP0 would be constant.  */
  
  rtx
  expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
! 	     int unsignedp)
  {
    rtx const_op1 = op1;
    enum mult_variant variant;
--- 2663,2676 ----
  
     We check specially for a constant integer as OP1.
     If you want this check for OP0 as well, then before calling
!    you should swap the two operands if OP0 would be constant.
!    
!    TRAP_ON_OVERFLOW is true if the operation should trap on
!    overflow.  */
  
  rtx
  expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
! 	     int unsignedp, int trap_on_overflow)
  {
    rtx const_op1 = op1;
    enum mult_variant variant;
*************** expand_mult (enum machine_mode mode, rtx
*** 2698,2704 ****
       that it seems better to use synth_mult always.  */
  
    if (const_op1 && GET_CODE (const_op1) == CONST_INT
!       && (unsignedp || !flag_trapv))
      {
        int mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
  
--- 2701,2707 ----
       that it seems better to use synth_mult always.  */
  
    if (const_op1 && GET_CODE (const_op1) == CONST_INT
!       && !trap_on_overflow)
      {
        int mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
  
*************** expand_mult (enum machine_mode mode, rtx
*** 2732,2741 ****
  
    /* This used to use umul_optab if unsigned, but for non-widening multiply
       there is no difference between signed and unsigned.  */
!   op0 = expand_binop (mode,
! 		      ! unsignedp
! 		      && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
! 		      ? smulv_optab : smul_optab,
  		      op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
    if (op0 == 0)
      abort ();
--- 2735,2741 ----
  
    /* This used to use umul_optab if unsigned, but for non-widening multiply
       there is no difference between signed and unsigned.  */
!   op0 = expand_binop (mode, trap_on_overflow ? smulv_optab : smul_optab,
  		      op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
    if (op0 == 0)
      abort ();
*************** expand_sdiv_pow2 (enum machine_mode mode
*** 3299,3305 ****
  
  rtx
  expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
! 	       rtx op0, rtx op1, rtx target, int unsignedp)
  {
    enum machine_mode compute_mode;
    rtx tquotient;
--- 3299,3306 ----
  
  rtx
  expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
! 	       rtx op0, rtx op1, rtx target, int unsignedp,
! 	       int trap_on_overflow)
  {
    enum machine_mode compute_mode;
    rtx tquotient;
*************** expand_divmod (int rem_flag, enum tree_c
*** 3359,3371 ****
      return rem_flag ? const0_rtx : op0;
  
      /* When dividing by -1, we could get an overflow.
!      negv_optab can handle overflows.  */
    if (! unsignedp && op1 == constm1_rtx)
      {
        if (rem_flag)
  	return const0_rtx;
!       return expand_unop (mode, flag_trapv && GET_MODE_CLASS(mode) == MODE_INT
! 			  ? negv_optab : neg_optab, op0, target, 0);
      }
  
    if (target
--- 3360,3372 ----
      return rem_flag ? const0_rtx : op0;
  
      /* When dividing by -1, we could get an overflow.
!        negv_optab can handle overflows.  */
    if (! unsignedp && op1 == constm1_rtx)
      {
        if (rem_flag)
  	return const0_rtx;
!       return expand_unop (mode, trap_on_overflow ? negv_optab : neg_optab,
! 			  op0, target, 0);
      }
  
    if (target
*************** expand_divmod (int rem_flag, enum tree_c
*** 3873,3879 ****
  		t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
  				    NULL_RTX);
  		t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1,
! 				    NULL_RTX, 0);
  		if (t4)
  		  {
  		    rtx t5;
--- 3874,3880 ----
  		t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
  				    NULL_RTX);
  		t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1,
! 				    NULL_RTX, 0, trap_on_overflow);
  		if (t4)
  		  {
  		    rtx t5;
*************** expand_divmod (int rem_flag, enum tree_c
*** 4207,4213 ****
  			       NULL_RTX, unsignedp);
  	    quotient = expand_mult (compute_mode, t1,
  				    gen_int_mode (ml, compute_mode),
! 				    NULL_RTX, 1);
  
  	    insn = get_last_insn ();
  	    set_unique_reg_note (insn,
--- 4208,4214 ----
  			       NULL_RTX, unsignedp);
  	    quotient = expand_mult (compute_mode, t1,
  				    gen_int_mode (ml, compute_mode),
! 				    NULL_RTX, 1, 0);
  
  	    insn = get_last_insn ();
  	    set_unique_reg_note (insn,
*************** expand_divmod (int rem_flag, enum tree_c
*** 4232,4238 ****
  		rtx tem;
  		quotient = expand_binop (compute_mode, udiv_optab, op0, op1,
  					 quotient, 1, OPTAB_LIB_WIDEN);
! 		tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 1);
  		remainder = expand_binop (compute_mode, sub_optab, op0, tem,
  					  remainder, 1, OPTAB_LIB_WIDEN);
  	      }
--- 4233,4239 ----
  		rtx tem;
  		quotient = expand_binop (compute_mode, udiv_optab, op0, op1,
  					 quotient, 1, OPTAB_LIB_WIDEN);
! 		tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 1, 0);
  		remainder = expand_binop (compute_mode, sub_optab, op0, tem,
  					  remainder, 1, OPTAB_LIB_WIDEN);
  	      }
*************** expand_divmod (int rem_flag, enum tree_c
*** 4257,4268 ****
  		rtx tem;
  		quotient = expand_binop (compute_mode, sdiv_optab, op0, op1,
  					 quotient, 0, OPTAB_LIB_WIDEN);
! 		tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 0);
  		remainder = expand_binop (compute_mode, sub_optab, op0, tem,
  					  remainder, 0, OPTAB_LIB_WIDEN);
  	      }
! 	    abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 1, 0);
! 	    abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 1, 0);
  	    tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
  				build_int_cst (NULL_TREE, 1),
  				NULL_RTX, 1);
--- 4258,4270 ----
  		rtx tem;
  		quotient = expand_binop (compute_mode, sdiv_optab, op0, op1,
  					 quotient, 0, OPTAB_LIB_WIDEN);
! 		tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 0,
! 				   trap_on_overflow);
  		remainder = expand_binop (compute_mode, sub_optab, op0, tem,
  					  remainder, 0, OPTAB_LIB_WIDEN);
  	      }
! 	    abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 1, 0, 0);
! 	    abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 1, 0, 0);
  	    tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
  				build_int_cst (NULL_TREE, 1),
  				NULL_RTX, 1);
*************** expand_divmod (int rem_flag, enum tree_c
*** 4391,4397 ****
  	{
  	  /* We divided.  Now finish doing X - Y * (X / Y).  */
  	  remainder = expand_mult (compute_mode, quotient, op1,
! 				   NULL_RTX, unsignedp);
  	  remainder = expand_binop (compute_mode, sub_optab, op0,
  				    remainder, target, unsignedp,
  				    OPTAB_LIB_WIDEN);
--- 4393,4399 ----
  	{
  	  /* We divided.  Now finish doing X - Y * (X / Y).  */
  	  remainder = expand_mult (compute_mode, quotient, op1,
! 				   NULL_RTX, unsignedp, trap_on_overflow);
  	  remainder = expand_binop (compute_mode, sub_optab, op0,
  				    remainder, target, unsignedp,
  				    OPTAB_LIB_WIDEN);
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.711
diff -c -3 -p -r1.711 expr.c
*** expr.c	26 Aug 2004 00:24:33 -0000	1.711
--- expr.c	27 Aug 2004 11:47:46 -0000
*************** force_operand (rtx value, rtx target)
*** 5666,5672 ****
        switch (code)
  	{
  	case MULT:
! 	  return expand_mult (GET_MODE (value), op1, op2, target, 1);
  	case DIV:
  	  if (!INTEGRAL_MODE_P (GET_MODE (value)))
  	    return expand_simple_binop (GET_MODE (value), code, op1, op2,
--- 5666,5672 ----
        switch (code)
  	{
  	case MULT:
! 	  return expand_mult (GET_MODE (value), op1, op2, target, 1, 0);
  	case DIV:
  	  if (!INTEGRAL_MODE_P (GET_MODE (value)))
  	    return expand_simple_binop (GET_MODE (value), code, op1, op2,
*************** force_operand (rtx value, rtx target)
*** 5675,5693 ****
  	    return expand_divmod (0,
  				  FLOAT_MODE_P (GET_MODE (value))
  				  ? RDIV_EXPR : TRUNC_DIV_EXPR,
! 				  GET_MODE (value), op1, op2, target, 0);
  	  break;
  	case MOD:
  	  return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
! 				target, 0);
  	  break;
  	case UDIV:
  	  return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
! 				target, 1);
  	  break;
  	case UMOD:
  	  return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
! 				target, 1);
  	  break;
  	case ASHIFTRT:
  	  return expand_simple_binop (GET_MODE (value), code, op1, op2,
--- 5675,5693 ----
  	    return expand_divmod (0,
  				  FLOAT_MODE_P (GET_MODE (value))
  				  ? RDIV_EXPR : TRUNC_DIV_EXPR,
! 				  GET_MODE (value), op1, op2, target, 0, 0);
  	  break;
  	case MOD:
  	  return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
! 				target, 0, 0);
  	  break;
  	case UDIV:
  	  return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
! 				target, 1, 0);
  	  break;
  	case UMOD:
  	  return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
! 				target, 1, 0);
  	  break;
  	case ASHIFTRT:
  	  return expand_simple_binop (GET_MODE (value), code, op1, op2,
*************** expand_expr_real_1 (tree exp, rtx target
*** 6202,6207 ****
--- 6202,6208 ----
    int ignore;
    tree context;
    bool reduce_bit_field = false;
+   enum overflow_behavior ob;
  #define REDUCE_BIT_FIELD(expr)	(reduce_bit_field && !ignore		  \
  				 ? reduce_to_bit_field_precision ((expr), \
  								  target, \
*************** expand_expr_real_1 (tree exp, rtx target
*** 7277,7283 ****
  
  	 If this is an EXPAND_SUM call, always return the sum.  */
        if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
! 	  || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
  	{
  	  if (modifier == EXPAND_STACK_PARM)
  	    target = 0;
--- 7278,7284 ----
  
  	 If this is an EXPAND_SUM call, always return the sum.  */
        if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
! 	  || (mode == ptr_mode && !traps_on_overflow_p (exp)))
  	{
  	  if (modifier == EXPAND_STACK_PARM)
  	    target = 0;
*************** expand_expr_real_1 (tree exp, rtx target
*** 7511,7517 ****
  	}
        expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
  		       subtarget, &op0, &op1, 0);
!       return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
  
      case TRUNC_DIV_EXPR:
      case FLOOR_DIV_EXPR:
--- 7512,7519 ----
  	}
        expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
  		       subtarget, &op0, &op1, 0);
!       return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp,
! 					    traps_on_overflow_p (exp)));
  
      case TRUNC_DIV_EXPR:
      case FLOOR_DIV_EXPR:
*************** expand_expr_real_1 (tree exp, rtx target
*** 7525,7531 ****
  	 where some terms of the dividend have coeffs divisible by it.  */
        expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
  		       subtarget, &op0, &op1, 0);
!       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
  
      case RDIV_EXPR:
        /* Emit a/b as a*(1/b).  Later we may manage CSE the reciprocal saving
--- 7527,7534 ----
  	 where some terms of the dividend have coeffs divisible by it.  */
        expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
  		       subtarget, &op0, &op1, 0);
!       return expand_divmod (0, code, mode, op0, op1, target, unsignedp,
! 			    traps_on_overflow_p (exp));
  
      case RDIV_EXPR:
        /* Emit a/b as a*(1/b).  Later we may manage CSE the reciprocal saving
*************** expand_expr_real_1 (tree exp, rtx target
*** 7550,7556 ****
  	target = 0;
        expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
  		       subtarget, &op0, &op1, 0);
!       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
  
      case FIX_ROUND_EXPR:
      case FIX_FLOOR_EXPR:
--- 7553,7559 ----
  	target = 0;
        expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
  		       subtarget, &op0, &op1, 0);
!       return expand_divmod (1, code, mode, op0, op1, target, unsignedp, 0);
  
      case FIX_ROUND_EXPR:
      case FIX_FLOOR_EXPR:
*************** expand_expr_real_1 (tree exp, rtx target
*** 7578,7588 ****
        return target;
  
      case NEGATE_EXPR:
        op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        if (modifier == EXPAND_STACK_PARM)
  	target = 0;
        temp = expand_unop (mode,
!       			  optab_for_tree_code (NEGATE_EXPR, type),
  			  op0, target, 0);
        if (temp == 0)
  	abort ();
--- 7581,7592 ----
        return target;
  
      case NEGATE_EXPR:
+       ob = GET_TREE_OVERFLOW_BEHAVIOR (exp);
        op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        if (modifier == EXPAND_STACK_PARM)
  	target = 0;
        temp = expand_unop (mode,
!       			  optab_for_tree_code (NEGATE_EXPR, type, ob),
  			  op0, target, 0);
        if (temp == 0)
  	abort ();
*************** expand_expr_real_1 (tree exp, rtx target
*** 7604,7609 ****
--- 7608,7614 ----
  	return op0;
  
        return expand_abs (mode, op0, target, unsignedp,
+ 			 traps_on_overflow_p (exp),
  			 safe_from_p (target, TREE_OPERAND (exp, 0), 1));
  
      case MAX_EXPR:
*************** expand_expr_real_1 (tree exp, rtx target
*** 7622,7628 ****
        /* First try to do it with a special MIN or MAX instruction.
  	 If that does not win, use a conditional jump to select the proper
  	 value.  */
!       this_optab = optab_for_tree_code (code, type);
        temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
  			   OPTAB_WIDEN);
        if (temp != 0)
--- 7627,7633 ----
        /* First try to do it with a special MIN or MAX instruction.
  	 If that does not win, use a conditional jump to select the proper
  	 value.  */
!       this_optab = optab_for_tree_code (code, type, OB_NO_OVERFLOW);
        temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
  			   OPTAB_WIDEN);
        if (temp != 0)
*************** expand_expr_real_1 (tree exp, rtx target
*** 8196,8202 ****
    expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
  		   subtarget, &op0, &op1, 0);
   binop2:
!   this_optab = optab_for_tree_code (code, type);
   binop3:
    if (modifier == EXPAND_STACK_PARM)
      target = 0;
--- 8201,8208 ----
    expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
  		   subtarget, &op0, &op1, 0);
   binop2:
!   ob = GET_TREE_OVERFLOW_BEHAVIOR (exp);
!   this_optab = optab_for_tree_code (code, type, ob);
   binop3:
    if (modifier == EXPAND_STACK_PARM)
      target = 0;
Index: expr.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.h,v
retrieving revision 1.170
diff -c -3 -p -r1.170 expr.h
*** expr.h	18 Aug 2004 08:23:46 -0000	1.170
--- expr.h	27 Aug 2004 11:47:46 -0000
*************** extern void fixup_tail_calls (void);
*** 573,579 ****
  extern rtx expand_shift (enum tree_code, enum machine_mode, rtx, tree, rtx,
  			 int);
  extern rtx expand_divmod (int, enum tree_code, enum machine_mode, rtx, rtx,
! 			  rtx, int);
  #endif
  
  extern void locate_and_pad_parm (enum machine_mode, tree, int, int, tree,
--- 573,579 ----
  extern rtx expand_shift (enum tree_code, enum machine_mode, rtx, tree, rtx,
  			 int);
  extern rtx expand_divmod (int, enum tree_code, enum machine_mode, rtx, rtx,
! 			  rtx, int, int);
  #endif
  
  extern void locate_and_pad_parm (enum machine_mode, tree, int, int, tree,
*************** extern rtx store_bit_field (rtx, unsigne
*** 741,747 ****
  extern rtx extract_bit_field (rtx, unsigned HOST_WIDE_INT,
  			      unsigned HOST_WIDE_INT, int, rtx,
  			      enum machine_mode, enum machine_mode);
! extern rtx expand_mult (enum machine_mode, rtx, rtx, rtx, int);
  extern bool const_mult_add_overflow_p (rtx, rtx, rtx, enum machine_mode, int);
  extern rtx expand_mult_add (rtx, rtx, rtx, rtx,enum machine_mode, int);
  extern rtx expand_mult_highpart_adjust (enum machine_mode, rtx, rtx, rtx, rtx, int);
--- 741,747 ----
  extern rtx extract_bit_field (rtx, unsigned HOST_WIDE_INT,
  			      unsigned HOST_WIDE_INT, int, rtx,
  			      enum machine_mode, enum machine_mode);
! extern rtx expand_mult (enum machine_mode, rtx, rtx, rtx, int, int);
  extern bool const_mult_add_overflow_p (rtx, rtx, rtx, enum machine_mode, int);
  extern rtx expand_mult_add (rtx, rtx, rtx, rtx,enum machine_mode, int);
  extern rtx expand_mult_highpart_adjust (enum machine_mode, rtx, rtx, rtx, rtx, int);
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.444
diff -c -3 -p -r1.444 fold-const.c
*** fold-const.c	25 Aug 2004 09:51:25 -0000	1.444
--- fold-const.c	27 Aug 2004 11:47:46 -0000
*************** enum comparison_code {
*** 81,86 ****
--- 81,99 ----
    COMPCODE_TRUE = 15
  };
  
+ /* True if the currently processed operation traps on overflow.  */
+ 
+ static bool curr_op_traps_on_overflow;
+ 
+ /* True if the currently processed operation may be assumed not to
+    overflow.  */
+ 
+ static bool curr_op_does_not_overflow;
+ 
+ /* True if the traps due to overflow are to be ignored.  */
+ 
+ static bool ignore_overflow_traps;
+ 
  static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
  static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
  static bool negate_mathfn_p (enum built_in_function);
*************** static tree fold_relational_const (enum 
*** 138,143 ****
--- 151,157 ----
  static tree fold_relational_hi_lo (enum tree_code *, const tree,
                                     tree *, tree *);
  static bool tree_expr_nonzero_p (tree);
+ static tree fold_2 (tree);
  
  /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
     overflow.  Suppose A, B and SUM have the same respective signs as A1, B1,
*************** negate_expr_p (tree t)
*** 914,920 ****
    switch (TREE_CODE (t))
      {
      case INTEGER_CST:
!       if (TYPE_UNSIGNED (type) || ! flag_trapv)
  	return true;
  
        /* Check that -CST will not overflow type.  */
--- 928,935 ----
    switch (TREE_CODE (t))
      {
      case INTEGER_CST:
!       if (TYPE_UNSIGNED (type)
! 	  || !curr_op_traps_on_overflow)
  	return true;
  
        /* Check that -CST will not overflow type.  */
*************** negate_expr (tree t)
*** 1012,1018 ****
        tem = fold_negate_const (t, type);
        if (! TREE_OVERFLOW (tem)
  	  || TYPE_UNSIGNED (type)
! 	  || ! flag_trapv)
  	return tem;
        break;
  
--- 1027,1033 ----
        tem = fold_negate_const (t, type);
        if (! TREE_OVERFLOW (tem)
  	  || TYPE_UNSIGNED (type)
! 	  || ! curr_op_traps_on_overflow)
  	return tem;
        break;
  
*************** extract_muldiv_1 (tree t, tree c, enum t
*** 5249,5255 ****
  			     fold_convert (ctype, c), 0);
  	  /* We allow the constant to overflow with wrapping semantics.  */
  	  if (op1 == 0
! 	      || (TREE_OVERFLOW (op1) && ! flag_wrapv))
  	    break;
  	}
        else
--- 5264,5271 ----
  			     fold_convert (ctype, c), 0);
  	  /* We allow the constant to overflow with wrapping semantics.  */
  	  if (op1 == 0
! 	      || (TREE_OVERFLOW (op1)
! 		  && default_overflow_behavior != OB_MODULO))
  	    break;
  	}
        else
*************** extract_muldiv_1 (tree t, tree c, enum t
*** 5325,5331 ****
  	 overflowed.  */
        if ((! TYPE_UNSIGNED (ctype)
  	   || (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype)))
! 	  && ! flag_wrapv
  	  && ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
  	      || (tcode == MULT_EXPR
  		  && code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
--- 5341,5347 ----
  	 overflowed.  */
        if ((! TYPE_UNSIGNED (ctype)
  	   || (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype)))
! 	  && does_not_overflow_p (t)
  	  && ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
  	      || (tcode == MULT_EXPR
  		  && code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
*************** tree_swap_operands_p (tree arg0, tree ar
*** 6008,6016 ****
--- 6024,6067 ----
  static tree fold_1 (tree);
  static
  #endif
+ 
+ /* A wrapper to set up flags describing the behavior on overflows
+    and restore them after running the real fold function.  */
+ 
  tree
  fold (tree expr)
  {
+   tree ret;
+   enum overflow_behavior old_overflow_behavior = default_overflow_behavior;
+   bool old_curr_op_traps_on_overflow = curr_op_traps_on_overflow;
+   bool old_curr_op_does_not_overflow = curr_op_does_not_overflow;
+ 
+   if (traps_on_overflow_p (expr)
+       && !ignore_overflow_traps)
+     {
+       default_overflow_behavior = OB_TRAP;
+       curr_op_traps_on_overflow = true;
+     }
+   else
+     {
+       default_overflow_behavior = OB_MODULO;
+       curr_op_traps_on_overflow = false;
+     }
+ 
+   curr_op_does_not_overflow = does_not_overflow_p (expr);
+ 
+   ret = fold_2 (expr);
+ 
+   default_overflow_behavior = old_overflow_behavior;
+   curr_op_traps_on_overflow = old_curr_op_traps_on_overflow;
+   curr_op_does_not_overflow = old_curr_op_does_not_overflow;
+ 
+   return ret;
+ }
+ 
+ static tree
+ fold_2 (tree expr)
+ {
    const tree t = expr;
    const tree type = TREE_TYPE (expr);
    tree t1 = NULL_TREE;
*************** fold (tree expr)
*** 6101,6108 ****
       to ARG1 to reduce the number of tests below.  */
    if (commutative_tree_code (code)
        && tree_swap_operands_p (arg0, arg1, true))
!     return fold (build2 (code, type, TREE_OPERAND (t, 1),
! 			 TREE_OPERAND (t, 0)));
  
    /* Now WINS is set as described above,
       ARG0 is the first operand of EXPR,
--- 6152,6165 ----
       to ARG1 to reduce the number of tests below.  */
    if (commutative_tree_code (code)
        && tree_swap_operands_p (arg0, arg1, true))
!     {
!       tem = build2 (code, type, TREE_OPERAND (t, 1),
! 		    TREE_OPERAND (t, 0));
!       /* Swapping the operands does not change overflow behavior.  */
!       copy_overflow_behavior (tem, t);
! 
!       return fold (tem);
!     }
  
    /* Now WINS is set as described above,
       ARG0 is the first operand of EXPR,
*************** fold (tree expr)
*** 6915,6921 ****
        /* (-A) - B -> (-B) - A  where B is easily negated and we can swap.  */
        if (TREE_CODE (arg0) == NEGATE_EXPR
  	  && (FLOAT_TYPE_P (type)
! 	      || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv))
  	  && negate_expr_p (arg1)
  	  && reorder_operands_p (arg0, arg1))
  	return fold (build2 (MINUS_EXPR, type, negate_expr (arg1),
--- 6972,6980 ----
        /* (-A) - B -> (-B) - A  where B is easily negated and we can swap.  */
        if (TREE_CODE (arg0) == NEGATE_EXPR
  	  && (FLOAT_TYPE_P (type)
! 	      || (INTEGRAL_TYPE_P (type)
! 		  && default_overflow_behavior == OB_MODULO
! 		  && !curr_op_traps_on_overflow))
  	  && negate_expr_p (arg1)
  	  && reorder_operands_p (arg0, arg1))
  	return fold (build2 (MINUS_EXPR, type, negate_expr (arg1),
*************** fold (tree expr)
*** 6990,6996 ****
                 /* Avoid this transformation if B is a positive REAL_CST.  */
  	       && (TREE_CODE (arg1) != REAL_CST
  		   ||  REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
! 	      || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
  	return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
  
        if (TREE_CODE (arg0) == MULT_EXPR
--- 7049,7057 ----
                 /* Avoid this transformation if B is a positive REAL_CST.  */
  	       && (TREE_CODE (arg1) != REAL_CST
  		   ||  REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
! 	      || (INTEGRAL_TYPE_P (type)
! 		  && default_overflow_behavior == OB_MODULO
! 		  && !curr_op_traps_on_overflow)))
  	return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
  
        if (TREE_CODE (arg0) == MULT_EXPR
*************** fold (tree expr)
*** 7642,7648 ****
  	  && !TYPE_UNSIGNED (type)
  	  && TREE_CODE (arg1) == INTEGER_CST
  	  && TREE_INT_CST_HIGH (arg1) < 0
! 	  && !flag_trapv
  	  /* Avoid this transformation if C is INT_MIN, i.e. C == -C.  */
  	  && !sign_bit_p (arg1, arg1))
  	return fold (build2 (code, type, fold_convert (type, arg0),
--- 7703,7709 ----
  	  && !TYPE_UNSIGNED (type)
  	  && TREE_CODE (arg1) == INTEGER_CST
  	  && TREE_INT_CST_HIGH (arg1) < 0
! 	  && !curr_op_traps_on_overflow
  	  /* Avoid this transformation if C is INT_MIN, i.e. C == -C.  */
  	  && !sign_bit_p (arg1, arg1))
  	return fold (build2 (code, type, fold_convert (type, arg0),
*************** fold (tree expr)
*** 7652,7658 ****
        if (code == TRUNC_MOD_EXPR
  	  && !TYPE_UNSIGNED (type)
  	  && TREE_CODE (arg1) == NEGATE_EXPR
! 	  && !flag_trapv)
  	return fold (build2 (code, type, fold_convert (type, arg0),
  			     fold_convert (type, TREE_OPERAND (arg1, 0))));
  
--- 7713,7719 ----
        if (code == TRUNC_MOD_EXPR
  	  && !TYPE_UNSIGNED (type)
  	  && TREE_CODE (arg1) == NEGATE_EXPR
! 	  && !curr_op_traps_on_overflow)
  	return fold (build2 (code, type, fold_convert (type, arg0),
  			     fold_convert (type, TREE_OPERAND (arg1, 0))));
  
*************** fold_initializer (tree expr)
*** 9223,9240 ****
  {
    int saved_signaling_nans = flag_signaling_nans;
    int saved_trapping_math = flag_trapping_math;
!   int saved_trapv = flag_trapv;
    tree result;
  
    flag_signaling_nans = 0;
    flag_trapping_math = 0;
!   flag_trapv = 0;
  
    result = fold (expr);
  
    flag_signaling_nans = saved_signaling_nans;
    flag_trapping_math = saved_trapping_math;
!   flag_trapv = saved_trapv;
  
    return result;
  }
--- 9284,9301 ----
  {
    int saved_signaling_nans = flag_signaling_nans;
    int saved_trapping_math = flag_trapping_math;
!   int saved_ignore_overflow_traps = ignore_overflow_traps;
    tree result;
  
    flag_signaling_nans = 0;
    flag_trapping_math = 0;
!   ignore_overflow_traps = true;
  
    result = fold (expr);
  
    flag_signaling_nans = saved_signaling_nans;
    flag_trapping_math = saved_trapping_math;
!   ignore_overflow_traps = saved_ignore_overflow_traps;
  
    return result;
  }
*************** tree_expr_nonzero_p (tree t)
*** 9628,9635 ****
    switch (TREE_CODE (t))
      {
      case ABS_EXPR:
!       if (!TYPE_UNSIGNED (type) && !flag_wrapv)
  	return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
  
      case INTEGER_CST:
        /* We used to test for !integer_zerop here.  This does not work correctly
--- 9689,9697 ----
    switch (TREE_CODE (t))
      {
      case ABS_EXPR:
!       if (does_not_overflow_p (t))
  	return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+       break;
  
      case INTEGER_CST:
        /* We used to test for !integer_zerop here.  This does not work correctly
*************** tree_expr_nonzero_p (tree t)
*** 9638,9644 ****
  	      || TREE_INT_CST_HIGH (t) != 0);
  
      case PLUS_EXPR:
!       if (!TYPE_UNSIGNED (type) && !flag_wrapv)
  	{
  	  /* With the presence of negative values it is hard
  	     to say something.  */
--- 9700,9706 ----
  	      || TREE_INT_CST_HIGH (t) != 0);
  
      case PLUS_EXPR:
!       if (does_not_overflow_p (t))
  	{
  	  /* With the presence of negative values it is hard
  	     to say something.  */
*************** tree_expr_nonzero_p (tree t)
*** 9652,9658 ****
        break;
  
      case MULT_EXPR:
!       if (!TYPE_UNSIGNED (type) && !flag_wrapv)
  	{
  	  return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
  	          && tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
--- 9714,9720 ----
        break;
  
      case MULT_EXPR:
!       if (does_not_overflow_p (t))
  	{
  	  return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
  	          && tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.67
diff -c -3 -p -r2.67 gimplify.c
*** gimplify.c	25 Aug 2004 18:11:12 -0000	2.67
--- gimplify.c	27 Aug 2004 11:47:46 -0000
*************** gimplify_self_mod_expr (tree *expr_p, tr
*** 1683,1688 ****
--- 1683,1689 ----
      }
  
    t1 = build (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
+   copy_overflow_behavior (t1, *expr_p);
    t1 = build (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
  
    if (postfix)
Index: ifcvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.163
diff -c -3 -p -r1.163 ifcvt.c
*** ifcvt.c	25 Aug 2004 19:52:53 -0000	1.163
--- ifcvt.c	27 Aug 2004 11:47:46 -0000
*************** noce_try_abs (struct noce_if_info *if_in
*** 1696,1702 ****
  
    start_sequence ();
  
!   target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1);
  
    /* ??? It's a quandary whether cmove would be better here, especially
       for integers.  Perhaps combine will clean things up.  */
--- 1696,1702 ----
  
    start_sequence ();
  
!   target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 0, 1);
  
    /* ??? It's a quandary whether cmove would be better here, especially
       for integers.  Perhaps combine will clean things up.  */
Index: loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop.c,v
retrieving revision 1.507
diff -c -3 -p -r1.507 loop.c
*** loop.c	25 Aug 2004 08:20:09 -0000	1.507
--- loop.c	27 Aug 2004 11:47:46 -0000
*************** basic_induction_var (const struct loop *
*** 6278,6283 ****
--- 6278,6287 ----
  	return 0;
  
      case SIGN_EXTEND:
+       /* FIXME -- this test is bogus.  The fact that sign extension
+ 	 is used here does not necessarily imply that (only) signed
+ 	 arithmetics was used during the IV computation.  */
+ 
        /* Ignore this BIV if signed arithmetic overflow is defined.  */
        if (flag_wrapv)
  	return 0;
*************** product_cheap_p (rtx a, rtx b)
*** 7839,7845 ****
       of insns is generated.  */
  
    start_sequence ();
!   expand_mult (GET_MODE (a), a, b, NULL_RTX, 1);
    tmp = get_insns ();
    end_sequence ();
  
--- 7843,7849 ----
       of insns is generated.  */
  
    start_sequence ();
!   expand_mult (GET_MODE (a), a, b, NULL_RTX, 1, 0);
    tmp = get_insns ();
    end_sequence ();
  
Index: optabs.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.c,v
retrieving revision 1.235
diff -c -3 -p -r1.235 optabs.c
*** optabs.c	19 Aug 2004 22:24:54 -0000	1.235
--- optabs.c	27 Aug 2004 11:47:46 -0000
*************** expand_cmplxdiv_straight (rtx real0, rtx
*** 345,351 ****
  			realr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 real_t, divisor, realr, unsignedp);
  
    if (res == 0)
      return 0;
--- 346,352 ----
  			realr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 real_t, divisor, realr, unsignedp, 0);
  
    if (res == 0)
      return 0;
*************** expand_cmplxdiv_straight (rtx real0, rtx
*** 358,364 ****
  			imagr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 imag_t, divisor, imagr, unsignedp);
  
    if (res == 0)
      return 0;
--- 359,365 ----
  			imagr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 imag_t, divisor, imagr, unsignedp, 0);
  
    if (res == 0)
      return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 412,419 ****
      }
    else
      {
!       temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1);
!       temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1);
      }
  
    if (temp1 == 0 || temp2 == 0)
--- 413,420 ----
      }
    else
      {
!       temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 0, 1);
!       temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 0, 1);
      }
  
    if (temp1 == 0 || temp2 == 0)
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 431,437 ****
  			  NULL_RTX, unsignedp, methods);
    else
      ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			   imag1, real1, NULL_RTX, unsignedp);
  
    if (ratio == 0)
      return 0;
--- 432,438 ----
  			  NULL_RTX, unsignedp, methods);
    else
      ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			   imag1, real1, NULL_RTX, unsignedp, 0);
  
    if (ratio == 0)
      return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 502,508 ****
  			realr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 real_t, divisor, realr, unsignedp);
  
    if (res == 0)
      return 0;
--- 503,509 ----
  			realr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 real_t, divisor, realr, unsignedp, 0);
  
    if (res == 0)
      return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 515,521 ****
  			imagr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 imag_t, divisor, imagr, unsignedp);
  
    if (res == 0)
      return 0;
--- 516,522 ----
  			imagr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 imag_t, divisor, imagr, unsignedp, 0);
  
    if (res == 0)
      return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 536,542 ****
  			  NULL_RTX, unsignedp, methods);
    else
      ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			   real1, imag1, NULL_RTX, unsignedp);
  
    if (ratio == 0)
      return 0;
--- 537,543 ----
  			  NULL_RTX, unsignedp, methods);
    else
      ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			   real1, imag1, NULL_RTX, unsignedp, 0);
  
    if (ratio == 0)
      return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 602,608 ****
  			realr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 real_t, divisor, realr, unsignedp);
  
    if (res == 0)
      return 0;
--- 603,609 ----
  			realr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 real_t, divisor, realr, unsignedp, 0);
  
    if (res == 0)
      return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 615,621 ****
  			imagr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 imag_t, divisor, imagr, unsignedp);
  
    if (res == 0)
      return 0;
--- 616,622 ----
  			imagr, unsignedp, methods);
    else
      res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 			 imag_t, divisor, imagr, unsignedp, 0);
  
    if (res == 0)
      return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 634,640 ****
     or division) but probably ought to be relied on more widely
     throughout the expander.  */
  optab
! optab_for_tree_code (enum tree_code code, tree type)
  {
    bool trapv;
    switch (code)
--- 635,642 ----
     or division) but probably ought to be relied on more widely
     throughout the expander.  */
  optab
! optab_for_tree_code (enum tree_code code, tree type,
! 		     enum overflow_behavior ob)
  {
    bool trapv;
    switch (code)
*************** optab_for_tree_code (enum tree_code code
*** 687,693 ****
        break;
      }
  
!   trapv = flag_trapv && INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type);
    switch (code)
      {
      case PLUS_EXPR:
--- 689,695 ----
        break;
      }
  
!   trapv = ob == OB_TRAP;
    switch (code)
      {
      case PLUS_EXPR:
*************** expand_binop (enum machine_mode mode, op
*** 1776,1782 ****
  				    realr, unsignedp, methods);
  	      else
  		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 				     real0, real1, realr, unsignedp);
  
  	      if (res == 0)
  		break;
--- 1778,1784 ----
  				    realr, unsignedp, methods);
  	      else
  		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 				     real0, real1, realr, unsignedp, 0);
  
  	      if (res == 0)
  		break;
*************** expand_binop (enum machine_mode mode, op
*** 1788,1794 ****
  				    imagr, unsignedp, methods);
  	      else
  		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 				     imag0, real1, imagr, unsignedp);
  
  	      if (res == 0)
  		break;
--- 1790,1796 ----
  				    imagr, unsignedp, methods);
  	      else
  		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 				     imag0, real1, imagr, unsignedp, 0);
  
  	      if (res == 0)
  		break;
*************** expand_vector_binop (enum machine_mode m
*** 2048,2054 ****
  				    unsignedp, methods);
  	      else
  		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 				     a, b, t, unsignedp);
  	    }
  	  else
  	    res = expand_binop (submode, binoptab, a, b, t,
--- 2050,2056 ----
  				    unsignedp, methods);
  	      else
  		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! 				     a, b, t, unsignedp, 0);
  	    }
  	  else
  	    res = expand_binop (submode, binoptab, a, b, t,
*************** expand_unop (enum machine_mode mode, opt
*** 2963,2973 ****
  
  rtx
  expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
! 		   int result_unsignedp)
  {
    rtx temp;
  
!   if (! flag_trapv)
      result_unsignedp = 1;
  
    /* First try to do it with a special abs instruction.  */
--- 2965,2975 ----
  
  rtx
  expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
! 		   int result_unsignedp, int traps_on_overflow)
  {
    rtx temp;
  
!   if (!traps_on_overflow)
      result_unsignedp = 1;
  
    /* First try to do it with a special abs instruction.  */
*************** expand_abs_nojump (enum machine_mode mod
*** 3067,3080 ****
  
  rtx
  expand_abs (enum machine_mode mode, rtx op0, rtx target,
! 	    int result_unsignedp, int safe)
  {
    rtx temp, op1;
  
!   if (! flag_trapv)
      result_unsignedp = 1;
  
!   temp = expand_abs_nojump (mode, op0, target, result_unsignedp);
    if (temp != 0)
      return temp;
  
--- 3069,3084 ----
  
  rtx
  expand_abs (enum machine_mode mode, rtx op0, rtx target,
! 	    int result_unsignedp, int trap_on_overflow,
! 	    int safe)
  {
    rtx temp, op1;
  
!   if (!trap_on_overflow)
      result_unsignedp = 1;
  
!   temp = expand_abs_nojump (mode, op0, target, result_unsignedp,
! 			    trap_on_overflow);
    if (temp != 0)
      return temp;
  
*************** expand_abs (enum machine_mode mode, rtx 
*** 3127,3133 ****
  
  rtx
  expand_complex_abs (enum machine_mode mode, rtx op0, rtx target,
! 		    int unsignedp)
  {
    enum mode_class class = GET_MODE_CLASS (mode);
    enum machine_mode wider_mode;
--- 3131,3137 ----
  
  rtx
  expand_complex_abs (enum machine_mode mode, rtx op0, rtx target,
! 		    int unsignedp, int trap_on_overflow)
  {
    enum mode_class class = GET_MODE_CLASS (mode);
    enum machine_mode wider_mode;
*************** expand_complex_abs (enum machine_mode mo
*** 3148,3155 ****
  
    last = get_last_insn ();
  
!   this_abs_optab = ! unsignedp && flag_trapv
!                    && (GET_MODE_CLASS(mode) == MODE_INT)
                     ? absv_optab : abs_optab;
  
    if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
--- 3152,3159 ----
  
    last = get_last_insn ();
  
!   this_abs_optab = trap_on_overflow
!                    && GET_MODE_CLASS(mode) == MODE_INT
                     ? absv_optab : abs_optab;
  
    if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
*************** expand_complex_abs (enum machine_mode mo
*** 3206,3212 ****
  	  rtx xop0 = op0;
  
  	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
! 	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
  
  	  if (temp)
  	    {
--- 3210,3217 ----
  	  rtx xop0 = op0;
  
  	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
! 	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp,
! 				     trap_on_overflow);
  
  	  if (temp)
  	    {
*************** expand_complex_abs (enum machine_mode mo
*** 3228,3234 ****
    /* Open-code the complex absolute-value operation
       if we can open-code sqrt.  Otherwise it's not worth while.  */
    if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
!       && ! flag_trapv)
      {
        rtx real, imag, total;
  
--- 3233,3239 ----
    /* Open-code the complex absolute-value operation
       if we can open-code sqrt.  Otherwise it's not worth while.  */
    if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
!       && ! trap_on_overflow)
      {
        rtx real, imag, total;
  
*************** expand_complex_abs (enum machine_mode mo
*** 3236,3243 ****
        imag = gen_imagpart (submode, op0);
  
        /* Square both parts.  */
!       real = expand_mult (submode, real, real, NULL_RTX, 0);
!       imag = expand_mult (submode, imag, imag, NULL_RTX, 0);
  
        /* Sum the parts.  */
        total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
--- 3241,3248 ----
        imag = gen_imagpart (submode, op0);
  
        /* Square both parts.  */
!       real = expand_mult (submode, real, real, NULL_RTX, 0, 0);
!       imag = expand_mult (submode, imag, imag, NULL_RTX, 0, 0);
  
        /* Sum the parts.  */
        total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
*************** expand_complex_abs (enum machine_mode mo
*** 3286,3292 ****
  
  	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
  
! 	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
  
  	  if (temp)
  	    {
--- 3291,3298 ----
  
  	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
  
! 	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp,
! 				     trap_on_overflow);
  
  	  if (temp)
  	    {
Index: optabs.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.h,v
retrieving revision 1.33
diff -c -3 -p -r1.33 optabs.h
*** optabs.h	11 Aug 2004 02:50:06 -0000	1.33
--- optabs.h	27 Aug 2004 11:47:46 -0000
*************** extern bool expand_twoval_binop_libfunc 
*** 426,436 ****
  extern rtx expand_unop (enum machine_mode, optab, rtx, rtx, int);
  
  /* Expand the absolute value operation.  */
! extern rtx expand_abs_nojump (enum machine_mode, rtx, rtx, int);
! extern rtx expand_abs (enum machine_mode, rtx, rtx, int, int);
  
  /* Expand the complex absolute value operation.  */
! extern rtx expand_complex_abs (enum machine_mode, rtx, rtx, int);
  
  /* Generate an instruction with a given INSN_CODE with an output and
     an input.  */
--- 426,436 ----
  extern rtx expand_unop (enum machine_mode, optab, rtx, rtx, int);
  
  /* Expand the absolute value operation.  */
! extern rtx expand_abs_nojump (enum machine_mode, rtx, rtx, int, int);
! extern rtx expand_abs (enum machine_mode, rtx, rtx, int, int, int);
  
  /* Expand the complex absolute value operation.  */
! extern rtx expand_complex_abs (enum machine_mode, rtx, rtx, int, int);
  
  /* Generate an instruction with a given INSN_CODE with an output and
     an input.  */
*************** enum can_compare_purpose
*** 455,461 ****
  
  /* Return the optab used for computing the given operation on the type
     given by the second argument.  */
! extern optab optab_for_tree_code (enum tree_code, tree);
  
  /* Nonzero if a compare of mode MODE can be done straightforwardly
     (without splitting it into pieces).  */
--- 455,462 ----
  
  /* Return the optab used for computing the given operation on the type
     given by the second argument.  */
! extern optab optab_for_tree_code (enum tree_code, tree,
! 				  enum overflow_behavior);
  
  /* Nonzero if a compare of mode MODE can be done straightforwardly
     (without splitting it into pieces).  */
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.202
diff -c -3 -p -r1.202 simplify-rtx.c
*** simplify-rtx.c	27 Jul 2004 19:09:32 -0000	1.202
--- simplify-rtx.c	27 Aug 2004 11:47:46 -0000
*************** simplify_const_relational_operation (enu
*** 2847,2853 ****
       because it gives an incorrect result if the subtraction wraps around zero.
       ANSI C defines unsigned operations such that they never overflow, and
       thus such cases can not be ignored; but we cannot do it even for
!      signed comparisons for languages such as Java, so test flag_wrapv.  */
  
    if (!flag_wrapv && INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
        && ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
--- 2847,2858 ----
       because it gives an incorrect result if the subtraction wraps around zero.
       ANSI C defines unsigned operations such that they never overflow, and
       thus such cases can not be ignored; but we cannot do it even for
!      signed comparisons for languages such as Java, so test flag_wrapv.
!      
!      FIXME -- this is nonsense; we no longer have information on what
!      the type of arguments was.  We could wery well compute the subtraction
!      in unsigned arithmetics, then cast it to signed and compare.  The cast
!      would not be represented at rtl level, since it is a no-op.  */
  
    if (!flag_wrapv && INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
        && ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
Index: tree-complex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-complex.c,v
retrieving revision 2.9
diff -c -3 -p -r2.9 tree-complex.c
*** tree-complex.c	25 Aug 2004 09:51:29 -0000	2.9
--- tree-complex.c	27 Aug 2004 11:47:46 -0000
*************** expand_vector_operations_1 (block_stmt_i
*** 753,758 ****
--- 753,759 ----
    enum tree_code code;
    enum machine_mode compute_mode;
    optab op;
+   enum overflow_behavior ob;
  
    switch (TREE_CODE (stmt))
      {
*************** expand_vector_operations_1 (block_stmt_i
*** 781,793 ****
        && TREE_CODE_CLASS (code) != '2')
      return;
  
    if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR)
      return;
  
    if (code == CONVERT_EXPR)
      abort ();
  
!   op = optab_for_tree_code (code, type);
  
    /* Optabs will try converting a negation into a subtraction, so
       look for it as well.  TODO: negation of floating-point vectors
--- 782,796 ----
        && TREE_CODE_CLASS (code) != '2')
      return;
  
+   ob = GET_TREE_OVERFLOW_BEHAVIOR (rhs);
+ 
    if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR)
      return;
  
    if (code == CONVERT_EXPR)
      abort ();
  
!   op = optab_for_tree_code (code, type, ob);
  
    /* Optabs will try converting a negation into a subtraction, so
       look for it as well.  TODO: negation of floating-point vectors
*************** expand_vector_operations_1 (block_stmt_i
*** 795,801 ****
    if (op == NULL
        && code == NEGATE_EXPR
        && INTEGRAL_TYPE_P (TREE_TYPE (type)))
!     op = optab_for_tree_code (MINUS_EXPR, type);
  
    /* For very wide vectors, try using a smaller vector mode.  */
    compute_type = type;
--- 798,804 ----
    if (op == NULL
        && code == NEGATE_EXPR
        && INTEGRAL_TYPE_P (TREE_TYPE (type)))
!     op = optab_for_tree_code (MINUS_EXPR, type, ob);
  
    /* For very wide vectors, try using a smaller vector mode.  */
    compute_type = type;
*************** expand_vector_operations_1 (block_stmt_i
*** 836,842 ****
        {
        case PLUS_EXPR:
        case MINUS_EXPR:
!         if (TYPE_TRAP_SIGNED (type))
  	  break;
  
          *p_rhs = expand_vector_addition (bsi, do_binop, do_plus_minus, type,
--- 839,845 ----
        {
        case PLUS_EXPR:
        case MINUS_EXPR:
!         if (traps_on_overflow_p (rhs))
  	  break;
  
          *p_rhs = expand_vector_addition (bsi, do_binop, do_plus_minus, type,
*************** expand_vector_operations_1 (block_stmt_i
*** 846,852 ****
          return;
  
        case NEGATE_EXPR:
!         if (TYPE_TRAP_SIGNED (type))
  	  break;
  
          *p_rhs = expand_vector_addition (bsi, do_unop, do_negate, type,
--- 849,855 ----
          return;
  
        case NEGATE_EXPR:
!         if (traps_on_overflow_p (rhs))
  	  break;
  
          *p_rhs = expand_vector_addition (bsi, do_unop, do_negate, type,
Index: tree-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dump.c,v
retrieving revision 1.29
diff -c -3 -p -r1.29 tree-dump.c
*** tree-dump.c	26 Jul 2004 08:23:34 -0000	1.29
--- tree-dump.c	27 Aug 2004 11:47:46 -0000
*************** static const struct dump_option_value_in
*** 709,714 ****
--- 709,715 ----
    {"vops", TDF_VOPS},
    {"lineno", TDF_LINENO},
    {"uid", TDF_UID},
+   {"wraps", TDF_WRAPS},
    {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO)},
    {NULL, 0}
  };
Index: tree-eh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-eh.c,v
retrieving revision 2.16
diff -c -3 -p -r2.16 tree-eh.c
*** tree-eh.c	25 Aug 2004 09:51:29 -0000	2.16
--- tree-eh.c	27 Aug 2004 11:47:46 -0000
*************** tree_could_trap_p (tree expr)
*** 1730,1736 ****
  	  honor_nans = flag_trapping_math && !flag_finite_math_only;
  	  honor_snans = flag_signaling_nans != 0;
  	}
!       else if (INTEGRAL_TYPE_P (t) && TYPE_TRAP_SIGNED (t))
  	honor_trapv = true;
      }
  
--- 1730,1737 ----
  	  honor_nans = flag_trapping_math && !flag_finite_math_only;
  	  honor_snans = flag_signaling_nans != 0;
  	}
!       else if (INTEGRAL_TYPE_P (t)
! 	       && traps_on_overflow_p (expr))
  	honor_trapv = true;
      }
  
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.32
diff -c -3 -p -r2.32 tree-pretty-print.c
*** tree-pretty-print.c	25 Aug 2004 21:21:15 -0000	2.32
--- tree-pretty-print.c	27 Aug 2004 11:47:46 -0000
*************** print_generic_expr (FILE *file, tree t, 
*** 148,153 ****
--- 148,185 ----
    dump_generic_node (&buffer, t, 0, flags, false);
  }
  
+ /* Dumps overflow behavior of operation EXPR to BUFFER.  */
+ 
+ static void
+ dump_overflow_behavior (pretty_printer *buffer, tree expr)
+ {
+   enum overflow_behavior ob = GET_TREE_OVERFLOW_BEHAVIOR (expr);
+ 
+   if (!affected_by_overflow_behavior_p (TREE_CODE (expr)))
+     return;
+ 
+   switch (ob)
+     {
+     case OB_MODULO:
+       break;
+ 
+     case OB_UNDEFINED:
+       pp_string (buffer, "{u}");
+       break;
+ 
+     case OB_NO_OVERFLOW:
+       pp_string (buffer, "{n}");
+       break;
+ 
+     case OB_TRAP:
+       pp_string (buffer, "{t}");
+       break;
+ 
+     default:
+       abort ();
+     }
+ }
+ 
  /* Dump the name of a _DECL node and its DECL_UID if TDF_UID is set
     in FLAGS.  */
  
*************** dump_generic_node (pretty_printer *buffe
*** 982,987 ****
--- 1014,1021 ----
  
  	pp_space (buffer);
  	pp_string (buffer, op);
+ 	if (flags & TDF_WRAPS)
+ 	  dump_overflow_behavior (buffer, node);
  	pp_space (buffer);
  
  	/* When the operands are expressions with less priority,
*************** dump_generic_node (pretty_printer *buffe
*** 1012,1017 ****
--- 1046,1054 ----
        else
  	pp_string (buffer, op_symbol (node));
  
+       if (flags & TDF_WRAPS)
+ 	dump_overflow_behavior (buffer, node);
+ 
        if (op_prio (TREE_OPERAND (node, 0)) < op_prio (node))
  	{
  	  pp_character (buffer, '(');
*************** dump_generic_node (pretty_printer *buffe
*** 1033,1038 ****
--- 1070,1077 ----
        else
  	dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
        pp_string (buffer, op_symbol (node));
+       if (flags & TDF_WRAPS)
+ 	dump_overflow_behavior (buffer, node);
        break;
  
      case MIN_EXPR:
*************** dump_generic_node (pretty_printer *buffe
*** 1052,1058 ****
        break;
  
      case ABS_EXPR:
!       pp_string (buffer, "ABS_EXPR <");
        dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
        pp_character (buffer, '>');
        break;
--- 1091,1100 ----
        break;
  
      case ABS_EXPR:
!       pp_string (buffer, "ABS_EXPR");
!       if (flags & TDF_WRAPS)
! 	dump_overflow_behavior (buffer, node);
!       pp_string (buffer, " <");
        dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
        pp_character (buffer, '>');
        break;
Index: tree-vectorizer.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-vectorizer.c,v
retrieving revision 2.5
diff -c -3 -p -r2.5 tree-vectorizer.c
*** tree-vectorizer.c	25 Aug 2004 21:21:19 -0000	2.5
--- tree-vectorizer.c	27 Aug 2004 11:47:47 -0000
*************** vectorizable_operation (tree stmt, block
*** 1112,1117 ****
--- 1112,1118 ----
    int op_type;
    tree op;
    optab optab;
+   enum overflow_behavior ob;
  
    /* Is STMT a vectorizable binary/unary operation?   */
    if (TREE_CODE (stmt) != MODIFY_EXPR)
*************** vectorizable_operation (tree stmt, block
*** 1121,1128 ****
      return false;
  
    operation = TREE_OPERAND (stmt, 1);
    code = TREE_CODE (operation);
!   optab = optab_for_tree_code (code, vectype);
  
    /* Support only unary or binary operations.  */
    op_type = TREE_CODE_LENGTH (code);
--- 1122,1130 ----
      return false;
  
    operation = TREE_OPERAND (stmt, 1);
+   ob = GET_TREE_OVERFLOW_BEHAVIOR (operation);
    code = TREE_CODE (operation);
!   optab = optab_for_tree_code (code, vectype, ob);
  
    /* Support only unary or binary operations.  */
    op_type = TREE_CODE_LENGTH (code);
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.417
diff -c -3 -p -r1.417 tree.c
*** tree.c	27 Aug 2004 00:55:38 -0000	1.417
--- tree.c	27 Aug 2004 11:47:47 -0000
*************** Software Foundation, 59 Temple Place - S
*** 50,55 ****
--- 50,59 ----
  #include "tree-flow.h"
  #include "params.h"
  
+ /* Expressions are by default build with this overflow behavior.  */
+ 
+ enum overflow_behavior default_overflow_behavior = OB_MODULO;
+ 
  /* obstack.[ch] explicitly declined to prototype this.  */
  extern int _obstack_allocated_p (struct obstack *h, void *obj);
  
*************** build1_stat (enum tree_code code, tree t
*** 2416,2421 ****
--- 2420,2428 ----
        break;
      }
  
+   if (affected_by_overflow_behavior_p (code))
+     SET_TREE_OVERFLOW_BEHAVIOR (t, default_overflow_behavior);
+ 
    return t;
  }
  
*************** build2_stat (enum tree_code code, tree t
*** 2474,2479 ****
--- 2481,2489 ----
    TREE_THIS_VOLATILE (t)
      = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
  
+   if (affected_by_overflow_behavior_p (code))
+     SET_TREE_OVERFLOW_BEHAVIOR (t, default_overflow_behavior);
+ 
    return t;
  }
  
*************** tree_fold_gcd (tree a, tree b)
*** 5837,5840 ****
--- 5847,5913 ----
      }
  }
  
+ /* Returns true if the operation OP is affected by overflow behavior flags.  */
+ 
+ bool
+ affected_by_overflow_behavior_p (enum tree_code code)
+ {
+   switch (code)
+     {
+     case PLUS_EXPR:
+     case MINUS_EXPR:
+     case MULT_EXPR:
+     case NEGATE_EXPR:
+     case ABS_EXPR:
+     case PREINCREMENT_EXPR:
+     case POSTINCREMENT_EXPR:
+     case PREDECREMENT_EXPR:
+     case POSTDECREMENT_EXPR:
+ 
+     /*  Division may overflow if we divide by -1.  */
+     case TRUNC_DIV_EXPR:
+     case CEIL_DIV_EXPR:
+     case FLOOR_DIV_EXPR:
+     case ROUND_DIV_EXPR:
+     case EXACT_DIV_EXPR:
+       return true;
+ 
+     default:
+       return false;
+     }
+ }
+ 
+ /* Returns true if the operation EXPR may trap according to overflow
+    behavior flags.  */
+ 
+ bool
+ traps_on_overflow_p (tree expr)
+ {
+   if (!affected_by_overflow_behavior_p (TREE_CODE (expr)))
+     return false;
+ 
+   return GET_TREE_OVERFLOW_BEHAVIOR (expr) == OB_TRAP;
+ }
+ 
+ /* Returns true if the operation EXPR may be assumed not to overflow
+    according to behavior flags.  */
+ 
+ bool
+ does_not_overflow_p (tree expr)
+ {
+   if (!affected_by_overflow_behavior_p (TREE_CODE (expr)))
+     return false;
+ 
+   return GET_TREE_OVERFLOW_BEHAVIOR (expr) != OB_MODULO;
+ }
+ 
+ /* Copies overflow behavior flags from expression FROM to TO.  */
+ 
+ void
+ copy_overflow_behavior (tree to, tree from)
+ {
+   enum overflow_behavior ob = GET_TREE_OVERFLOW_BEHAVIOR (from);
+   SET_TREE_OVERFLOW_BEHAVIOR (to, ob);
+ }
+ 
  #include "gt-tree.h"
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.605
diff -c -3 -p -r1.605 tree.h
*** tree.h	27 Aug 2004 00:27:24 -0000	1.605
--- tree.h	27 Aug 2004 11:47:47 -0000
*************** struct tree_common GTY(())
*** 220,225 ****
--- 220,227 ----
         EH_FILTER_MUST_NOT_THROW in EH_FILTER_EXPR
         TYPE_REF_CAN_ALIAS_ALL in
             POINTER_TYPE, REFERENCE_TYPE
+        TREE_OVERFLOW_BEHAVIOR
+            in arithmetic expressions
  
     public_flag:
  
*************** struct tree_common GTY(())
*** 232,237 ****
--- 234,241 ----
             ASM_EXPR
         TYPE_CACHED_VALUES_P in
            ..._TYPE
+        TREE_OVERFLOW_BEHAVIOR
+            in arithmetic expressions
         SAVE_EXPR_RESOLVED_P in
  	  SAVE_EXPR
  
*************** extern void tree_operand_check_failed (i
*** 852,860 ****
  /* In integral and pointer types, means an unsigned type.  */
  #define TYPE_UNSIGNED(NODE) (TYPE_CHECK (NODE)->common.unsigned_flag)
  
- #define TYPE_TRAP_SIGNED(NODE) \
-   (flag_trapv && ! TYPE_UNSIGNED (NODE))
- 
  /* Nonzero in a VAR_DECL means assembler code has been written.
     Nonzero in a FUNCTION_DECL means that the function has been compiled.
     This is interesting in an inline function, since it might not need
--- 856,861 ----
*************** extern void tree_operand_check_failed (i
*** 915,920 ****
--- 916,950 ----
     any expression node.  */
  #define TREE_INVARIANT(NODE) ((NODE)->common.invariant_flag)
  
+ /* Defines a behavior of an expression on overflow.  */
+ 
+ enum overflow_behavior
+ {
+   OB_MODULO = 0,	/* The operation is computed modulo 2^size of type.  */
+   OB_UNDEFINED = 1,	/* The behavior is undefined, i.e. we may assume
+ 			   any semantics as needed, or assume that the
+ 			   overflow does not occur.  */
+   OB_NO_OVERFLOW = 2,	/* The operation is guaranteed to be executed with
+ 			   such operands that it does not overflow.  */
+   OB_TRAP = 3		/* The operation traps.  */
+ };
+ 
+ extern enum overflow_behavior default_overflow_behavior;
+ 
+ #define GET_TREE_OVERFLOW_BEHAVIOR(NODE) \
+   (2 * (NODE)->common.static_flag + (NODE)->common.public_flag)
+ #define SET_TREE_OVERFLOW_BEHAVIOR(NODE, VAL) \
+   do \
+     { \
+       (NODE)->common.static_flag = ((VAL) & 2) != 0; \
+       (NODE)->common.public_flag = ((VAL) & 1) != 0; \
+     } while (0)
+ 
+ bool affected_by_overflow_behavior_p (enum tree_code);
+ bool traps_on_overflow_p (tree);
+ bool does_not_overflow_p (tree);
+ void copy_overflow_behavior (tree, tree);
+ 
  /* These flags are available for each language front end to use internally.  */
  #define TREE_LANG_FLAG_0(NODE) ((NODE)->common.lang_flag_0)
  #define TREE_LANG_FLAG_1(NODE) ((NODE)->common.lang_flag_1)
*************** enum tree_dump_index
*** 3733,3739 ****
  #define TDF_VOPS	(1 << 6)	/* display virtual operands */
  #define TDF_LINENO	(1 << 7)	/* display statement line numbers */
  #define TDF_UID		(1 << 8)	/* display decl UIDs */
! 
  
  typedef struct dump_info *dump_info_p;
  
--- 3763,3770 ----
  #define TDF_VOPS	(1 << 6)	/* display virtual operands */
  #define TDF_LINENO	(1 << 7)	/* display statement line numbers */
  #define TDF_UID		(1 << 8)	/* display decl UIDs */
! #define TDF_WRAPS	(1 << 9)	/* display overflow behavior of
! 					   operations */
  
  typedef struct dump_info *dump_info_p;
  



More information about the Gcc-patches mailing list