Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard.
2016-05-04 Richard Biener <rguent...@suse.de> * match.pd: Add BIT_FIELD_REF canonicalizations and vector constructor simplifications. * fold-const.c (fold_ternary_loc): Remove duplicate functionality here. Index: gcc/match.pd =================================================================== *** gcc/match.pd.orig 2016-05-03 15:15:58.002994741 +0200 --- gcc/match.pd 2016-05-04 09:35:57.656880256 +0200 *************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) *** 3256,3258 **** --- 3256,3354 ---- WARN_STRICT_OVERFLOW_COMPARISON); } (cmp @0 { res; }))))))))) + + /* Canonicalizations of BIT_FIELD_REFs. */ + + (simplify + (BIT_FIELD_REF @0 @1 @2) + (switch + (if (TREE_CODE (TREE_TYPE (@0)) == COMPLEX_TYPE + && tree_int_cst_equal (@1, TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0))))) + (switch + (if (integer_zerop (@2)) + (view_convert (realpart @0))) + (if (tree_int_cst_equal (@2, TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0))))) + (view_convert (imagpart @0))))) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && INTEGRAL_TYPE_P (type) + /* A bit-field-ref that referenced the full argument can be stripped. */ + && ((compare_tree_int (@1, TYPE_PRECISION (TREE_TYPE (@0))) == 0 + && integer_zerop (@2)) + /* Low-parts can be reduced to integral conversions. + ??? The following doesn't work for PDP endian. */ + || (BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN + /* Don't even think about BITS_BIG_ENDIAN. */ + && TYPE_PRECISION (TREE_TYPE (@0)) % BITS_PER_UNIT == 0 + && TYPE_PRECISION (type) % BITS_PER_UNIT == 0 + && compare_tree_int (@2, (BYTES_BIG_ENDIAN + ? (TYPE_PRECISION (TREE_TYPE (@0)) + - TYPE_PRECISION (type)) + : 0)) == 0))) + (convert @0)))) + + /* Simplify vector extracts. */ + + (simplify + (BIT_FIELD_REF CONSTRUCTOR@0 @1 @2) + (if (VECTOR_TYPE_P (TREE_TYPE (@0)) + && (types_match (type, TREE_TYPE (TREE_TYPE (@0))) + || (VECTOR_TYPE_P (type) + && types_match (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (@0)))))) + (with + { + tree ctor = (TREE_CODE (@0) == SSA_NAME + ? gimple_assign_rhs1 (SSA_NAME_DEF_STMT (@0)) : @0); + tree eltype = TREE_TYPE (TREE_TYPE (ctor)); + unsigned HOST_WIDE_INT width = tree_to_uhwi (TYPE_SIZE (eltype)); + unsigned HOST_WIDE_INT n = tree_to_uhwi (@1); + unsigned HOST_WIDE_INT idx = tree_to_uhwi (@2); + } + (if (n != 0 + && (idx % width) == 0 + && (n % width) == 0 + && ((idx + n) / width) <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (ctor))) + (with + { + idx = idx / width; + n = n / width; + /* Constructor elements can be subvectors. */ + unsigned HOST_WIDE_INT k = 1; + if (CONSTRUCTOR_NELTS (ctor) != 0) + { + tree cons_elem = TREE_TYPE (CONSTRUCTOR_ELT (ctor, 0)->value); + if (TREE_CODE (cons_elem) == VECTOR_TYPE) + k = TYPE_VECTOR_SUBPARTS (cons_elem); + } + } + (switch + /* We keep an exact subset of the constructor elements. */ + (if ((idx % k) == 0 && (n % k) == 0) + (if (CONSTRUCTOR_NELTS (ctor) == 0) + { build_constructor (type, NULL); } + (with + { + idx /= k; + n /= k; + } + (if (n == 1) + (if (idx < CONSTRUCTOR_NELTS (ctor)) + { CONSTRUCTOR_ELT (ctor, idx)->value; } + { build_zero_cst (type); }) + { + vec<constructor_elt, va_gc> *vals; + vec_alloc (vals, n); + for (unsigned i = 0; + i < n && idx + i < CONSTRUCTOR_NELTS (ctor); ++i) + CONSTRUCTOR_APPEND_ELT (vals, NULL_TREE, + CONSTRUCTOR_ELT (ctor, idx + i)->value); + build_constructor (type, vals); + })))) + /* The bitfield references a single constructor element. */ + (if (idx + n <= (idx / k + 1) * k) + (switch + (if (CONSTRUCTOR_NELTS (ctor) <= idx / k) + { build_zero_cst (type); }) + (if (n == k) + { CONSTRUCTOR_ELT (ctor, idx / k)->value; }) + (BIT_FIELD_REF { CONSTRUCTOR_ELT (ctor, idx / k)->value; } + @1 { bitsize_int ((idx % k) * width); }))))))))) Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c.orig 2016-05-03 14:20:49.209109405 +0200 --- gcc/fold-const.c 2016-05-03 16:17:58.209422083 +0200 *************** fold_ternary_loc (location_t loc, enum t *** 11729,11737 **** gcc_unreachable (); case BIT_FIELD_REF: ! if ((TREE_CODE (arg0) == VECTOR_CST ! || (TREE_CODE (arg0) == CONSTRUCTOR ! && TREE_CODE (TREE_TYPE (arg0)) == VECTOR_TYPE)) && (type == TREE_TYPE (TREE_TYPE (arg0)) || (TREE_CODE (type) == VECTOR_TYPE && TREE_TYPE (type) == TREE_TYPE (TREE_TYPE (arg0))))) --- 11729,11735 ---- gcc_unreachable (); case BIT_FIELD_REF: ! if (TREE_CODE (arg0) == VECTOR_CST && (type == TREE_TYPE (TREE_TYPE (arg0)) || (TREE_CODE (type) == VECTOR_TYPE && TREE_TYPE (type) == TREE_TYPE (TREE_TYPE (arg0))))) *************** fold_ternary_loc (location_t loc, enum t *** 11759,11846 **** vals[i] = VECTOR_CST_ELT (arg0, idx + i); return build_vector (type, vals); } - - /* Constructor elements can be subvectors. */ - unsigned HOST_WIDE_INT k = 1; - if (CONSTRUCTOR_NELTS (arg0) != 0) - { - tree cons_elem = TREE_TYPE (CONSTRUCTOR_ELT (arg0, 0)->value); - if (TREE_CODE (cons_elem) == VECTOR_TYPE) - k = TYPE_VECTOR_SUBPARTS (cons_elem); - } - - /* We keep an exact subset of the constructor elements. */ - if ((idx % k) == 0 && (n % k) == 0) - { - if (CONSTRUCTOR_NELTS (arg0) == 0) - return build_constructor (type, NULL); - idx /= k; - n /= k; - if (n == 1) - { - if (idx < CONSTRUCTOR_NELTS (arg0)) - return CONSTRUCTOR_ELT (arg0, idx)->value; - return build_zero_cst (type); - } - - vec<constructor_elt, va_gc> *vals; - vec_alloc (vals, n); - for (unsigned i = 0; - i < n && idx + i < CONSTRUCTOR_NELTS (arg0); - ++i) - CONSTRUCTOR_APPEND_ELT (vals, NULL_TREE, - CONSTRUCTOR_ELT - (arg0, idx + i)->value); - return build_constructor (type, vals); - } - /* The bitfield references a single constructor element. */ - else if (idx + n <= (idx / k + 1) * k) - { - if (CONSTRUCTOR_NELTS (arg0) <= idx / k) - return build_zero_cst (type); - else if (n == k) - return CONSTRUCTOR_ELT (arg0, idx / k)->value; - else - return fold_build3_loc (loc, code, type, - CONSTRUCTOR_ELT (arg0, idx / k)->value, op1, - build_int_cst (TREE_TYPE (op2), (idx % k) * width)); - } } } - /* A bit-field-ref that referenced the full argument can be stripped. */ - if (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) - && TYPE_PRECISION (TREE_TYPE (arg0)) == tree_to_uhwi (arg1) - && integer_zerop (op2)) - return fold_convert_loc (loc, type, arg0); - /* On constants we can use native encode/interpret to constant fold (nearly) all BIT_FIELD_REFs. */ if (CONSTANT_CLASS_P (arg0) && can_native_interpret_type_p (type) ! && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (arg0))) ! /* This limitation should not be necessary, we just need to ! round this up to mode size. */ ! && tree_to_uhwi (op1) % BITS_PER_UNIT == 0 ! /* Need bit-shifting of the buffer to relax the following. */ ! && tree_to_uhwi (op2) % BITS_PER_UNIT == 0) { unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); unsigned HOST_WIDE_INT bitsize = tree_to_uhwi (op1); ! unsigned HOST_WIDE_INT clen; ! clen = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (arg0))); ! /* ??? We cannot tell native_encode_expr to start at ! some random byte only. So limit us to a reasonable amount ! of work. */ ! if (clen <= 4096) { ! unsigned char *b = XALLOCAVEC (unsigned char, clen); ! unsigned HOST_WIDE_INT len = native_encode_expr (arg0, b, clen); if (len > 0 ! && len * BITS_PER_UNIT >= bitpos + bitsize) { ! tree v = native_interpret_expr (type, ! b + bitpos / BITS_PER_UNIT, bitsize / BITS_PER_UNIT); if (v) return v; --- 11757,11788 ---- vals[i] = VECTOR_CST_ELT (arg0, idx + i); return build_vector (type, vals); } } } /* On constants we can use native encode/interpret to constant fold (nearly) all BIT_FIELD_REFs. */ if (CONSTANT_CLASS_P (arg0) && can_native_interpret_type_p (type) ! && BITS_PER_UNIT == 8) { unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); unsigned HOST_WIDE_INT bitsize = tree_to_uhwi (op1); ! /* Limit us to a reasonable amount of work. To relax the ! other limitations we need bit-shifting of the buffer ! and rounding up the size. */ ! if (bitpos % BITS_PER_UNIT == 0 ! && bitsize % BITS_PER_UNIT == 0 ! && bitsize <= MAX_BITSIZE_MODE_ANY_MODE) { ! unsigned char b[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT]; ! unsigned HOST_WIDE_INT len ! = native_encode_expr (arg0, b, bitsize / BITS_PER_UNIT, ! bitpos / BITS_PER_UNIT); if (len > 0 ! && len * BITS_PER_UNIT >= bitsize) { ! tree v = native_interpret_expr (type, b, bitsize / BITS_PER_UNIT); if (v) return v;