On Tue, 17 May 2016, Michael Matz wrote: > Hi, > > On Tue, 17 May 2016, Richard Biener wrote: > > > BIT_INSERT_EXPR > > This. > > > Any preference?
Here is an updated patch. Bootstrapped and tested on x86_64-unknown-linux-gnu. I plan to commit this tomorrow if there are no further comments. Thanks, Richard. 2011-06-19 Richard Guenther <rguent...@suse.de> PR tree-optimization/29756 * tree.def (BIT_INSERT_EXPR): New tcc_expression tree code. * expr.c (expand_expr_real_2): Handle BIT_INSERT_EXPR. * fold-const.c (operand_equal_p): Likewise. (fold_ternary_loc): Add constant folding of BIT_INSERT_EXPR. * gimplify.c (gimplify_expr): Handle BIT_INSERT_EXPR. * tree-inline.c (estimate_operator_cost): Likewise. * tree-pretty-print.c (dump_generic_node): Likewise. * tree-ssa-operands.c (get_expr_operands): Likewise. * cfgexpand.c (expand_debug_expr): Likewise. * gimple-pretty-print.c (dump_ternary_rhs): Likewise. * gimple.c (get_gimple_rhs_num_ops): Handle BIT_INSERT_EXPR. * tree-cfg.c (verify_gimple_assign_ternary): Verify BIT_INSERT_EXPR. * tree-ssa.c (non_rewritable_lvalue_p): We can rewrite vector inserts using BIT_FIELD_REF or MEM_REF on the lhs. (execute_update_addresses_taken): Do it. * gcc.dg/tree-ssa/vector-6.c: New testcase. Index: trunk/gcc/expr.c =================================================================== *** trunk.orig/gcc/expr.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/expr.c 2016-05-19 10:23:35.667140692 +0200 *************** expand_expr_real_2 (sepops ops, rtx targ *** 9225,9230 **** --- 9225,9247 ---- target = expand_vec_cond_expr (type, treeop0, treeop1, treeop2, target); return target; + case BIT_INSERT_EXPR: + { + unsigned bitpos = tree_to_uhwi (treeop2); + unsigned bitsize; + if (INTEGRAL_TYPE_P (TREE_TYPE (treeop1))) + bitsize = TYPE_PRECISION (TREE_TYPE (treeop1)); + else + bitsize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (treeop1))); + rtx op0 = expand_normal (treeop0); + rtx op1 = expand_normal (treeop1); + rtx dst = gen_reg_rtx (mode); + emit_move_insn (dst, op0); + store_bit_field (dst, bitsize, bitpos, 0, 0, + TYPE_MODE (TREE_TYPE (treeop1)), op1, false); + return dst; + } + default: gcc_unreachable (); } Index: trunk/gcc/fold-const.c =================================================================== *** trunk.orig/gcc/fold-const.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/fold-const.c 2016-05-19 10:23:35.699141058 +0200 *************** operand_equal_p (const_tree arg0, const_ *** 3163,3168 **** --- 3163,3169 ---- case VEC_COND_EXPR: case DOT_PROD_EXPR: + case BIT_INSERT_EXPR: return OP_SAME (0) && OP_SAME (1) && OP_SAME (2); default: *************** fold_ternary_loc (location_t loc, enum t *** 11870,11875 **** --- 11871,11916 ---- } return NULL_TREE; + case BIT_INSERT_EXPR: + /* Perform (partial) constant folding of BIT_INSERT_EXPR. */ + if (TREE_CODE (arg0) == INTEGER_CST + && TREE_CODE (arg1) == INTEGER_CST) + { + unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); + unsigned bitsize = TYPE_PRECISION (TREE_TYPE (arg1)); + wide_int tem = wi::bit_and (arg0, + wi::shifted_mask (bitpos, bitsize, true, + TYPE_PRECISION (type))); + wide_int tem2 + = wi::lshift (wi::zext (wi::to_wide (arg1, TYPE_PRECISION (type)), + bitsize), bitpos); + return wide_int_to_tree (type, wi::bit_or (tem, tem2)); + } + else if (TREE_CODE (arg0) == VECTOR_CST + && CONSTANT_CLASS_P (arg1) + && types_compatible_p (TREE_TYPE (TREE_TYPE (arg0)), + TREE_TYPE (arg1))) + { + unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); + unsigned HOST_WIDE_INT elsize + = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg1))); + if (bitpos % elsize == 0) + { + unsigned k = bitpos / elsize; + if (operand_equal_p (VECTOR_CST_ELT (arg0, k), arg1, 0)) + return arg0; + else + { + tree *elts = XALLOCAVEC (tree, TYPE_VECTOR_SUBPARTS (type)); + memcpy (elts, VECTOR_CST_ELTS (arg0), + sizeof (tree) * TYPE_VECTOR_SUBPARTS (type)); + elts[k] = arg1; + return build_vector (type, elts); + } + } + } + return NULL_TREE; + default: return NULL_TREE; } /* switch (code) */ Index: trunk/gcc/gimplify.c =================================================================== *** trunk.orig/gcc/gimplify.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/gimplify.c 2016-05-19 10:23:35.723141333 +0200 *************** gimplify_expr (tree *expr_p, gimple_seq *** 10950,10955 **** --- 10950,10959 ---- /* Classified as tcc_expression. */ goto expr_3; + case BIT_INSERT_EXPR: + /* Argument 3 is a constant. */ + goto expr_2; + case POINTER_PLUS_EXPR: { enum gimplify_status r0, r1; Index: trunk/gcc/tree-inline.c =================================================================== *** trunk.orig/gcc/tree-inline.c 2016-05-18 09:42:22.733237510 +0200 --- trunk/gcc/tree-inline.c 2016-05-19 10:23:35.739141516 +0200 *************** estimate_operator_cost (enum tree_code c *** 3941,3946 **** --- 3941,3950 ---- return weights->div_mod_cost; return 1; + /* Bit-field insertion needs several shift and mask operations. */ + case BIT_INSERT_EXPR: + return 3; + default: /* We expect a copy assignment with no operator. */ gcc_assert (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS); Index: trunk/gcc/tree-pretty-print.c =================================================================== *** trunk.orig/gcc/tree-pretty-print.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/tree-pretty-print.c 2016-05-19 10:23:35.763141790 +0200 *************** dump_generic_node (pretty_printer *pp, t *** 1876,1881 **** --- 1876,1898 ---- pp_greater (pp); break; + case BIT_INSERT_EXPR: + pp_string (pp, "BIT_INSERT_EXPR <"); + dump_generic_node (pp, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (pp, ", "); + dump_generic_node (pp, TREE_OPERAND (node, 1), spc, flags, false); + pp_string (pp, ", "); + dump_generic_node (pp, TREE_OPERAND (node, 2), spc, flags, false); + pp_string (pp, " ("); + if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 1)))) + pp_decimal_int (pp, + TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (node, 1)))); + else + dump_generic_node (pp, TYPE_SIZE (TREE_TYPE (TREE_OPERAND (node, 1))), + spc, flags, false); + pp_string (pp, " bits)>"); + break; + case ARRAY_REF: case ARRAY_RANGE_REF: op0 = TREE_OPERAND (node, 0); Index: trunk/gcc/tree-ssa-operands.c =================================================================== *** trunk.orig/gcc/tree-ssa-operands.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/tree-ssa-operands.c 2016-05-19 10:23:35.779141973 +0200 *************** get_expr_operands (struct function *fn, *** 833,838 **** --- 833,839 ---- get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0), flags); return; + case BIT_INSERT_EXPR: case COMPOUND_EXPR: case OBJ_TYPE_REF: case ASSERT_EXPR: Index: trunk/gcc/tree.def =================================================================== *** trunk.orig/gcc/tree.def 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/tree.def 2016-05-19 10:23:35.779141973 +0200 *************** DEFTREECODE (ADDR_EXPR, "addr_expr", tcc *** 852,857 **** --- 852,871 ---- descriptor of type ptr_mode. */ DEFTREECODE (FDESC_EXPR, "fdesc_expr", tcc_expression, 2) + /* Given a word, a value and a bit position within the word, + produce the value that results if replacing the parts of word + starting at the bit position with value. + Operand 0 is a tree for the word of integral or vector type; + Operand 1 is a tree for the value of integral or vector element type; + Operand 2 is a tree giving the constant position of the first referenced bit; + The number of bits replaced is given by the precision of the value + type if that is integral or by its size if it is non-integral. + ??? The reason to make the size of the replacement implicit is to not + have a quaternary operation. + The replaced bits shall be fully inside the word. If the word is of + vector type the replaced bits shall be aligned with its elements. */ + DEFTREECODE (BIT_INSERT_EXPR, "bit_field_insert", tcc_expression, 3) + /* Given two real or integer operands of the same type, returns a complex value of the corresponding complex type. */ DEFTREECODE (COMPLEX_EXPR, "complex_expr", tcc_binary, 2) Index: trunk/gcc/cfgexpand.c =================================================================== *** trunk.orig/gcc/cfgexpand.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/cfgexpand.c 2016-05-19 10:23:35.787142064 +0200 *************** expand_debug_expr (tree exp) *** 5025,5030 **** --- 5025,5031 ---- case FIXED_CONVERT_EXPR: case OBJ_TYPE_REF: case WITH_SIZE_EXPR: + case BIT_INSERT_EXPR: return NULL; case DOT_PROD_EXPR: Index: trunk/gcc/gimple-pretty-print.c =================================================================== *** trunk.orig/gcc/gimple-pretty-print.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/gimple-pretty-print.c 2016-05-19 10:23:35.787142064 +0200 *************** dump_ternary_rhs (pretty_printer *buffer *** 479,484 **** --- 479,502 ---- pp_greater (buffer); break; + case BIT_INSERT_EXPR: + pp_string (buffer, "BIT_INSERT_EXPR <"); + dump_generic_node (buffer, gimple_assign_rhs1 (gs), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, gimple_assign_rhs2 (gs), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, gimple_assign_rhs3 (gs), spc, flags, false); + pp_string (buffer, " ("); + if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs2 (gs)))) + pp_decimal_int (buffer, + TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs2 (gs)))); + else + dump_generic_node (buffer, + TYPE_SIZE (TREE_TYPE (gimple_assign_rhs2 (gs))), + spc, flags, false); + pp_string (buffer, " bits)>"); + break; + default: gcc_unreachable (); } Index: trunk/gcc/gimple.c =================================================================== *** trunk.orig/gcc/gimple.c 2016-05-18 13:45:15.350948365 +0200 --- trunk/gcc/gimple.c 2016-05-19 10:23:35.787142064 +0200 *************** get_gimple_rhs_num_ops (enum tree_code c *** 2044,2049 **** --- 2044,2050 ---- || (SYM) == REALIGN_LOAD_EXPR \ || (SYM) == VEC_COND_EXPR \ || (SYM) == VEC_PERM_EXPR \ + || (SYM) == BIT_INSERT_EXPR \ || (SYM) == FMA_EXPR) ? GIMPLE_TERNARY_RHS \ : ((SYM) == CONSTRUCTOR \ || (SYM) == OBJ_TYPE_REF \ Index: trunk/gcc/tree-cfg.c =================================================================== *** trunk.orig/gcc/tree-cfg.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/tree-cfg.c 2016-05-19 10:23:35.799142201 +0200 *************** verify_gimple_assign_ternary (gassign *s *** 4155,4160 **** --- 4155,4207 ---- return false; + case BIT_INSERT_EXPR: + if (! useless_type_conversion_p (lhs_type, rhs1_type)) + { + error ("type mismatch in BIT_INSERT_EXPR"); + debug_generic_expr (lhs_type); + debug_generic_expr (rhs1_type); + return true; + } + if (! ((INTEGRAL_TYPE_P (rhs1_type) + && INTEGRAL_TYPE_P (rhs2_type)) + || (VECTOR_TYPE_P (rhs1_type) + && types_compatible_p (TREE_TYPE (rhs1_type), rhs2_type)))) + { + error ("not allowed type combination in BIT_INSERT_EXPR"); + debug_generic_expr (rhs1_type); + debug_generic_expr (rhs2_type); + return true; + } + if (! tree_fits_uhwi_p (rhs3) + || ! tree_fits_uhwi_p (TYPE_SIZE (rhs2_type))) + { + error ("invalid position or size in BIT_INSERT_EXPR"); + return true; + } + if (INTEGRAL_TYPE_P (rhs1_type)) + { + unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (rhs3); + if (bitpos >= TYPE_PRECISION (rhs1_type) + || (bitpos + TYPE_PRECISION (rhs2_type) + > TYPE_PRECISION (rhs1_type))) + { + error ("insertion out of range in BIT_INSERT_EXPR"); + return true; + } + } + else if (VECTOR_TYPE_P (rhs1_type)) + { + unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (rhs3); + unsigned HOST_WIDE_INT bitsize = tree_to_uhwi (TYPE_SIZE (rhs2_type)); + if (bitpos % bitsize != 0) + { + error ("vector insertion not at element boundary"); + return true; + } + } + return false; + case DOT_PROD_EXPR: case REALIGN_LOAD_EXPR: /* FIXME. */ Index: trunk/gcc/tree-ssa.c =================================================================== *** trunk.orig/gcc/tree-ssa.c 2016-05-17 17:19:41.783958489 +0200 --- trunk/gcc/tree-ssa.c 2016-05-19 11:17:40.008247968 +0200 *************** non_rewritable_lvalue_p (tree lhs) *** 1303,1323 **** && DECL_P (TREE_OPERAND (lhs, 0))) return false; ! /* A decl that is wrapped inside a MEM-REF that covers ! it full is also rewritable. ! ??? The following could be relaxed allowing component references that do not change the access size. */ if (TREE_CODE (lhs) == MEM_REF ! && TREE_CODE (TREE_OPERAND (lhs, 0)) == ADDR_EXPR ! && integer_zerop (TREE_OPERAND (lhs, 1))) { tree decl = TREE_OPERAND (TREE_OPERAND (lhs, 0), 0); ! if (DECL_P (decl) && DECL_SIZE (decl) == TYPE_SIZE (TREE_TYPE (lhs)) && (TREE_THIS_VOLATILE (decl) == TREE_THIS_VOLATILE (lhs))) return false; } return true; } --- 1303,1350 ---- && DECL_P (TREE_OPERAND (lhs, 0))) return false; ! /* ??? The following could be relaxed allowing component references that do not change the access size. */ if (TREE_CODE (lhs) == MEM_REF ! && TREE_CODE (TREE_OPERAND (lhs, 0)) == ADDR_EXPR) { tree decl = TREE_OPERAND (TREE_OPERAND (lhs, 0), 0); ! ! /* A decl that is wrapped inside a MEM-REF that covers ! it full is also rewritable. */ ! if (integer_zerop (TREE_OPERAND (lhs, 1)) ! && DECL_P (decl) && DECL_SIZE (decl) == TYPE_SIZE (TREE_TYPE (lhs)) && (TREE_THIS_VOLATILE (decl) == TREE_THIS_VOLATILE (lhs))) return false; + + /* A vector-insert using a MEM_REF or ARRAY_REF is rewritable + using a BIT_INSERT_EXPR. */ + if (DECL_P (decl) + && VECTOR_TYPE_P (TREE_TYPE (decl)) + && TYPE_MODE (TREE_TYPE (decl)) != BLKmode + && types_compatible_p (TREE_TYPE (lhs), + TREE_TYPE (TREE_TYPE (decl))) + && tree_fits_uhwi_p (TREE_OPERAND (lhs, 1)) + && tree_int_cst_lt (TREE_OPERAND (lhs, 1), + TYPE_SIZE_UNIT (TREE_TYPE (decl))) + && (tree_to_uhwi (TREE_OPERAND (lhs, 1)) + % tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (lhs)))) == 0) + return false; } + /* A vector-insert using a BIT_FIELD_REF is rewritable using + BIT_INSERT_EXPR. */ + if (TREE_CODE (lhs) == BIT_FIELD_REF + && DECL_P (TREE_OPERAND (lhs, 0)) + && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (lhs, 0))) + && TYPE_MODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) != BLKmode + && types_compatible_p (TREE_TYPE (lhs), + TREE_TYPE (TREE_TYPE (TREE_OPERAND (lhs, 0)))) + && (tree_to_uhwi (TREE_OPERAND (lhs, 2)) + % tree_to_uhwi (TYPE_SIZE (TREE_TYPE (lhs)))) == 0) + return false; + return true; } *************** execute_update_addresses_taken (void) *** 1536,1541 **** --- 1563,1624 ---- stmt = gsi_stmt (gsi); unlink_stmt_vdef (stmt); update_stmt (stmt); + continue; + } + + /* Rewrite a vector insert via a BIT_FIELD_REF on the LHS + into a BIT_INSERT_EXPR. */ + if (TREE_CODE (lhs) == BIT_FIELD_REF + && DECL_P (TREE_OPERAND (lhs, 0)) + && bitmap_bit_p (suitable_for_renaming, + DECL_UID (TREE_OPERAND (lhs, 0))) + && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (lhs, 0))) + && TYPE_MODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) != BLKmode + && types_compatible_p (TREE_TYPE (lhs), + TREE_TYPE (TREE_TYPE + (TREE_OPERAND (lhs, 0)))) + && (tree_to_uhwi (TREE_OPERAND (lhs, 2)) + % tree_to_uhwi (TYPE_SIZE (TREE_TYPE (lhs))) == 0)) + { + tree var = TREE_OPERAND (lhs, 0); + tree val = gimple_assign_rhs1 (stmt); + tree bitpos = TREE_OPERAND (lhs, 2); + gimple_assign_set_lhs (stmt, var); + gimple_assign_set_rhs_with_ops + (&gsi, BIT_INSERT_EXPR, var, val, bitpos); + stmt = gsi_stmt (gsi); + unlink_stmt_vdef (stmt); + update_stmt (stmt); + continue; + } + + /* Rewrite a vector insert using a MEM_REF on the LHS + into a BIT_INSERT_EXPR. */ + if (TREE_CODE (lhs) == MEM_REF + && TREE_CODE (TREE_OPERAND (lhs, 0)) == ADDR_EXPR + && (sym = TREE_OPERAND (TREE_OPERAND (lhs, 0), 0)) + && DECL_P (sym) + && bitmap_bit_p (suitable_for_renaming, DECL_UID (sym)) + && VECTOR_TYPE_P (TREE_TYPE (sym)) + && TYPE_MODE (TREE_TYPE (sym)) != BLKmode + && types_compatible_p (TREE_TYPE (lhs), + TREE_TYPE (TREE_TYPE (sym))) + && tree_fits_uhwi_p (TREE_OPERAND (lhs, 1)) + && tree_int_cst_lt (TREE_OPERAND (lhs, 1), + TYPE_SIZE_UNIT (TREE_TYPE (sym))) + && (tree_to_uhwi (TREE_OPERAND (lhs, 1)) + % tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (lhs)))) == 0) + { + tree val = gimple_assign_rhs1 (stmt); + tree bitpos + = wide_int_to_tree (bitsizetype, + mem_ref_offset (lhs) * BITS_PER_UNIT); + gimple_assign_set_lhs (stmt, sym); + gimple_assign_set_rhs_with_ops + (&gsi, BIT_INSERT_EXPR, sym, val, bitpos); + stmt = gsi_stmt (gsi); + unlink_stmt_vdef (stmt); + update_stmt (stmt); continue; } Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/vector-6.c =================================================================== *** /dev/null 1970-01-01 00:00:00.000000000 +0000 --- trunk/gcc/testsuite/gcc.dg/tree-ssa/vector-6.c 2016-05-19 11:18:53.465098885 +0200 *************** *** 0 **** --- 1,33 ---- + /* { dg-do compile } */ + /* { dg-options "-O -fdump-tree-ccp1" } */ + + typedef int v4si __attribute__((vector_size (4 * sizeof (int)))); + + v4si test1 (v4si v, int i) + { + ((int *)&v)[0] = i; + return v; + } + + v4si test2 (v4si v, int i) + { + int *p = (int *)&v; + *p = i; + return v; + } + + v4si test3 (v4si v, int i) + { + ((int *)&v)[3] = i; + return v; + } + + v4si test4 (v4si v, int i) + { + int *p = (int *)&v; + p += 3; + *p = i; + return v; + } + + /* { dg-final { scan-tree-dump-times "Now a gimple register: v" 4 "ccp1" } } */