On Tue, May 7, 2013 at 11:26 PM, Marc Glisse <marc.gli...@inria.fr> wrote:
> Hello,
>
> this patch is about the use of TYPE_PRECISION for non-scalar types. For
> complex types, it is unused (always 0) and for vectors, the field is used to
> store the log of the number of elements, so in both cases we shouldn't use
> the macro. I tried to enforce it, see the SCALAR_TYPE_CHECK in tree.h (I
> assume I should remove it and the FIXME before commit), and started fixing
> the crashes, but there were too many and I gave up. Those fixes I did write
> are included in the patch, since I believe we eventually want to get there.
>
> For hashing in gimple.c, including TYPE_UNSIGNED for complex and vector
> seems questionable: I think that it is the same as for the inner type, which
> is already hashed. I didn't change that in the patch.
>
> Passes bootstrap+testsuite on x86_64-linux-gnu.

Ok.

Thanks,
Richard.

>
> 2013-05-07  Marc Glisse  <marc.gli...@inria.fr>
>
> gcc/
>         * stor-layout.c (element_precision): New function.
>         * machmode.h (element_precision): Declare it.
>         * tree.c (build_minus_one_cst): New function.
>         (element_precision): Likewise.
>         * tree.h (SCALAR_TYPE_CHECK): New macro.
>         (build_minus_one_cst): Declare new function.
>         (element_precision): Likewise.
>         * fold-const.c (operand_equal_p): Use element_precision.
>         (fold_binary_loc): Handle vector types.
>         * convert.c (convert_to_integer): Use element_precision.
>         * gimple.c (iterative_hash_canonical_type): Handle complex and
> vectors
>         separately.
>
> gcc/c-family/
>         * c-common.c (vector_types_convertible_p): No TYPE_PRECISION for
>         vectors.
>
> gcc/testsuite/
>         * gcc.dg/vector-shift.c: New testcase.
>
> --
> Marc Glisse
> Index: gcc/convert.c
> ===================================================================
> --- gcc/convert.c       (revision 198685)
> +++ gcc/convert.c       (working copy)
> @@ -348,22 +348,22 @@ convert_to_real (tree type, tree expr)
>     fixed-point or vector; in other cases error is called.
>
>     The result of this is always supposed to be a newly created tree node
>     not in use in any existing structure.  */
>
>  tree
>  convert_to_integer (tree type, tree expr)
>  {
>    enum tree_code ex_form = TREE_CODE (expr);
>    tree intype = TREE_TYPE (expr);
> -  unsigned int inprec = TYPE_PRECISION (intype);
> -  unsigned int outprec = TYPE_PRECISION (type);
> +  unsigned int inprec = element_precision (intype);
> +  unsigned int outprec = element_precision (type);
>
>    /* An INTEGER_TYPE cannot be incomplete, but an ENUMERAL_TYPE can
>       be.  Consider `enum E = { a, b = (enum E) 3 };'.  */
>    if (!COMPLETE_TYPE_P (type))
>      {
>        error ("conversion to incomplete type");
>        return error_mark_node;
>      }
>
>    /* Convert e.g. (long)round(d) -> lround(d).  */
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c  (revision 198685)
> +++ gcc/tree.c  (working copy)
> @@ -1615,20 +1615,59 @@ build_one_cst (tree type)
>      case COMPLEX_TYPE:
>        return build_complex (type,
>                             build_one_cst (TREE_TYPE (type)),
>                             build_zero_cst (TREE_TYPE (type)));
>
>      default:
>        gcc_unreachable ();
>      }
>  }
>
> +/* Return a constant of arithmetic type TYPE which is the
> +   opposite of the multiplicative identity of the set TYPE.  */
> +
> +tree
> +build_minus_one_cst (tree type)
> +{
> +  switch (TREE_CODE (type))
> +    {
> +    case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
> +    case POINTER_TYPE: case REFERENCE_TYPE:
> +    case OFFSET_TYPE:
> +      return build_int_cst (type, -1);
> +
> +    case REAL_TYPE:
> +      return build_real (type, dconstm1);
> +
> +    case FIXED_POINT_TYPE:
> +      /* We can only generate 1 for accum types.  */
> +      gcc_assert (ALL_SCALAR_ACCUM_MODE_P (TYPE_MODE (type)));
> +      return build_fixed (type, fixed_from_double_int
> (double_int_minus_one,
> +                                                      TYPE_MODE (type)));
> +
> +    case VECTOR_TYPE:
> +      {
> +       tree scalar = build_minus_one_cst (TREE_TYPE (type));
> +
> +       return build_vector_from_val (type, scalar);
> +      }
> +
> +    case COMPLEX_TYPE:
> +      return build_complex (type,
> +                           build_minus_one_cst (TREE_TYPE (type)),
> +                           build_zero_cst (TREE_TYPE (type)));
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
>  /* Build 0 constant of type TYPE.  This is used by constructor folding
>     and thus the constant should be represented in memory by
>     zero(es).  */
>
>  tree
>  build_zero_cst (tree type)
>  {
>    switch (TREE_CODE (type))
>      {
>      case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
> @@ -6921,20 +6960,33 @@ compare_tree_int (const_tree t, unsigned
>  bool
>  valid_constant_size_p (const_tree size)
>  {
>    if (! host_integerp (size, 1)
>        || TREE_OVERFLOW (size)
>        || tree_int_cst_sign_bit (size) != 0)
>      return false;
>    return true;
>  }
>
> +/* Return the precision of the type, or for a complex or vector type the
> +   precision of the type of its elements.  */
> +
> +unsigned int
> +element_precision (const_tree type)
> +{
> +  enum tree_code code = TREE_CODE (type);
> +  if (code == COMPLEX_TYPE || code == VECTOR_TYPE)
> +    type = TREE_TYPE (type);
> +
> +  return TYPE_PRECISION (type);
> +}
> +
>  /* Return true if CODE represents an associative tree code.  Otherwise
>     return false.  */
>  bool
>  associative_tree_code (enum tree_code code)
>  {
>    switch (code)
>      {
>      case BIT_IOR_EXPR:
>      case BIT_AND_EXPR:
>      case BIT_XOR_EXPR:
> Index: gcc/tree.h
> ===================================================================
> --- gcc/tree.h  (revision 198685)
> +++ gcc/tree.h  (working copy)
> @@ -929,20 +929,23 @@ extern void omp_clause_range_check_faile
>
>  #define RECORD_OR_UNION_CHECK(T)       \
>    TREE_CHECK3 (T, RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE)
>  #define NOT_RECORD_OR_UNION_CHECK(T) \
>    TREE_NOT_CHECK3 (T, RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE)
>
>  #define NUMERICAL_TYPE_CHECK(T)                                        \
>    TREE_CHECK5 (T, INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, REAL_TYPE,
> \
>                FIXED_POINT_TYPE)
>
> +#define SCALAR_TYPE_CHECK(T)   \
> +  TREE_NOT_CHECK2 (TYPE_CHECK (T), COMPLEX_TYPE, VECTOR_TYPE)
> +
>  /* Here is how primitive or already-canonicalized types' hash codes
>     are made.  */
>  #define TYPE_HASH(TYPE) (TYPE_UID (TYPE))
>
>  /* A simple hash function for an arbitrary tree node.  This must not be
>     used in hash tables which are saved to a PCH.  */
>  #define TREE_HASH(NODE) ((size_t) (NODE) & 0777777)
>
>  /* Tests if CODE is a conversion expr (NOP_EXPR or CONVERT_EXPR).  */
>  #define CONVERT_EXPR_CODE_P(CODE)                              \
> @@ -2108,20 +2111,22 @@ struct GTY(()) tree_block {
>     overloaded and used for different macros in different kinds of types.
>     Each macro must check to ensure the tree node is of the proper kind of
>     type.  Note also that some of the front-ends also overload these fields,
>     so they must be checked as well.  */
>
>  #define TYPE_UID(NODE) (TYPE_CHECK (NODE)->type_common.uid)
>  #define TYPE_SIZE(NODE) (TYPE_CHECK (NODE)->type_common.size)
>  #define TYPE_SIZE_UNIT(NODE) (TYPE_CHECK (NODE)->type_common.size_unit)
>  #define TYPE_POINTER_TO(NODE) (TYPE_CHECK (NODE)->type_common.pointer_to)
>  #define TYPE_REFERENCE_TO(NODE) (TYPE_CHECK
> (NODE)->type_common.reference_to)
> +//FIXME: we want
> +//#define TYPE_PRECISION(NODE) (SCALAR_TYPE_CHECK
> (NODE)->type_common.precision)
>  #define TYPE_PRECISION(NODE) (TYPE_CHECK (NODE)->type_common.precision)
>  #define TYPE_NAME(NODE) (TYPE_CHECK (NODE)->type_common.name)
>  #define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK
> (NODE)->type_common.next_variant)
>  #define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK
> (NODE)->type_common.main_variant)
>  #define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type_common.context)
>
>  /* Vector types need to check target flags to determine type.  */
>  extern enum machine_mode vector_type_mode (const_tree);
>  #define TYPE_MODE(NODE) \
>    (VECTOR_TYPE_P (TYPE_CHECK (NODE)) \
> @@ -4759,20 +4764,21 @@ extern tree make_vector_stat (unsigned M
>  extern tree build_vector_stat (tree, tree * MEM_STAT_DECL);
>  #define build_vector(t,v) build_vector_stat (t, v MEM_STAT_INFO)
>  extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *);
>  extern tree build_vector_from_val (tree, tree);
>  extern tree build_constructor (tree, vec<constructor_elt, va_gc> *);
>  extern tree build_constructor_single (tree, tree, tree);
>  extern tree build_constructor_from_list (tree, tree);
>  extern tree build_real_from_int_cst (tree, const_tree);
>  extern tree build_complex (tree, tree, tree);
>  extern tree build_one_cst (tree);
> +extern tree build_minus_one_cst (tree);
>  extern tree build_zero_cst (tree);
>  extern tree build_string (int, const char *);
>  extern tree build_tree_list_stat (tree, tree MEM_STAT_DECL);
>  #define build_tree_list(t,q) build_tree_list_stat(t,q MEM_STAT_INFO)
>  extern tree build_tree_list_vec_stat (const vec<tree, va_gc>
> *MEM_STAT_DECL);
>  #define build_tree_list_vec(v) build_tree_list_vec_stat (v MEM_STAT_INFO)
>  extern tree build_decl_stat (location_t, enum tree_code,
>                              tree, tree MEM_STAT_DECL);
>  extern tree build_fn_decl (const char *, tree);
>  #define build_decl(l,c,t,q) build_decl_stat (l,c,t,q MEM_STAT_INFO)
> @@ -4859,20 +4865,21 @@ tree_low_cst (const_tree t, int pos)
>  extern HOST_WIDE_INT size_low_cst (const_tree);
>  extern int tree_int_cst_sgn (const_tree);
>  extern int tree_int_cst_sign_bit (const_tree);
>  extern unsigned int tree_int_cst_min_precision (tree, bool);
>  extern bool tree_expr_nonnegative_p (tree);
>  extern bool tree_expr_nonnegative_warnv_p (tree, bool *);
>  extern bool may_negate_without_overflow_p (const_tree);
>  extern tree strip_array_types (tree);
>  extern tree excess_precision_type (tree);
>  extern bool valid_constant_size_p (const_tree);
> +extern unsigned int element_precision (const_tree);
>
>  /* Construct various nodes representing fract or accum data types.  */
>
>  extern tree make_fract_type (int, int, int);
>  extern tree make_accum_type (int, int, int);
>
>  #define make_signed_fract_type(P) make_fract_type (P, 0, 0)
>  #define make_unsigned_fract_type(P) make_fract_type (P, 1, 0)
>  #define make_sat_signed_fract_type(P) make_fract_type (P, 0, 1)
>  #define make_sat_unsigned_fract_type(P) make_fract_type (P, 1, 1)
> Index: gcc/gimple.c
> ===================================================================
> --- gcc/gimple.c        (revision 198685)
> +++ gcc/gimple.c        (working copy)
> @@ -3076,29 +3076,36 @@ iterative_hash_canonical_type (tree type
>       checked.  */
>    v = iterative_hash_hashval_t (TREE_CODE (type), 0);
>    v = iterative_hash_hashval_t (TREE_ADDRESSABLE (type), v);
>    v = iterative_hash_hashval_t (TYPE_ALIGN (type), v);
>    v = iterative_hash_hashval_t (TYPE_MODE (type), v);
>
>    /* Incorporate common features of numerical types.  */
>    if (INTEGRAL_TYPE_P (type)
>        || SCALAR_FLOAT_TYPE_P (type)
>        || FIXED_POINT_TYPE_P (type)
> -      || TREE_CODE (type) == VECTOR_TYPE
> -      || TREE_CODE (type) == COMPLEX_TYPE
>        || TREE_CODE (type) == OFFSET_TYPE
>        || POINTER_TYPE_P (type))
>      {
>        v = iterative_hash_hashval_t (TYPE_PRECISION (type), v);
>        v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v);
>      }
>
> +  if (VECTOR_TYPE_P (type))
> +    {
> +      v = iterative_hash_hashval_t (TYPE_VECTOR_SUBPARTS (type), v);
> +      v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v);
> +    }
> +
> +  if (TREE_CODE (type) == COMPLEX_TYPE)
> +    v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v);
> +
>    /* For pointer and reference types, fold in information about the type
>       pointed to but do not recurse to the pointed-to type.  */
>    if (POINTER_TYPE_P (type))
>      {
>        v = iterative_hash_hashval_t (TYPE_REF_CAN_ALIAS_ALL (type), v);
>        v = iterative_hash_hashval_t (TYPE_ADDR_SPACE (TREE_TYPE (type)), v);
>        v = iterative_hash_hashval_t (TYPE_RESTRICT (type), v);
>        v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v);
>      }
>
> Index: gcc/testsuite/gcc.dg/vector-shift.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/vector-shift.c (revision 0)
> +++ gcc/testsuite/gcc.dg/vector-shift.c (revision 0)
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fdump-tree-original" } */
> +
> +typedef unsigned vec __attribute__ ((vector_size (4 * sizeof (int))));
> +
> +void
> +f (vec *x)
> +{
> +  *x = (*x << 4) << 3;
> +}
> +
> +/* { dg-final { scan-tree-dump "<< 7" "original" } } */
> +/* { dg-final { cleanup-tree-dump "original" } } */
>
> Property changes on: gcc/testsuite/gcc.dg/vector-shift.c
> ___________________________________________________________________
> Added: svn:eol-style
>    + native
> Added: svn:keywords
>    + Author Date Id Revision URL
>
> Index: gcc/c-family/c-common.c
> ===================================================================
> --- gcc/c-family/c-common.c     (revision 198685)
> +++ gcc/c-family/c-common.c     (working copy)
> @@ -2220,21 +2220,21 @@ vector_types_convertible_p (const_tree t
>    static bool emitted_lax_note = false;
>    bool convertible_lax;
>
>    if ((TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2))
>        && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)))
>      return true;
>
>    convertible_lax =
>      (tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))
>       && (TREE_CODE (TREE_TYPE (t1)) != REAL_TYPE ||
> -        TYPE_PRECISION (t1) == TYPE_PRECISION (t2))
> +        TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2))
>       && (INTEGRAL_TYPE_P (TREE_TYPE (t1))
>          == INTEGRAL_TYPE_P (TREE_TYPE (t2))));
>
>    if (!convertible_lax || flag_lax_vector_conversions)
>      return convertible_lax;
>
>    if (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
>        && lang_hooks.types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2)))
>      return true;
>
> Index: gcc/fold-const.c
> ===================================================================
> --- gcc/fold-const.c    (revision 198685)
> +++ gcc/fold-const.c    (working copy)
> @@ -2438,21 +2438,22 @@ operand_equal_p (const_tree arg0, const_
>      return 0;
>
>    /* We cannot consider pointers to different address space equal.  */
>    if (POINTER_TYPE_P (TREE_TYPE (arg0)) && POINTER_TYPE_P (TREE_TYPE
> (arg1))
>        && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))
>           != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1)))))
>      return 0;
>
>    /* If both types don't have the same precision, then it is not safe
>       to strip NOPs.  */
> -  if (TYPE_PRECISION (TREE_TYPE (arg0)) != TYPE_PRECISION (TREE_TYPE
> (arg1)))
> +  if (element_precision (TREE_TYPE (arg0))
> +      != element_precision (TREE_TYPE (arg1)))
>      return 0;
>
>    STRIP_NOPS (arg0);
>    STRIP_NOPS (arg1);
>
>    /* In case both args are comparisons but with different comparison
>       code, try to swap the comparison operands of one arg to produce
>       a match and compare that variant.  */
>    if (TREE_CODE (arg0) != TREE_CODE (arg1)
>        && COMPARISON_CLASS_P (arg0)
> @@ -9870,20 +9871,21 @@ exact_inverse (tree type, tree cst)
>     return NULL_TREE.  */
>
>  tree
>  fold_binary_loc (location_t loc,
>              enum tree_code code, tree type, tree op0, tree op1)
>  {
>    enum tree_code_class kind = TREE_CODE_CLASS (code);
>    tree arg0, arg1, tem;
>    tree t1 = NULL_TREE;
>    bool strict_overflow_p;
> +  unsigned int prec;
>
>    gcc_assert (IS_EXPR_CODE_CLASS (kind)
>               && TREE_CODE_LENGTH (code) == 2
>               && op0 != NULL_TREE
>               && op1 != NULL_TREE);
>
>    arg0 = op0;
>    arg1 = op1;
>
>    /* Strip any conversions that don't change the mode.  This is
> @@ -10140,35 +10142,35 @@ fold_binary_loc (location_t loc,
>
>           /* ~X + X is -1.  */
>           if (TREE_CODE (arg0) == BIT_NOT_EXPR
>               && !TYPE_OVERFLOW_TRAPS (type))
>             {
>               tree tem = TREE_OPERAND (arg0, 0);
>
>               STRIP_NOPS (tem);
>               if (operand_equal_p (tem, arg1, 0))
>                 {
> -                 t1 = build_int_cst_type (type, -1);
> +                 t1 = build_minus_one_cst (type);
>                   return omit_one_operand_loc (loc, type, t1, arg1);
>                 }
>             }
>
>           /* X + ~X is -1.  */
>           if (TREE_CODE (arg1) == BIT_NOT_EXPR
>               && !TYPE_OVERFLOW_TRAPS (type))
>             {
>               tree tem = TREE_OPERAND (arg1, 0);
>
>               STRIP_NOPS (tem);
>               if (operand_equal_p (arg0, tem, 0))
>                 {
> -                 t1 = build_int_cst_type (type, -1);
> +                 t1 = build_minus_one_cst (type);
>                   return omit_one_operand_loc (loc, type, t1, arg0);
>                 }
>             }
>
>           /* X + (X / CST) * -CST is X % CST.  */
>           if (TREE_CODE (arg1) == MULT_EXPR
>               && TREE_CODE (TREE_OPERAND (arg1, 0)) == TRUNC_DIV_EXPR
>               && operand_equal_p (arg0,
>                                   TREE_OPERAND (TREE_OPERAND (arg1, 0), 0),
> 0))
>             {
> @@ -10380,75 +10382,76 @@ fold_binary_loc (location_t loc,
>         code0 = TREE_CODE (arg0);
>         code1 = TREE_CODE (arg1);
>         if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
>              || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
>             && operand_equal_p (TREE_OPERAND (arg0, 0),
>                                 TREE_OPERAND (arg1, 0), 0)
>             && (rtype = TREE_TYPE (TREE_OPERAND (arg0, 0)),
>                 TYPE_UNSIGNED (rtype))
>             /* Only create rotates in complete modes.  Other cases are not
>                expanded properly.  */
> -           && TYPE_PRECISION (rtype) == GET_MODE_PRECISION (TYPE_MODE
> (rtype)))
> +           && (element_precision (rtype)
> +               == element_precision (TYPE_MODE (rtype))))
>           {
>             tree tree01, tree11;
>             enum tree_code code01, code11;
>
>             tree01 = TREE_OPERAND (arg0, 1);
>             tree11 = TREE_OPERAND (arg1, 1);
>             STRIP_NOPS (tree01);
>             STRIP_NOPS (tree11);
>             code01 = TREE_CODE (tree01);
>             code11 = TREE_CODE (tree11);
>             if (code01 == INTEGER_CST
>                 && code11 == INTEGER_CST
>                 && TREE_INT_CST_HIGH (tree01) == 0
>                 && TREE_INT_CST_HIGH (tree11) == 0
>                 && ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
> -                   == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
> +                   == element_precision (TREE_TYPE (TREE_OPERAND (arg0,
> 0)))))
>               {
>                 tem = build2_loc (loc, LROTATE_EXPR,
>                                   TREE_TYPE (TREE_OPERAND (arg0, 0)),
>                                   TREE_OPERAND (arg0, 0),
>                                   code0 == LSHIFT_EXPR ? tree01 : tree11);
>                 return fold_convert_loc (loc, type, tem);
>               }
>             else if (code11 == MINUS_EXPR)
>               {
>                 tree tree110, tree111;
>                 tree110 = TREE_OPERAND (tree11, 0);
>                 tree111 = TREE_OPERAND (tree11, 1);
>                 STRIP_NOPS (tree110);
>                 STRIP_NOPS (tree111);
>                 if (TREE_CODE (tree110) == INTEGER_CST
>                     && 0 == compare_tree_int (tree110,
> -                                             TYPE_PRECISION
> +                                             element_precision
>                                               (TREE_TYPE (TREE_OPERAND
>                                                           (arg0, 0))))
>                     && operand_equal_p (tree01, tree111, 0))
>                   return
>                     fold_convert_loc (loc, type,
>                                       build2 ((code0 == LSHIFT_EXPR
>                                                ? LROTATE_EXPR
>                                                : RROTATE_EXPR),
>                                               TREE_TYPE (TREE_OPERAND (arg0,
> 0)),
>                                               TREE_OPERAND (arg0, 0),
> tree01));
>               }
>             else if (code01 == MINUS_EXPR)
>               {
>                 tree tree010, tree011;
>                 tree010 = TREE_OPERAND (tree01, 0);
>                 tree011 = TREE_OPERAND (tree01, 1);
>                 STRIP_NOPS (tree010);
>                 STRIP_NOPS (tree011);
>                 if (TREE_CODE (tree010) == INTEGER_CST
>                     && 0 == compare_tree_int (tree010,
> -                                             TYPE_PRECISION
> +                                             element_precision
>                                               (TREE_TYPE (TREE_OPERAND
>                                                           (arg0, 0))))
>                     && operand_equal_p (tree11, tree011, 0))
>                     return fold_convert_loc
>                       (loc, type,
>                        build2 ((code0 != LSHIFT_EXPR
>                                 ? LROTATE_EXPR
>                                 : RROTATE_EXPR),
>                                TREE_TYPE (TREE_OPERAND (arg0, 0)),
>                                TREE_OPERAND (arg0, 0), tree11));
> @@ -11750,22 +11753,21 @@ fold_binary_loc (location_t loc,
>             }
>         }
>
>        t1 = distribute_bit_expr (loc, code, type, arg0, arg1);
>        if (t1 != NULL_TREE)
>         return t1;
>        /* Simplify ((int)c & 0377) into (int)c, if c is unsigned char.  */
>        if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
>           && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
>         {
> -         unsigned int prec
> -           = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)));
> +         prec = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)));
>
>           if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_WIDE_INT
>               && (~TREE_INT_CST_LOW (arg1)
>                   & (((HOST_WIDE_INT) 1 << prec) - 1)) == 0)
>             return
>               fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
>         }
>
>        /* Convert (and (not arg0) (not arg1)) to (not (or (arg0) (arg1))).
>
> @@ -11819,21 +11821,21 @@ fold_binary_loc (location_t loc,
>             = tree_low_cst (arg1, TYPE_UNSIGNED (TREE_TYPE (arg1)));
>           unsigned HOST_WIDE_INT newmask, zerobits = 0;
>           tree shift_type = TREE_TYPE (arg0);
>
>           if (TREE_CODE (arg0) == LSHIFT_EXPR)
>             zerobits = ((((unsigned HOST_WIDE_INT) 1) << shiftc) - 1);
>           else if (TREE_CODE (arg0) == RSHIFT_EXPR
>                    && TYPE_PRECISION (TREE_TYPE (arg0))
>                       == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg0))))
>             {
> -             unsigned int prec = TYPE_PRECISION (TREE_TYPE (arg0));
> +             prec = TYPE_PRECISION (TREE_TYPE (arg0));
>               tree arg00 = TREE_OPERAND (arg0, 0);
>               /* See if more bits can be proven as zero because of
>                  zero extension.  */
>               if (TREE_CODE (arg00) == NOP_EXPR
>                   && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg00, 0))))
>                 {
>                   tree inner_type = TREE_TYPE (TREE_OPERAND (arg00, 0));
>                   if (TYPE_PRECISION (inner_type)
>                       == GET_MODE_BITSIZE (TYPE_MODE (inner_type))
>                       && TYPE_PRECISION (inner_type) < prec)
> @@ -11862,22 +11864,20 @@ fold_binary_loc (location_t loc,
>             }
>
>           /* ((X << 16) & 0xff00) is (X, 0).  */
>           if ((mask & zerobits) == mask)
>             return omit_one_operand_loc (loc, type,
>                                      build_int_cst (type, 0), arg0);
>
>           newmask = mask | zerobits;
>           if (newmask != mask && (newmask & (newmask + 1)) == 0)
>             {
> -             unsigned int prec;
> -
>               /* Only do the transformation if NEWMASK is some integer
>                  mode's mask.  */
>               for (prec = BITS_PER_UNIT;
>                    prec < HOST_BITS_PER_WIDE_INT; prec <<= 1)
>                 if (newmask == (((unsigned HOST_WIDE_INT) 1) << prec) - 1)
>                   break;
>               if (prec < HOST_BITS_PER_WIDE_INT
>                   || newmask == ~(unsigned HOST_WIDE_INT) 0)
>                 {
>                   tree newmaskt;
> @@ -12407,78 +12407,79 @@ fold_binary_loc (location_t loc,
>        if (integer_zerop (arg1))
>         return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0));
>        if (integer_zerop (arg0))
>         return omit_one_operand_loc (loc, type, arg0, arg1);
>
>        /* Since negative shift count is not well-defined,
>          don't try to compute it in the compiler.  */
>        if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
>         return NULL_TREE;
>
> +      prec = element_precision (type);
> +
>        /* Turn (a OP c1) OP c2 into a OP (c1+c2).  */
>        if (TREE_CODE (op0) == code && host_integerp (arg1, false)
> -         && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
> +         && TREE_INT_CST_LOW (arg1) < prec
>           && host_integerp (TREE_OPERAND (arg0, 1), false)
> -         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION
> (type))
> +         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < prec)
>         {
>           HOST_WIDE_INT low = (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))
>                                + TREE_INT_CST_LOW (arg1));
>
>           /* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2
>              being well defined.  */
> -         if (low >= TYPE_PRECISION (type))
> +         if (low >= prec)
>             {
>               if (code == LROTATE_EXPR || code == RROTATE_EXPR)
> -               low = low % TYPE_PRECISION (type);
> +               low = low % prec;
>               else if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR)
> -               return omit_one_operand_loc (loc, type, build_int_cst (type,
> 0),
> +               return omit_one_operand_loc (loc, type, build_zero_cst
> (type),
>                                          TREE_OPERAND (arg0, 0));
>               else
> -               low = TYPE_PRECISION (type) - 1;
> +               low = prec - 1;
>             }
>
>           return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
> -                             build_int_cst (type, low));
> +                                 build_int_cst (TREE_TYPE (arg1), low));
>         }
>
>        /* Transform (x >> c) << c into x & (-1<<c), or transform (x << c) >>
> c
>           into x & ((unsigned)-1 >> c) for unsigned types.  */
>        if (((code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR)
>             || (TYPE_UNSIGNED (type)
>                && code == RSHIFT_EXPR && TREE_CODE (arg0) == LSHIFT_EXPR))
>           && host_integerp (arg1, false)
> -         && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
> +         && TREE_INT_CST_LOW (arg1) < prec
>           && host_integerp (TREE_OPERAND (arg0, 1), false)
> -         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION
> (type))
> +         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < prec)
>         {
>           HOST_WIDE_INT low0 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
>           HOST_WIDE_INT low1 = TREE_INT_CST_LOW (arg1);
>           tree lshift;
>           tree arg00;
>
>           if (low0 == low1)
>             {
>               arg00 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
>
> -             lshift = build_int_cst (type, -1);
> -             lshift = int_const_binop (code, lshift, arg1);
> +             lshift = build_minus_one_cst (type);
> +             lshift = const_binop (code, lshift, arg1);
>
>               return fold_build2_loc (loc, BIT_AND_EXPR, type, arg00,
> lshift);
>             }
>         }
>
>        /* Rewrite an LROTATE_EXPR by a constant into an
>          RROTATE_EXPR by a new constant.  */
>        if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
>         {
> -         tree tem = build_int_cst (TREE_TYPE (arg1),
> -                                   TYPE_PRECISION (type));
> +         tree tem = build_int_cst (TREE_TYPE (arg1), prec);
>           tem = const_binop (MINUS_EXPR, tem, arg1);
>           return fold_build2_loc (loc, RROTATE_EXPR, type, op0, tem);
>         }
>
>        /* If we have a rotate of a bit operation with the rotate count and
>          the second operand of the bit operation both constant,
>          permute the two operations.  */
>        if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
>           && (TREE_CODE (arg0) == BIT_AND_EXPR
>               || TREE_CODE (arg0) == BIT_IOR_EXPR
> @@ -12492,21 +12493,21 @@ fold_binary_loc (location_t loc,
>
>        /* Two consecutive rotates adding up to the precision of the
>          type can be ignored.  */
>        if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
>           && TREE_CODE (arg0) == RROTATE_EXPR
>           && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
>           && TREE_INT_CST_HIGH (arg1) == 0
>           && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
>           && ((TREE_INT_CST_LOW (arg1)
>                + TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)))
> -             == (unsigned int) TYPE_PRECISION (type)))
> +             == prec))
>         return TREE_OPERAND (arg0, 0);
>
>        /* Fold (X & C2) << C1 into (X << C1) & (C2 << C1)
>               (X & C2) >> C1 into (X >> C1) & (C2 >> C1)
>          if the latter can be further optimized.  */
>        if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR)
>           && TREE_CODE (arg0) == BIT_AND_EXPR
>           && TREE_CODE (arg1) == INTEGER_CST
>           && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
>         {
> @@ -12905,22 +12906,22 @@ fold_binary_loc (location_t loc,
>          C1 is a valid shift constant, and C2 is a power of two, i.e.
>          a single bit.  */
>        if (TREE_CODE (arg0) == BIT_AND_EXPR
>           && TREE_CODE (TREE_OPERAND (arg0, 0)) == RSHIFT_EXPR
>           && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1))
>              == INTEGER_CST
>           && integer_pow2p (TREE_OPERAND (arg0, 1))
>           && integer_zerop (arg1))
>         {
>           tree itype = TREE_TYPE (arg0);
> -         unsigned HOST_WIDE_INT prec = TYPE_PRECISION (itype);
>           tree arg001 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 1);
> +         prec = TYPE_PRECISION (itype);
>
>           /* Check for a valid shift count.  */
>           if (TREE_INT_CST_HIGH (arg001) == 0
>               && TREE_INT_CST_LOW (arg001) < prec)
>             {
>               tree arg01 = TREE_OPERAND (arg0, 1);
>               tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
>               unsigned HOST_WIDE_INT log2 = tree_log2 (arg01);
>               /* If (C2 << C1) doesn't overflow, then ((X >> C1) & C2) != 0
>                  can be rewritten as (X & (C2 << C1)) != 0.  */
> Index: gcc/stor-layout.c
> ===================================================================
> --- gcc/stor-layout.c   (revision 198685)
> +++ gcc/stor-layout.c   (working copy)
> @@ -446,20 +446,32 @@ mode_for_vector (enum machine_mode inner
>
>  /* Return the alignment of MODE. This will be bounded by 1 and
>     BIGGEST_ALIGNMENT.  */
>
>  unsigned int
>  get_mode_alignment (enum machine_mode mode)
>  {
>    return MIN (BIGGEST_ALIGNMENT, MAX (1,
> mode_base_align[mode]*BITS_PER_UNIT));
>  }
>
> +/* Return the precision of the mode, or for a complex or vector mode the
> +   precision of the mode of its elements.  */
> +
> +unsigned int
> +element_precision (enum machine_mode mode)
> +{
> +  if (COMPLEX_MODE_P (mode) || VECTOR_MODE_P (mode))
> +    mode = GET_MODE_INNER (mode);
> +
> +  return GET_MODE_PRECISION (mode);
> +}
> +
>  /* Return the natural mode of an array, given that it is SIZE bytes in
>     total and has elements of type ELEM_TYPE.  */
>
>  static enum machine_mode
>  mode_for_array (tree elem_type, tree size)
>  {
>    tree elem_size;
>    unsigned HOST_WIDE_INT int_size, int_elem_size;
>    bool limit_p;
>
> Index: gcc/machmode.h
> ===================================================================
> --- gcc/machmode.h      (revision 198685)
> +++ gcc/machmode.h      (working copy)
> @@ -290,20 +290,24 @@ extern enum machine_mode get_best_mode (
>                                         enum machine_mode, bool);
>
>  /* Determine alignment, 1<=result<=BIGGEST_ALIGNMENT.  */
>
>  extern CONST_MODE_BASE_ALIGN unsigned char
> mode_base_align[NUM_MACHINE_MODES];
>
>  extern unsigned get_mode_alignment (enum machine_mode);
>
>  #define GET_MODE_ALIGNMENT(MODE) get_mode_alignment (MODE)
>
> +/* Get the precision of the mode or its inner mode if it has one.  */
> +
> +extern unsigned int element_precision (enum machine_mode);
> +
>  /* For each class, get the narrowest mode in that class.  */
>
>  extern const unsigned char class_narrowest_mode[MAX_MODE_CLASS];
>  #define GET_CLASS_NARROWEST_MODE(CLASS) \
>    ((enum machine_mode) class_narrowest_mode[CLASS])
>
>  /* Define the integer modes whose sizes are BITS_PER_UNIT and BITS_PER_WORD
>     and the mode whose class is Pmode and whose size is POINTER_SIZE.  */
>
>  extern enum machine_mode byte_mode;
>

Reply via email to