From patchwork Mon Nov 12 13:31:32 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: bit_field_ref of constructor of vectors Date: Mon, 12 Nov 2012 03:31:32 -0000 From: Marc Glisse X-Patchwork-Id: 198389 Message-Id: To: gcc-patches@gcc.gnu.org Hello, this patch lets us fold a bit_field_ref of a constructor even when the elements are vectors. Writing a testcase is not that convenient because of the lack of a dead code elimination pass after forwprop4 (RTL doesn't always remove everything either), but I see a clear difference on this test on x86_64 without AVX. typedef double vec __attribute__((vector_size(4*sizeof(double)))); void f(vec*x){ *x+=*x+*x; } double g(vec*x){ return (*x+*x)[3]; } void h(vec*x, double a, double b, double c, double d){ vec y={a,b,c,d}; *x+=y; } I don't know if the patch (assuming it is ok) is suitable for stage 3, it may have to wait. It passes bootstrap+testsuite. I am still not quite sure why we even have a valid_gimple_rhs_p function (after which we usually give up if it says no) instead of gimplifying, so I may have missed a reason why CONSTRUCTOR or BIT_FIELD_REF shouldn't be ok. 2012-11-12 Marc Glisse * fold-const.c (fold_ternary_loc) [BIT_FIELD_REF]: Handle CONSTRUCTOR with vector elements. * tree-ssa-propagate.c (valid_gimple_rhs_p): Handle CONSTRUCTOR and BIT_FIELD_REF. Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 193429) +++ gcc/fold-const.c (working copy) @@ -14054,65 +14054,75 @@ fold_ternary_loc (location_t loc, enum t unsigned HOST_WIDE_INT n = tree_low_cst (arg1, 1); unsigned HOST_WIDE_INT idx = tree_low_cst (op2, 1); if (n != 0 && (idx % width) == 0 && (n % width) == 0 && ((idx + n) / width) <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0))) { idx = idx / width; n = n / width; - if (TREE_CODE (type) == VECTOR_TYPE) + + if (TREE_CODE (arg0) == VECTOR_CST) { - if (TREE_CODE (arg0) == VECTOR_CST) - { - tree *vals = XALLOCAVEC (tree, n); - unsigned i; - for (i = 0; i < n; ++i) - vals[i] = VECTOR_CST_ELT (arg0, idx + i); - return build_vector (type, vals); - } - else - { - VEC(constructor_elt, gc) *vals; - unsigned i; - if (CONSTRUCTOR_NELTS (arg0) == 0) - return build_constructor (type, NULL); - if (TREE_CODE (TREE_TYPE (CONSTRUCTOR_ELT (arg0, - 0)->value)) - != VECTOR_TYPE) - { - vals = VEC_alloc (constructor_elt, gc, n); - for (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); - } - } + if (n == 1) + return VECTOR_CST_ELT (arg0, idx); + + tree *vals = XALLOCAVEC (tree, n); + for (unsigned i = 0; i < n; ++i) + 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); } - else if (n == 1) + + /* We keep an exact subset of the constructor elements. */ + if ((idx % k) == 0 && (n % k) == 0) { - if (TREE_CODE (arg0) == VECTOR_CST) - return VECTOR_CST_ELT (arg0, idx); - else if (CONSTRUCTOR_NELTS (arg0) == 0) - return build_zero_cst (type); - else if (TREE_CODE (TREE_TYPE (CONSTRUCTOR_ELT (arg0, - 0)->value)) - != VECTOR_TYPE) + VEC(constructor_elt, gc) *vals; + 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); } + vals = VEC_alloc (constructor_elt, gc, 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_low_cst (arg1, 1) && integer_zerop (op2)) return fold_convert_loc (loc, type, arg0); Index: gcc/tree-ssa-propagate.c =================================================================== --- gcc/tree-ssa-propagate.c (revision 193429) +++ gcc/tree-ssa-propagate.c (working copy) @@ -610,24 +610,38 @@ valid_gimple_rhs_p (tree expr) break; } return false; } break; case tcc_vl_exp: return false; case tcc_exceptional: + if (code == CONSTRUCTOR) + { + unsigned i; + tree elt; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), i, elt) + if (!is_gimple_val (elt)) + return false; + return true; + } if (code != SSA_NAME) return false; break; + case tcc_reference: + if (code == BIT_FIELD_REF) + return is_gimple_val (TREE_OPERAND (expr, 0)); + return false; + default: return false; } return true; } /* Return true if EXPR is a CALL_EXPR suitable for representation as a single GIMPLE_CALL statement. If the arguments require