I was sitting on this patch until I got around to fixing up Jakub's existing vector divmod code to use it. But seeing as how he's adding more uses, I think it's better to get it in earlier.
Tested via a patch sent under separate cover that changes __builtin_alpha_umulh to immediately fold to MULT_HIGHPART_EXPR. r~ --- * tree.def (MULT_HIGHPART_EXPR): New. * cfgexpand.c (expand_debug_expr): Ignore it. * expr.c (expand_expr_real_2): Handle it. * fold-const.c (int_const_binop_1): Likewise. * optabs.c (optab_for_tree_code): Likewise. * tree-cfg.c (verify_gimple_assign_binary): Likewise. * tree-inline.c (estimate_operator_cost): Likewise. * tree-pretty-print.c (dump_generic_node): Likewise. (op_code_prio, op_symbol_code): Likewise. * tree.c (commutative_tree_code): Likewise. Also handle WIDEN_MULT_EXPR, VEC_WIDEN_MULT_HI_EXPR, VEC_WIDEN_MULT_LO_EXPR. --- gcc/ChangeLog | 14 ++++++++++++++ gcc/cfgexpand.c | 6 +++++- gcc/expr.c | 1 + gcc/fold-const.c | 10 ++++++++++ gcc/optabs.c | 3 +++ gcc/tree-cfg.c | 1 + gcc/tree-inline.c | 1 + gcc/tree-pretty-print.c | 5 +++++ gcc/tree.c | 4 ++++ gcc/tree.def | 4 ++++ 10 files changed, 48 insertions(+), 1 deletions(-) diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index a8397c6..ad2f667 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3415,7 +3415,7 @@ expand_debug_expr (tree exp) case VEC_PERM_EXPR: return NULL; - /* Misc codes. */ + /* Misc codes. */ case ADDR_SPACE_CONVERT_EXPR: case FIXED_CONVERT_EXPR: case OBJ_TYPE_REF: @@ -3466,6 +3466,10 @@ expand_debug_expr (tree exp) } return NULL; + case MULT_HIGHPART_EXPR: + /* ??? Similar to the above. */ + return NULL; + case WIDEN_SUM_EXPR: case WIDEN_LSHIFT_EXPR: if (SCALAR_INT_MODE_P (GET_MODE (op0)) diff --git a/gcc/expr.c b/gcc/expr.c index cad5b10..5295da2 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8551,6 +8551,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, return expand_divmod (0, code, mode, op0, op1, target, unsignedp); case RDIV_EXPR: + case MULT_HIGHPART_EXPR: goto binop; case TRUNC_MOD_EXPR: diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 877cf32..702f4e0 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -999,6 +999,16 @@ int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree arg2, &res.low, &res.high); break; + case MULT_HIGHPART_EXPR: + /* ??? Need quad precision, or an additional shift operand + to the multiply primitive, to handle very large highparts. */ + if (TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT) + return NULL_TREE; + tmp = double_int_mul (op1, op2); + res = double_int_rshift (tmp, TYPE_PRECISION (type), + TYPE_PRECISION (type), !uns); + break; + case TRUNC_DIV_EXPR: case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: case EXACT_DIV_EXPR: diff --git a/gcc/optabs.c b/gcc/optabs.c index 9a549ff..3094476 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -367,6 +367,9 @@ optab_for_tree_code (enum tree_code code, const_tree type, case BIT_XOR_EXPR: return xor_optab; + case MULT_HIGHPART_EXPR: + return TYPE_UNSIGNED (type) ? umul_highpart_optab : smul_highpart_optab; + case TRUNC_MOD_EXPR: case CEIL_MOD_EXPR: case FLOOR_MOD_EXPR: diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index d7ab090..fe5af70 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -3731,6 +3731,7 @@ do_pointer_plus_expr_check: return false; case MULT_EXPR: + case MULT_HIGHPART_EXPR: case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 6746296..c3d3fb6 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -3379,6 +3379,7 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights, case POINTER_PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: + case MULT_HIGHPART_EXPR: case FMA_EXPR: case ADDR_SPACE_CONVERT_EXPR: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index f810d77..44d3c10 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1612,6 +1612,7 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case WIDEN_SUM_EXPR: case WIDEN_MULT_EXPR: case MULT_EXPR: + case MULT_HIGHPART_EXPR: case PLUS_EXPR: case POINTER_PLUS_EXPR: case MINUS_EXPR: @@ -2674,6 +2675,7 @@ op_code_prio (enum tree_code code) case WIDEN_MULT_PLUS_EXPR: case WIDEN_MULT_MINUS_EXPR: case MULT_EXPR: + case MULT_HIGHPART_EXPR: case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: @@ -2852,6 +2854,9 @@ op_symbol_code (enum tree_code code) case WIDEN_MULT_EXPR: return "w*"; + case MULT_HIGHPART_EXPR: + return "h*"; + case NEGATE_EXPR: case MINUS_EXPR: return "-"; diff --git a/gcc/tree.c b/gcc/tree.c index d3c2a19..1717d71 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -6899,6 +6899,7 @@ commutative_tree_code (enum tree_code code) { case PLUS_EXPR: case MULT_EXPR: + case MULT_HIGHPART_EXPR: case MIN_EXPR: case MAX_EXPR: case BIT_IOR_EXPR: @@ -6913,6 +6914,9 @@ commutative_tree_code (enum tree_code code) case TRUTH_AND_EXPR: case TRUTH_XOR_EXPR: case TRUTH_OR_EXPR: + case WIDEN_MULT_EXPR: + case VEC_WIDEN_MULT_HI_EXPR: + case VEC_WIDEN_MULT_LO_EXPR: return true; default: diff --git a/gcc/tree.def b/gcc/tree.def index 8a3007c..b0d4aea 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -639,6 +639,10 @@ DEFTREECODE (MULT_EXPR, "mult_expr", tcc_binary, 2) second operand is an integer of type sizetype. */ DEFTREECODE (POINTER_PLUS_EXPR, "pointer_plus_expr", tcc_binary, 2) +/* Highpart multiplication. For an integral type with precision B, + returns bits [2B-1, B] of the full 2*B product. */ +DEFTREECODE (MULT_HIGHPART_EXPR, "mult_highpart_expr", tcc_binary, 2) + /* Division for integer result that rounds the quotient toward zero. */ DEFTREECODE (TRUNC_DIV_EXPR, "trunc_div_expr", tcc_binary, 2) -- 1.7.7.6