From patchwork Tue May 7 21:26:10 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Glisse X-Patchwork-Id: 242465 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 8E7622C0173 for ; Wed, 8 May 2013 07:26:25 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=LcGuX8wG3b4WzCqi565KLjsrSIn+8D66ij1xTZj5cvsnhLUy/iZZk Hjmz8cfoj4ZkRjvHHppEKsWq4VzezYRqaN88fUr1jpnYs1w9jfIuAjwSYSVHppNs EJlJ8jx+tCaVWjQ61sTUamsmcK3O9QW6JKDgBq2z8olIsjIaRcIqUs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=kFVZz48PQdvxH/sBSOUW/u8e6Es=; b=xuaImtJ6pkTy5yt4sMX0 RT8eFshGm9GEe0O1hMN9R6iOr2Jhjhh7xANqiQp/loAwVSbgiKwahec5EK6Hyavt UbMAOuR8Y2bcT3qcerG3iCc5QUvqlKlLql7HqLf7uuSLatnE7ptJOfkMngxCzYxe CtJ3i5xXYyM+V8Z9gvxOW0w= Received: (qmail 21388 invoked by alias); 7 May 2013 21:26:17 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 21375 invoked by uid 89); 7 May 2013 21:26:16 -0000 X-Spam-SWARE-Status: No, score=-5.6 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD autolearn=ham version=3.3.1 Received: from mail2-relais-roc.national.inria.fr (HELO mail2-relais-roc.national.inria.fr) (192.134.164.83) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Tue, 07 May 2013 21:26:13 +0000 Received: from stedding.saclay.inria.fr ([193.55.250.194]) by mail2-relais-roc.national.inria.fr with ESMTP/TLS/DHE-RSA-AES128-SHA; 07 May 2013 23:26:10 +0200 Received: from glisse (helo=localhost) by stedding.saclay.inria.fr with local-esmtp (Exim 4.80) (envelope-from ) id 1UZpOk-0006lv-I3 for gcc-patches@gcc.gnu.org; Tue, 07 May 2013 23:26:10 +0200 Date: Tue, 7 May 2013 23:26:10 +0200 (CEST) From: Marc Glisse To: gcc-patches@gcc.gnu.org Subject: TYPE_PRECISION for vectors Message-ID: User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) MIME-Version: 1.0 X-Virus-Found: No 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. 2013-05-07 Marc Glisse 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. 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 *); extern tree build_vector_from_val (tree, tree); extern tree build_constructor (tree, vec *); 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 *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 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;