This patch makes fold-const.c operate directly on the VECTOR_CST encoding when folding an operation that has a single VECTOR_CST input.
Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64le-linux-gnu. Also spot-checked on sparc64-linux-gnu. OK to install? Thanks, Richard 2017-12-06 Richard Sandiford <richard.sandif...@linaro.org> gcc/ * fold-const.c (fold_negate_expr_1): Use tree_vector_builder and new_unary_operation, operating only on the encoded elements. (const_unop): Likewise. (exact_inverse): Likewise. (distributes_over_addition_p): New function. (const_binop): Use tree_vector_builder and new_unary_operation for combinations of VECTOR_CST and INTEGER_CST. Operate only on the encoded elements unless the encoding is strided and the operation does not distribute over addition. (fold_convert_const): Use tree_vector_builder and new_unary_operation. Operate only on the encoded elements for truncating integer conversions, or for non-stepped encodings. Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c 2017-12-06 14:48:52.887162217 +0000 +++ gcc/fold-const.c 2017-12-06 14:48:56.997993407 +0000 @@ -566,10 +566,10 @@ fold_negate_expr_1 (location_t loc, tree case VECTOR_CST: { - int count = VECTOR_CST_NELTS (t), i; - - auto_vec<tree, 32> elts (count); - for (i = 0; i < count; i++) + tree_vector_builder elts; + elts.new_unary_operation (type, t, true); + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) { tree elt = fold_negate_expr (loc, VECTOR_CST_ELT (t, i)); if (elt == NULL_TREE) @@ -577,7 +577,7 @@ fold_negate_expr_1 (location_t loc, tree elts.quick_push (elt); } - return build_vector (type, elts); + return elts.build (); } case COMPLEX_EXPR: @@ -1121,6 +1121,27 @@ int_const_binop (enum tree_code code, co return int_const_binop_1 (code, arg1, arg2, 1); } +/* Return true if binary operation OP distributes over addition in operand + OPNO, with the other operand being held constant. OPNO counts from 1. */ + +static bool +distributes_over_addition_p (tree_code op, int opno) +{ + switch (op) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + return true; + + case LSHIFT_EXPR: + return opno == 1; + + default: + return false; + } +} + /* Combine two constants ARG1 and ARG2 under operation CODE to produce a new constant. We assume ARG1 and ARG2 have the same data type, or at least are the same kind of constant and the same machine mode. Return zero if @@ -1442,10 +1463,12 @@ const_binop (enum tree_code code, tree a && TREE_CODE (arg2) == INTEGER_CST) { tree type = TREE_TYPE (arg1); - int count = VECTOR_CST_NELTS (arg1), i; - - auto_vec<tree, 32> elts (count); - for (i = 0; i < count; i++) + bool step_ok_p = distributes_over_addition_p (code, 1); + tree_vector_builder elts; + if (!elts.new_unary_operation (type, arg1, step_ok_p)) + return NULL_TREE; + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) { tree elem1 = VECTOR_CST_ELT (arg1, i); @@ -1458,7 +1481,7 @@ const_binop (enum tree_code code, tree a elts.quick_push (elt); } - return build_vector (type, elts); + return elts.build (); } return NULL_TREE; } @@ -1649,10 +1672,12 @@ const_unop (enum tree_code code, tree ty else if (TREE_CODE (arg0) == VECTOR_CST) { tree elem; - unsigned count = VECTOR_CST_NELTS (arg0), i; - auto_vec<tree, 32> elements (count); - for (i = 0; i < count; i++) + /* This can cope with stepped encodings because ~x == -1 - x. */ + tree_vector_builder elements; + elements.new_unary_operation (type, arg0, true); + unsigned int i, count = elements.encoded_nelts (); + for (i = 0; i < count; ++i) { elem = VECTOR_CST_ELT (arg0, i); elem = const_unop (BIT_NOT_EXPR, TREE_TYPE (type), elem); @@ -1661,7 +1686,7 @@ const_unop (enum tree_code code, tree ty elements.quick_push (elem); } if (i == count) - return build_vector (type, elements); + return elements.build (); } break; @@ -2135,10 +2160,19 @@ fold_convert_const (enum tree_code code, if (TREE_CODE (arg1) == VECTOR_CST && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1)) { - int len = VECTOR_CST_NELTS (arg1); tree elttype = TREE_TYPE (type); - auto_vec<tree, 32> v (len); - for (int i = 0; i < len; ++i) + tree arg1_elttype = TREE_TYPE (TREE_TYPE (arg1)); + /* We can't handle steps directly when extending, since the + values need to wrap at the original precision first. */ + bool step_ok_p + = (INTEGRAL_TYPE_P (elttype) + && INTEGRAL_TYPE_P (arg1_elttype) + && TYPE_PRECISION (elttype) <= TYPE_PRECISION (arg1_elttype)); + tree_vector_builder v; + if (!v.new_unary_operation (type, arg1, step_ok_p)) + return NULL_TREE; + unsigned int len = v.encoded_nelts (); + for (unsigned int i = 0; i < len; ++i) { tree elt = VECTOR_CST_ELT (arg1, i); tree cvt = fold_convert_const (code, elttype, elt); @@ -2146,7 +2180,7 @@ fold_convert_const (enum tree_code code, return NULL_TREE; v.quick_push (cvt); } - return build_vector (type, v); + return v.build (); } } return NULL_TREE; @@ -8832,7 +8866,6 @@ exact_inverse (tree type, tree cst) REAL_VALUE_TYPE r; tree unit_type; machine_mode mode; - unsigned vec_nelts, i; switch (TREE_CODE (cst)) { @@ -8846,12 +8879,14 @@ exact_inverse (tree type, tree cst) case VECTOR_CST: { - vec_nelts = VECTOR_CST_NELTS (cst); unit_type = TREE_TYPE (type); mode = TYPE_MODE (unit_type); - auto_vec<tree, 32> elts (vec_nelts); - for (i = 0; i < vec_nelts; i++) + tree_vector_builder elts; + if (!elts.new_unary_operation (type, cst, false)) + return NULL_TREE; + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) { r = TREE_REAL_CST (VECTOR_CST_ELT (cst, i)); if (!exact_real_inverse (mode, &r)) @@ -8859,7 +8894,7 @@ exact_inverse (tree type, tree cst) elts.quick_push (build_real (unit_type, r)); } - return build_vector (type, elts); + return elts.build (); } default: