diff options
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r-- | gcc/optabs.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c index cd4f2cb..2202727 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -301,7 +301,13 @@ optab_for_tree_code (enum tree_code code, tree type) return TYPE_UNSIGNED (type) ? reduc_umin_optab : reduc_smin_optab; case REDUC_PLUS_EXPR: - return reduc_plus_optab; + return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab; + + case VEC_LSHIFT_EXPR: + return vec_shl_optab; + + case VEC_RSHIFT_EXPR: + return vec_shr_optab; default: break; @@ -443,6 +449,61 @@ force_expand_binop (enum machine_mode mode, optab binoptab, return true; } +/* Generate insns for VEC_LSHIFT_EXPR, VEC_RSHIFT_EXPR. */ + +rtx +expand_vec_shift_expr (tree vec_shift_expr, rtx target) +{ + enum insn_code icode; + rtx rtx_op1, rtx_op2; + enum machine_mode mode1; + enum machine_mode mode2; + enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_shift_expr)); + tree vec_oprnd = TREE_OPERAND (vec_shift_expr, 0); + tree shift_oprnd = TREE_OPERAND (vec_shift_expr, 1); + optab shift_optab; + rtx pat; + + switch (TREE_CODE (vec_shift_expr)) + { + case VEC_RSHIFT_EXPR: + shift_optab = vec_shr_optab; + break; + case VEC_LSHIFT_EXPR: + shift_optab = vec_shl_optab; + break; + default: + gcc_unreachable (); + } + + icode = (int) shift_optab->handlers[(int) mode].insn_code; + gcc_assert (icode != CODE_FOR_nothing); + + mode1 = insn_data[icode].operand[1].mode; + mode2 = insn_data[icode].operand[2].mode; + + rtx_op1 = expand_expr (vec_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL); + if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode1) + && mode1 != VOIDmode) + rtx_op1 = force_reg (mode1, rtx_op1); + + rtx_op2 = expand_expr (shift_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL); + if (!(*insn_data[icode].operand[2].predicate) (rtx_op2, mode2) + && mode2 != VOIDmode) + rtx_op2 = force_reg (mode2, rtx_op2); + + if (!target + || ! (*insn_data[icode].operand[0].predicate) (target, mode)) + target = gen_reg_rtx (mode); + + /* Emit instruction */ + pat = GEN_FCN (icode) (target, rtx_op1, rtx_op2); + gcc_assert (pat); + emit_insn (pat); + + return target; +} + /* This subroutine of expand_doubleword_shift handles the cases in which the effective shift value is >= BITS_PER_WORD. The arguments and return value are the same as for the parent routine, except that SUPERWORD_OP1 @@ -5074,11 +5135,14 @@ init_optabs (void) reduc_umax_optab = init_optab (UNKNOWN); reduc_smin_optab = init_optab (UNKNOWN); reduc_umin_optab = init_optab (UNKNOWN); - reduc_plus_optab = init_optab (UNKNOWN); + reduc_splus_optab = init_optab (UNKNOWN); + reduc_uplus_optab = init_optab (UNKNOWN); vec_extract_optab = init_optab (UNKNOWN); vec_set_optab = init_optab (UNKNOWN); vec_init_optab = init_optab (UNKNOWN); + vec_shl_optab = init_optab (UNKNOWN); + vec_shr_optab = init_optab (UNKNOWN); vec_realign_load_optab = init_optab (UNKNOWN); movmisalign_optab = init_optab (UNKNOWN); |