This re-surrects Josephs patch to fix PR35634 - the fact that
the C frontend family does not properly promote the expression
operands of self-modify expressions.  Accounting for this during
gimplification is indeed easiest (as long as fold isn't too clever
with the expressions in unpromoted form).  The patch, instead of
promoting to int/unsigned int uses an unsigned type for the
computation where otherwise undefined behavior would arise from
the computation in a type with lower precision.  That avoids
most of the vectorizer regressions with the earlier patch.
The remaining three regressions are fixed with the
vect_can_advance_ivs_p hunk.

Bootstrapped and tested on x86_64-unknown-linux-gnu without
the vect_can_advance_ivs_p hunk, re-testing with that.

Ok for trunk?  (I don't think this kind of patch qualifies for
backporting)

Thanks,
Richard.

2008-04-17  Richard Guenther  <rguent...@suse.de>

        PR c/35634
        * gimple.h (gimplify_self_mod_expr): Declare.
        * gimplify.c (gimplify_self_mod_expr): Export.  Take a different
        type for performing the arithmetic in.
        (gimplify_expr): Adjust.
        * tree-vect-loop-manip.c (vect_can_advance_ivs_p): Strip
        sign conversions we can re-apply after adjusting the IV.

        c-family/
        * c-gimplify.c (c_gimplify_expr): Gimplify self-modify expressions
        here and use a type with proper overflow behavior for types that would
        need to be promoted for the arithmetic.

        * gcc.dg/torture/pr35634.c: New testcase.
        * g++.dg/torture/pr35634.C: Likewise.
        * gcc.dg/vect/pr18536.c: Mark worker function noinline.

Index: gcc/testsuite/g++.dg/torture/pr35634.C
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/torture/pr35634.C      2012-11-27 15:49:46.387585847 
+0100
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do run } */
+ 
+ extern "C" void abort (void);
+ extern "C" void exit (int);
+ 
+ void foo (int i)
+ {
+     static int n;
+     if (i < -128 || i > 127)
+         abort ();
+     if (++n > 1000)
+         exit (0);
+ }
+ 
+ int main ()
+ {
+     char c;
+     for (c = 0; ; c++) foo (c);
+ }
Index: gcc/testsuite/gcc.dg/torture/pr35634.c
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/torture/pr35634.c      2012-11-27 15:49:46.424585859 
+0100
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do run } */
+ 
+ void abort (void);
+ void exit (int);
+ 
+ void foo (int i)
+ {
+     static int n;
+     if (i < -128 || i > 127)
+         abort ();
+     if (++n > 1000)
+         exit (0);
+ }
+ 
+ int main ()
+ {
+     char c;
+     for (c = 0; ; c++) foo (c);
+ }
Index: gcc/gimple.h
===================================================================
*** gcc/gimple.h.orig   2012-11-27 14:27:24.000000000 +0100
--- gcc/gimple.h        2012-11-27 15:49:46.424585859 +0100
*************** extern enum gimplify_status gimplify_exp
*** 979,984 ****
--- 979,986 ----
                                           bool (*) (tree), fallback_t);
  extern void gimplify_type_sizes (tree, gimple_seq *);
  extern void gimplify_one_sizepos (tree *, gimple_seq *);
+ enum gimplify_status gimplify_self_mod_expr (tree *, gimple_seq *, gimple_seq 
*,
+                                            bool, tree);
  extern bool gimplify_stmt (tree *, gimple_seq *);
  extern gimple gimplify_body (tree, bool);
  extern void push_gimplify_context (struct gimplify_ctx *);
Index: gcc/gimplify.c
===================================================================
*** gcc/gimplify.c.orig 2012-11-27 14:27:24.000000000 +0100
--- gcc/gimplify.c      2012-11-27 15:49:46.425585857 +0100
*************** gimplify_compound_lval (tree *expr_p, gi
*** 2319,2327 ****
      WANT_VALUE is nonzero iff we want to use the value of this expression
        in another expression.  */
  
! static enum gimplify_status
  gimplify_self_mod_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
!                       bool want_value)
  {
    enum tree_code code;
    tree lhs, lvalue, rhs, t1;
--- 2319,2327 ----
      WANT_VALUE is nonzero iff we want to use the value of this expression
        in another expression.  */
  
! enum gimplify_status
  gimplify_self_mod_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
!                       bool want_value, tree arith_type)
  {
    enum tree_code code;
    tree lhs, lvalue, rhs, t1;
*************** gimplify_self_mod_expr (tree *expr_p, gi
*** 2382,2408 ****
        return ret;
      }
  
    /* For POINTERs increment, use POINTER_PLUS_EXPR.  */
    if (POINTER_TYPE_P (TREE_TYPE (lhs)))
      {
        rhs = convert_to_ptrofftype_loc (loc, rhs);
        if (arith_code == MINUS_EXPR)
        rhs = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (rhs), rhs);
!       arith_code = POINTER_PLUS_EXPR;
      }
  
    if (postfix)
      {
-       tree t2 = get_initialized_tmp_var (lhs, pre_p, NULL);
-       t1 = build2 (arith_code, TREE_TYPE (*expr_p), t2, rhs);
        gimplify_assign (lvalue, t1, pre_p);
        gimplify_seq_add_seq (orig_post_p, post);
!       *expr_p = t2;
        return GS_ALL_DONE;
      }
    else
      {
-       t1 = build2 (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
        *expr_p = build2 (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
        return GS_OK;
      }
--- 2382,2413 ----
        return ret;
      }
  
+   if (postfix)
+     lhs = get_initialized_tmp_var (lhs, pre_p, NULL);
+ 
    /* For POINTERs increment, use POINTER_PLUS_EXPR.  */
    if (POINTER_TYPE_P (TREE_TYPE (lhs)))
      {
        rhs = convert_to_ptrofftype_loc (loc, rhs);
        if (arith_code == MINUS_EXPR)
        rhs = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (rhs), rhs);
!       t1 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (*expr_p), lhs, rhs);
      }
+   else
+     t1 = fold_convert (TREE_TYPE (*expr_p),
+                      fold_build2 (arith_code, arith_type,
+                                   fold_convert (arith_type, lhs),
+                                   fold_convert (arith_type, rhs)));
  
    if (postfix)
      {
        gimplify_assign (lvalue, t1, pre_p);
        gimplify_seq_add_seq (orig_post_p, post);
!       *expr_p = lhs;
        return GS_ALL_DONE;
      }
    else
      {
        *expr_p = build2 (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
        return GS_OK;
      }
*************** gimplify_expr (tree *expr_p, gimple_seq
*** 7111,7117 ****
        case PREINCREMENT_EXPR:
        case PREDECREMENT_EXPR:
          ret = gimplify_self_mod_expr (expr_p, pre_p, post_p,
!                                       fallback != fb_none);
          break;
  
        case ARRAY_REF:
--- 7116,7123 ----
        case PREINCREMENT_EXPR:
        case PREDECREMENT_EXPR:
          ret = gimplify_self_mod_expr (expr_p, pre_p, post_p,
!                                       fallback != fb_none,
!                                       TREE_TYPE (*expr_p));
          break;
  
        case ARRAY_REF:
Index: gcc/c-family/c-gimplify.c
===================================================================
*** gcc/c-family/c-gimplify.c.orig      2012-11-27 14:27:24.000000000 +0100
--- gcc/c-family/c-gimplify.c   2012-11-27 15:50:08.796585070 +0100
*************** c_gimplify_expr (tree *expr_p, gimple_se
*** 172,187 ****
  {
    enum tree_code code = TREE_CODE (*expr_p);
  
!   /* This is handled mostly by gimplify.c, but we have to deal with
!      not warning about int x = x; as it is a GCC extension to turn off
!      this warning but only if warn_init_self is zero.  */
!   if (code == DECL_EXPR
!       && TREE_CODE (DECL_EXPR_DECL (*expr_p)) == VAR_DECL
!       && !DECL_EXTERNAL (DECL_EXPR_DECL (*expr_p))
!       && !TREE_STATIC (DECL_EXPR_DECL (*expr_p))
!       && (DECL_INITIAL (DECL_EXPR_DECL (*expr_p)) == DECL_EXPR_DECL (*expr_p))
!       && !warn_init_self)
!     TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1;
  
    return GS_UNHANDLED;
  }
--- 172,208 ----
  {
    enum tree_code code = TREE_CODE (*expr_p);
  
!   switch (code)
!     {
!     case DECL_EXPR:
!       /* This is handled mostly by gimplify.c, but we have to deal with
!        not warning about int x = x; as it is a GCC extension to turn off
!        this warning but only if warn_init_self is zero.  */
!       if (TREE_CODE (DECL_EXPR_DECL (*expr_p)) == VAR_DECL
!         && !DECL_EXTERNAL (DECL_EXPR_DECL (*expr_p))
!         && !TREE_STATIC (DECL_EXPR_DECL (*expr_p))
!         && (DECL_INITIAL (DECL_EXPR_DECL (*expr_p)) == DECL_EXPR_DECL 
(*expr_p))
!         && !warn_init_self)
!       TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1;
!       break;
! 
!     case PREINCREMENT_EXPR:
!     case PREDECREMENT_EXPR:
!     case POSTINCREMENT_EXPR:
!     case POSTDECREMENT_EXPR:
!       {
!       tree type = TREE_TYPE (TREE_OPERAND (*expr_p, 0));
!       if (INTEGRAL_TYPE_P (type) && c_promoting_integer_type_p (type))
!         {
!           if (TYPE_OVERFLOW_UNDEFINED (type))
!             type = unsigned_type_for (type);
!           return gimplify_self_mod_expr (expr_p, pre_p, post_p, 1, type);
!         }
!       break;
!       }
! 
!     default:;
!     }
  
    return GS_UNHANDLED;
  }
Index: gcc/testsuite/gcc.dg/vect/pr18536.c
===================================================================
*** gcc/testsuite/gcc.dg/vect/pr18536.c.orig    2006-02-07 11:14:12.000000000 
+0100
--- gcc/testsuite/gcc.dg/vect/pr18536.c 2012-11-27 15:59:50.510564950 +0100
***************
*** 5,11 ****
  
  #define N 16
  
! int main1 (short a, short *b)
  {
    while (++a < 4) *b++ = 2;
  
--- 5,11 ----
  
  #define N 16
  
! __attribute__ ((noinline)) int main1 (short a, short *b)
  {
    while (++a < 4) *b++ = 2;
  
Index: gcc/tree-vect-loop-manip.c
===================================================================
*** gcc/tree-vect-loop-manip.c.orig     2012-11-26 12:40:21.000000000 +0100
--- gcc/tree-vect-loop-manip.c  2012-11-27 16:10:37.601542471 +0100
*************** vect_can_advance_ivs_p (loop_vec_info lo
*** 1727,1732 ****
--- 1727,1733 ----
          return false;
        }
  
+       STRIP_NOPS (access_fn);
        if (dump_enabled_p ())
          {
          dump_printf_loc (MSG_NOTE, vect_location,

Reply via email to