diff options
author | Richard Sandiford <richard.sandiford@linaro.org> | 2011-03-23 09:30:58 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2011-03-23 09:30:58 +0000 |
commit | a5c7d693b920b650fb863e4b9a41b01c199f698f (patch) | |
tree | 149ffb595908dd2c0744e01184f253f737706ef4 /gcc/optabs.c | |
parent | 78fadbabe3c1efabb7ebc58819ed75131958dfc4 (diff) | |
download | gcc-a5c7d693b920b650fb863e4b9a41b01c199f698f.zip gcc-a5c7d693b920b650fb863e4b9a41b01c199f698f.tar.gz gcc-a5c7d693b920b650fb863e4b9a41b01c199f698f.tar.bz2 |
optabs.h (emit_unop_insn, [...]): Change insn code parameter from "int" to "enum insn_code".
gcc/
* optabs.h (emit_unop_insn, maybe_emit_unop_insn): Change insn code
parameter from "int" to "enum insn_code".
(expand_operand_type): New enum.
(expand_operand): New structure.
(create_expand_operand): New function.
(create_fixed_operand, create_output_operand): Likewise
(create_input_operand, create_convert_operand_to): Likewise.
(create_convert_operand_from, create_address_operand): Likewise.
(create_integer_operand): Likewise.
(create_convert_operand_from_type, maybe_legitimize_operands): Declare.
(maybe_gen_insn, maybe_expand_insn, maybe_expand_jump_insn): Likewise.
(expand_insn, expand_jump_insn): Likewise.
* builtins.c (expand_builtin_prefetch): Use the new interfaces.
(expand_builtin_interclass_mathfn, expand_builtin_strlen): Likewise.
(expand_movstr, expand_builtin___clear_cache): Likewise.
(expand_builtin_lock_release): Likewise.
* explow.c (allocate_dynamic_stack_space): Likewise.
(probe_stack_range): Likewise. Allow check_stack to FAIL,
and use the default handling in that case.
* expmed.c (check_predicate_volatile_ok): Delete.
(store_bit_field_1, extract_bit_field_1): Use the new interfaces.
(emit_cstore): Likewise.
* expr.c (emit_block_move_via_movmem): Likewise.
(set_storage_via_setmem, expand_assignment): Likewise.
(emit_storent_insn, try_casesi): Likewise.
(emit_single_push_insn): Likewise. Allow the expansion to fail.
* optabs.c (expand_widen_pattern_expr, expand_ternary_op): Likewise.
(expand_vec_shift_expr, expand_binop_directly): Likewise.
(expand_twoval_unop, expand_twoval_binop): Likewise.
(expand_unop_direct, emit_indirect_jump): Likewise.
(emit_conditional_move, vector_compare_rtx): Likewise.
(expand_vec_cond_expr, expand_val_compare_and_swap_1): Likewise.
(expand_sync_operation, expand_sync_fetch_operation): Likewise.
(expand_sync_lock_test_and_set): Likewise.
(maybe_emit_unop_insn): Likewise. Change icode to an insn_code.
(emit_unop_insn): Likewise.
(expand_copysign_absneg): Change icode to an insn_code.
(create_convert_operand_from_type): New function.
(maybe_legitimize_operand, maybe_legitimize_operands): Likewise.
(maybe_gen_insn, maybe_expand_insn, maybe_expand_jump_insn): Likewise.
(expand_insn, expand_jump_insn): Likewise.
* config/i386/i386.md (setmem<mode>): Use nonmemory_operand rather
than const_int_operand for operand 2.
From-SVN: r171341
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r-- | gcc/optabs.c | 918 |
1 files changed, 390 insertions, 528 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c index a874c42..d1cfd3a 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -501,15 +501,13 @@ rtx expand_widen_pattern_expr (sepops ops, rtx op0, rtx op1, rtx wide_op, rtx target, int unsignedp) { + struct expand_operand eops[4]; tree oprnd0, oprnd1, oprnd2; enum machine_mode wmode = VOIDmode, tmode0, tmode1 = VOIDmode; optab widen_pattern_optab; - int icode; - enum machine_mode xmode0, xmode1 = VOIDmode, wxmode = VOIDmode; - rtx temp; - rtx pat; - rtx xop0, xop1, wxop; + enum insn_code icode; int nops = TREE_CODE_LENGTH (ops->code); + int op; oprnd0 = ops->op0; tmode0 = TYPE_MODE (TREE_TYPE (oprnd0)); @@ -517,117 +515,38 @@ expand_widen_pattern_expr (sepops ops, rtx op0, rtx op1, rtx wide_op, optab_for_tree_code (ops->code, TREE_TYPE (oprnd0), optab_default); if (ops->code == WIDEN_MULT_PLUS_EXPR || ops->code == WIDEN_MULT_MINUS_EXPR) - icode = (int) optab_handler (widen_pattern_optab, - TYPE_MODE (TREE_TYPE (ops->op2))); + icode = optab_handler (widen_pattern_optab, + TYPE_MODE (TREE_TYPE (ops->op2))); else - icode = (int) optab_handler (widen_pattern_optab, tmode0); + icode = optab_handler (widen_pattern_optab, tmode0); gcc_assert (icode != CODE_FOR_nothing); - xmode0 = insn_data[icode].operand[1].mode; if (nops >= 2) { oprnd1 = ops->op1; tmode1 = TYPE_MODE (TREE_TYPE (oprnd1)); - xmode1 = insn_data[icode].operand[2].mode; } /* The last operand is of a wider mode than the rest of the operands. */ if (nops == 2) - { - wmode = tmode1; - wxmode = xmode1; - } + wmode = tmode1; else if (nops == 3) { gcc_assert (tmode1 == tmode0); gcc_assert (op1); oprnd2 = ops->op2; wmode = TYPE_MODE (TREE_TYPE (oprnd2)); - wxmode = insn_data[icode].operand[3].mode; } - if (!wide_op) - wmode = wxmode = insn_data[icode].operand[0].mode; - - if (!target - || ! (*insn_data[icode].operand[0].predicate) (target, wmode)) - temp = gen_reg_rtx (wmode); - else - temp = target; - - xop0 = op0; - xop1 = op1; - wxop = wide_op; - - /* In case the insn wants input operands in modes different from - those of the actual operands, convert the operands. It would - seem that we don't need to convert CONST_INTs, but we do, so - that they're properly zero-extended, sign-extended or truncated - for their mode. */ - - if (GET_MODE (op0) != xmode0 && xmode0 != VOIDmode) - xop0 = convert_modes (xmode0, - GET_MODE (op0) != VOIDmode - ? GET_MODE (op0) - : tmode0, - xop0, unsignedp); - + op = 0; + create_output_operand (&eops[op++], target, TYPE_MODE (ops->type)); + create_convert_operand_from (&eops[op++], op0, tmode0, unsignedp); if (op1) - if (GET_MODE (op1) != xmode1 && xmode1 != VOIDmode) - xop1 = convert_modes (xmode1, - GET_MODE (op1) != VOIDmode - ? GET_MODE (op1) - : tmode1, - xop1, unsignedp); - + create_convert_operand_from (&eops[op++], op1, tmode1, unsignedp); if (wide_op) - if (GET_MODE (wide_op) != wxmode && wxmode != VOIDmode) - wxop = convert_modes (wxmode, - GET_MODE (wide_op) != VOIDmode - ? GET_MODE (wide_op) - : wmode, - wxop, unsignedp); - - /* Now, if insn's predicates don't allow our operands, put them into - pseudo regs. */ - - if (! (*insn_data[icode].operand[1].predicate) (xop0, xmode0) - && xmode0 != VOIDmode) - xop0 = copy_to_mode_reg (xmode0, xop0); - - if (op1) - { - if (! (*insn_data[icode].operand[2].predicate) (xop1, xmode1) - && xmode1 != VOIDmode) - xop1 = copy_to_mode_reg (xmode1, xop1); - - if (wide_op) - { - if (! (*insn_data[icode].operand[3].predicate) (wxop, wxmode) - && wxmode != VOIDmode) - wxop = copy_to_mode_reg (wxmode, wxop); - - pat = GEN_FCN (icode) (temp, xop0, xop1, wxop); - } - else - pat = GEN_FCN (icode) (temp, xop0, xop1); - } - else - { - if (wide_op) - { - if (! (*insn_data[icode].operand[2].predicate) (wxop, wxmode) - && wxmode != VOIDmode) - wxop = copy_to_mode_reg (wxmode, wxop); - - pat = GEN_FCN (icode) (temp, xop0, wxop); - } - else - pat = GEN_FCN (icode) (temp, xop0); - } - - emit_insn (pat); - return temp; + create_convert_operand_from (&eops[op++], wide_op, wmode, unsignedp); + expand_insn (icode, op, eops); + return eops[0].value; } /* Generate code to perform an operation specified by TERNARY_OPTAB @@ -645,67 +564,17 @@ rtx expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0, rtx op1, rtx op2, rtx target, int unsignedp) { - int icode = (int) optab_handler (ternary_optab, mode); - enum machine_mode mode0 = insn_data[icode].operand[1].mode; - enum machine_mode mode1 = insn_data[icode].operand[2].mode; - enum machine_mode mode2 = insn_data[icode].operand[3].mode; - rtx temp; - rtx pat; - rtx xop0 = op0, xop1 = op1, xop2 = op2; + struct expand_operand ops[4]; + enum insn_code icode = optab_handler (ternary_optab, mode); gcc_assert (optab_handler (ternary_optab, mode) != CODE_FOR_nothing); - if (!target || !insn_data[icode].operand[0].predicate (target, mode)) - temp = gen_reg_rtx (mode); - else - temp = target; - - /* In case the insn wants input operands in modes different from - those of the actual operands, convert the operands. It would - seem that we don't need to convert CONST_INTs, but we do, so - that they're properly zero-extended, sign-extended or truncated - for their mode. */ - - if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) - xop0 = convert_modes (mode0, - GET_MODE (op0) != VOIDmode - ? GET_MODE (op0) - : mode, - xop0, unsignedp); - - if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) - xop1 = convert_modes (mode1, - GET_MODE (op1) != VOIDmode - ? GET_MODE (op1) - : mode, - xop1, unsignedp); - - if (GET_MODE (op2) != mode2 && mode2 != VOIDmode) - xop2 = convert_modes (mode2, - GET_MODE (op2) != VOIDmode - ? GET_MODE (op2) - : mode, - xop2, unsignedp); - - /* Now, if insn's predicates don't allow our operands, put them into - pseudo regs. */ - - if (!insn_data[icode].operand[1].predicate (xop0, mode0) - && mode0 != VOIDmode) - xop0 = copy_to_mode_reg (mode0, xop0); - - if (!insn_data[icode].operand[2].predicate (xop1, mode1) - && mode1 != VOIDmode) - xop1 = copy_to_mode_reg (mode1, xop1); - - if (!insn_data[icode].operand[3].predicate (xop2, mode2) - && mode2 != VOIDmode) - xop2 = copy_to_mode_reg (mode2, xop2); - - pat = GEN_FCN (icode) (temp, xop0, xop1, xop2); - - emit_insn (pat); - return temp; + create_output_operand (&ops[0], target, mode); + create_convert_operand_from (&ops[1], op0, mode, unsignedp); + create_convert_operand_from (&ops[2], op1, mode, unsignedp); + create_convert_operand_from (&ops[3], op2, mode, unsignedp); + expand_insn (icode, 4, ops); + return ops[0].value; } @@ -751,15 +620,13 @@ force_expand_binop (enum machine_mode mode, optab binoptab, rtx expand_vec_shift_expr (sepops ops, rtx target) { + struct expand_operand eops[3]; enum insn_code icode; rtx rtx_op1, rtx_op2; - enum machine_mode mode1; - enum machine_mode mode2; enum machine_mode mode = TYPE_MODE (ops->type); tree vec_oprnd = ops->op0; tree shift_oprnd = ops->op1; optab shift_optab; - rtx pat; switch (ops->code) { @@ -776,29 +643,15 @@ expand_vec_shift_expr (sepops ops, rtx target) icode = optab_handler (shift_optab, mode); gcc_assert (icode != CODE_FOR_nothing); - mode1 = insn_data[icode].operand[1].mode; - mode2 = insn_data[icode].operand[2].mode; - rtx_op1 = expand_normal (vec_oprnd); - if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode1) - && mode1 != VOIDmode) - rtx_op1 = force_reg (mode1, rtx_op1); - rtx_op2 = expand_normal (shift_oprnd); - 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); + create_output_operand (&eops[0], target, mode); + create_input_operand (&eops[1], rtx_op1, GET_MODE (rtx_op1)); + create_convert_operand_from_type (&eops[2], rtx_op2, TREE_TYPE (shift_oprnd)); + expand_insn (icode, 3, eops); - /* Emit instruction */ - pat = GEN_FCN (icode) (target, rtx_op1, rtx_op2); - gcc_assert (pat); - emit_insn (pat); - - return target; + return eops[0].value; } /* This subroutine of expand_doubleword_shift handles the cases in which @@ -1389,21 +1242,16 @@ expand_binop_directly (enum machine_mode mode, optab binoptab, rtx target, int unsignedp, enum optab_methods methods, rtx last) { - int icode = (int) optab_handler (binoptab, mode); - enum machine_mode mode0 = insn_data[icode].operand[1].mode; - enum machine_mode mode1 = insn_data[icode].operand[2].mode; + enum insn_code icode = optab_handler (binoptab, mode); + enum machine_mode mode0 = insn_data[(int) icode].operand[1].mode; + enum machine_mode mode1 = insn_data[(int) icode].operand[2].mode; enum machine_mode tmp_mode; + struct expand_operand ops[3]; bool commutative_p; rtx pat; rtx xop0 = op0, xop1 = op1; - rtx temp; rtx swap; - if (target) - temp = target; - else - temp = gen_reg_rtx (mode); - /* If it is a commutative operator and the modes would match if we would swap the operands, we can save the conversions. */ commutative_p = commutative_optab_p (binoptab); @@ -1421,49 +1269,9 @@ expand_binop_directly (enum machine_mode mode, optab binoptab, if (!shift_optab_p (binoptab)) xop1 = avoid_expensive_constant (mode1, binoptab, xop1, unsignedp); - /* In case the insn wants input operands in modes different from - those of the actual operands, convert the operands. It would - seem that we don't need to convert CONST_INTs, but we do, so - that they're properly zero-extended, sign-extended or truncated - for their mode. */ - - if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode) - xop0 = convert_modes (mode0, - GET_MODE (xop0) != VOIDmode - ? GET_MODE (xop0) - : mode, - xop0, unsignedp); - - if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode) - xop1 = convert_modes (mode1, - GET_MODE (xop1) != VOIDmode - ? GET_MODE (xop1) - : mode, - xop1, unsignedp); - - /* If operation is commutative, - try to make the first operand a register. - Even better, try to make it the same as the target. - Also try to make the last operand a constant. */ - if (commutative_p - && swap_commutative_operands_with_target (target, xop0, xop1)) - { - swap = xop1; - xop1 = xop0; - xop0 = swap; - } - /* Now, if insn's predicates don't allow our operands, put them into pseudo regs. */ - if (!insn_data[icode].operand[1].predicate (xop0, mode0) - && mode0 != VOIDmode) - xop0 = copy_to_mode_reg (mode0, xop0); - - if (!insn_data[icode].operand[2].predicate (xop1, mode1) - && mode1 != VOIDmode) - xop1 = copy_to_mode_reg (mode1, xop1); - if (binoptab == vec_pack_trunc_optab || binoptab == vec_pack_usat_optab || binoptab == vec_pack_ssat_optab @@ -1472,34 +1280,53 @@ expand_binop_directly (enum machine_mode mode, optab binoptab, { /* The mode of the result is different then the mode of the arguments. */ - tmp_mode = insn_data[icode].operand[0].mode; + tmp_mode = insn_data[(int) icode].operand[0].mode; if (GET_MODE_NUNITS (tmp_mode) != 2 * GET_MODE_NUNITS (mode)) - return 0; + { + delete_insns_since (last); + return NULL_RTX; + } } else tmp_mode = mode; - if (!insn_data[icode].operand[0].predicate (temp, tmp_mode)) - temp = gen_reg_rtx (tmp_mode); - - pat = GEN_FCN (icode) (temp, xop0, xop1); - if (pat) - { - /* If PAT is composed of more than one insn, try to add an appropriate - REG_EQUAL note to it. If we can't because TEMP conflicts with an - operand, call expand_binop again, this time without a target. */ - if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX - && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1)) + create_output_operand (&ops[0], target, tmp_mode); + create_convert_operand_from (&ops[1], xop0, mode, unsignedp); + create_convert_operand_from (&ops[2], xop1, mode, unsignedp); + if (maybe_legitimize_operands (icode, 0, 3, ops)) + { + /* If operation is commutative, + try to make the first operand a register. + Even better, try to make it the same as the target. + Also try to make the last operand a constant. */ + if (commutative_p + && swap_commutative_operands_with_target (ops[0].value, ops[1].value, + ops[2].value)) { - delete_insns_since (last); - return expand_binop (mode, binoptab, op0, op1, NULL_RTX, - unsignedp, methods); + swap = ops[2].value; + ops[2].value = ops[1].value; + ops[1].value = swap; } - emit_insn (pat); - return temp; - } + pat = GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value); + if (pat) + { + /* If PAT is composed of more than one insn, try to add an appropriate + REG_EQUAL note to it. If we can't because TEMP conflicts with an + operand, call expand_binop again, this time without a target. */ + if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX + && ! add_equal_note (pat, ops[0].value, binoptab->code, + ops[1].value, ops[2].value)) + { + delete_insns_since (last); + return expand_binop (mode, binoptab, op0, op1, NULL_RTX, + unsignedp, methods); + } + emit_insn (pat); + return ops[0].value; + } + } delete_insns_since (last); return NULL_RTX; } @@ -2284,32 +2111,14 @@ expand_twoval_unop (optab unoptab, rtx op0, rtx targ0, rtx targ1, if (optab_handler (unoptab, mode) != CODE_FOR_nothing) { - int icode = (int) optab_handler (unoptab, mode); - enum machine_mode mode0 = insn_data[icode].operand[2].mode; - rtx pat; - rtx xop0 = op0; - - if (GET_MODE (xop0) != VOIDmode - && GET_MODE (xop0) != mode0) - xop0 = convert_to_mode (mode0, xop0, unsignedp); + struct expand_operand ops[3]; + enum insn_code icode = optab_handler (unoptab, mode); - /* Now, if insn doesn't accept these operands, put them into pseudos. */ - if (!insn_data[icode].operand[2].predicate (xop0, mode0)) - xop0 = copy_to_mode_reg (mode0, xop0); - - /* We could handle this, but we should always be called with a pseudo - for our targets and all insns should take them as outputs. */ - gcc_assert (insn_data[icode].operand[0].predicate (targ0, mode)); - gcc_assert (insn_data[icode].operand[1].predicate (targ1, mode)); - - pat = GEN_FCN (icode) (targ0, targ1, xop0); - if (pat) - { - emit_insn (pat); - return 1; - } - else - delete_insns_since (last); + create_fixed_operand (&ops[0], targ0); + create_fixed_operand (&ops[1], targ1); + create_convert_operand_from (&ops[2], op0, mode, unsignedp); + if (maybe_expand_insn (icode, 3, ops)) + return 1; } /* It can't be done in this mode. Can we do it in a wider mode? */ @@ -2376,56 +2185,23 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1, if (optab_handler (binoptab, mode) != CODE_FOR_nothing) { - int icode = (int) optab_handler (binoptab, mode); + struct expand_operand ops[4]; + enum insn_code icode = optab_handler (binoptab, mode); enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode; - rtx pat; rtx xop0 = op0, xop1 = op1; /* If we are optimizing, force expensive constants into a register. */ xop0 = avoid_expensive_constant (mode0, binoptab, xop0, unsignedp); xop1 = avoid_expensive_constant (mode1, binoptab, xop1, unsignedp); - /* In case the insn wants input operands in modes different from - those of the actual operands, convert the operands. It would - seem that we don't need to convert CONST_INTs, but we do, so - that they're properly zero-extended, sign-extended or truncated - for their mode. */ - - if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) - xop0 = convert_modes (mode0, - GET_MODE (op0) != VOIDmode - ? GET_MODE (op0) - : mode, - xop0, unsignedp); - - if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) - xop1 = convert_modes (mode1, - GET_MODE (op1) != VOIDmode - ? GET_MODE (op1) - : mode, - xop1, unsignedp); - - /* Now, if insn doesn't accept these operands, put them into pseudos. */ - if (!insn_data[icode].operand[1].predicate (xop0, mode0)) - xop0 = copy_to_mode_reg (mode0, xop0); - - if (!insn_data[icode].operand[2].predicate (xop1, mode1)) - xop1 = copy_to_mode_reg (mode1, xop1); - - /* We could handle this, but we should always be called with a pseudo - for our targets and all insns should take them as outputs. */ - gcc_assert (insn_data[icode].operand[0].predicate (targ0, mode)); - gcc_assert (insn_data[icode].operand[3].predicate (targ1, mode)); - - pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1); - if (pat) - { - emit_insn (pat); - return 1; - } - else - delete_insns_since (last); + create_fixed_operand (&ops[0], targ0); + create_convert_operand_from (&ops[1], op0, mode, unsignedp); + create_convert_operand_from (&ops[2], op1, mode, unsignedp); + create_fixed_operand (&ops[3], targ1); + if (maybe_expand_insn (icode, 4, ops)) + return 1; + delete_insns_since (last); } /* It can't be done in this mode. Can we do it in a wider mode? */ @@ -2985,34 +2761,19 @@ expand_unop_direct (enum machine_mode mode, optab unoptab, rtx op0, rtx target, { if (optab_handler (unoptab, mode) != CODE_FOR_nothing) { - int icode = (int) optab_handler (unoptab, mode); - enum machine_mode mode0 = insn_data[icode].operand[1].mode; - rtx xop0 = op0; + struct expand_operand ops[2]; + enum insn_code icode = optab_handler (unoptab, mode); rtx last = get_last_insn (); - rtx pat, temp; - - if (target) - temp = target; - else - temp = gen_reg_rtx (mode); - - if (GET_MODE (xop0) != VOIDmode - && GET_MODE (xop0) != mode0) - xop0 = convert_to_mode (mode0, xop0, unsignedp); - - /* Now, if insn doesn't accept our operand, put it into a pseudo. */ - - if (!insn_data[icode].operand[1].predicate (xop0, mode0)) - xop0 = copy_to_mode_reg (mode0, xop0); - - if (!insn_data[icode].operand[0].predicate (temp, mode)) - temp = gen_reg_rtx (mode); + rtx pat; - pat = GEN_FCN (icode) (temp, xop0); + create_output_operand (&ops[0], target, mode); + create_convert_operand_from (&ops[1], op0, mode, unsignedp); + pat = maybe_gen_insn (icode, 2, ops); if (pat) { if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX - && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX)) + && ! add_equal_note (pat, ops[0].value, unoptab->code, + ops[1].value, NULL_RTX)) { delete_insns_since (last); return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp); @@ -3020,10 +2781,8 @@ expand_unop_direct (enum machine_mode mode, optab unoptab, rtx op0, rtx target, emit_insn (pat); - return temp; + return ops[0].value; } - else - delete_insns_since (last); } return 0; } @@ -3499,7 +3258,7 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target, int bitpos, bool op0_is_abs) { enum machine_mode imode; - int icode; + enum insn_code icode; rtx sign, label; if (target == op1) @@ -3507,10 +3266,10 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target, /* Check if the back end provides an insn that handles signbit for the argument's mode. */ - icode = (int) optab_handler (signbit_optab, mode); + icode = optab_handler (signbit_optab, mode); if (icode != CODE_FOR_nothing) { - imode = insn_data[icode].operand[0].mode; + imode = insn_data[(int) icode].operand[0].mode; sign = gen_reg_rtx (imode); emit_unop_insn (icode, sign, op1, UNKNOWN); } @@ -3731,37 +3490,25 @@ expand_copysign (rtx op0, rtx op1, rtx target) Return false if expansion failed. */ bool -maybe_emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code) +maybe_emit_unop_insn (enum insn_code icode, rtx target, rtx op0, + enum rtx_code code) { - rtx temp; - enum machine_mode mode0 = insn_data[icode].operand[1].mode; + struct expand_operand ops[2]; rtx pat; - rtx last = get_last_insn (); - - temp = target; - - /* Now, if insn does not accept our operands, put them into pseudos. */ - - if (!insn_data[icode].operand[1].predicate (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp))) - temp = gen_reg_rtx (GET_MODE (temp)); - - pat = GEN_FCN (icode) (temp, op0); + create_output_operand (&ops[0], target, GET_MODE (target)); + create_input_operand (&ops[1], op0, GET_MODE (op0)); + pat = maybe_gen_insn (icode, 2, ops); if (!pat) - { - delete_insns_since (last); - return false; - } + return false; if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN) - add_equal_note (pat, temp, code, op0, NULL_RTX); + add_equal_note (pat, ops[0].value, code, ops[1].value, NULL_RTX); emit_insn (pat); - if (temp != target) - emit_move_insn (target, temp); + if (ops[0].value != target) + emit_move_insn (target, ops[0].value); return true; } /* Generate an instruction whose insn-code is INSN_CODE, @@ -3771,7 +3518,7 @@ maybe_emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code) the value that is stored into TARGET. */ void -emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code) +emit_unop_insn (enum insn_code icode, rtx target, rtx op0, enum rtx_code code) { bool ok = maybe_emit_unop_insn (icode, target, op0, code); gcc_assert (ok); @@ -4418,11 +4165,10 @@ prepare_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison, void emit_indirect_jump (rtx loc) { - if (!insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate - (loc, Pmode)) - loc = copy_to_mode_reg (Pmode, loc); + struct expand_operand ops[1]; - emit_jump_insn (gen_indirect_jump (loc)); + create_address_operand (&ops[0], loc); + expand_jump_insn (CODE_FOR_indirect_jump, 1, ops); emit_barrier (); } @@ -4447,7 +4193,7 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1, enum machine_mode cmode, rtx op2, rtx op3, enum machine_mode mode, int unsignedp) { - rtx tem, subtarget, comparison, insn; + rtx tem, comparison, last; enum insn_code icode; enum rtx_code reversed; @@ -4494,24 +4240,6 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1, if (!target) target = gen_reg_rtx (mode); - subtarget = target; - - /* If the insn doesn't accept these operands, put them in pseudos. */ - - if (!insn_data[icode].operand[0].predicate - (subtarget, insn_data[icode].operand[0].mode)) - subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode); - - if (!insn_data[icode].operand[2].predicate - (op2, insn_data[icode].operand[2].mode)) - op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); - - if (!insn_data[icode].operand[3].predicate - (op3, insn_data[icode].operand[3].mode)) - op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3); - - /* Everything should now be in the suitable form. */ - code = unsignedp ? unsigned_condition (code) : code; comparison = simplify_gen_relational (code, VOIDmode, cmode, op0, op1); @@ -4522,30 +4250,27 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1, return NULL_RTX; do_pending_stack_adjust (); - start_sequence (); + last = get_last_insn (); prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1), GET_CODE (comparison), NULL_RTX, unsignedp, OPTAB_WIDEN, &comparison, &cmode); - if (!comparison) - insn = NULL_RTX; - else - insn = GEN_FCN (icode) (subtarget, comparison, op2, op3); - - /* If that failed, then give up. */ - if (insn == 0) + if (comparison) { - end_sequence (); - return 0; - } - - emit_insn (insn); - insn = get_insns (); - end_sequence (); - emit_insn (insn); - if (subtarget != target) - convert_move (target, subtarget, 0); + struct expand_operand ops[4]; - return target; + create_output_operand (&ops[0], target, mode); + create_fixed_operand (&ops[1], comparison); + create_input_operand (&ops[2], op2, mode); + create_input_operand (&ops[3], op3, mode); + if (maybe_expand_insn (icode, 4, ops)) + { + if (ops[0].value != target) + convert_move (target, ops[0].value, false); + return target; + } + } + delete_insns_since (last); + return NULL_RTX; } /* Return nonzero if a conditional move of mode MODE is supported. @@ -4586,7 +4311,7 @@ emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1, enum machine_mode cmode, rtx op2, rtx op3, enum machine_mode mode, int unsignedp) { - rtx tem, subtarget, comparison, insn; + rtx tem, comparison, last; enum insn_code icode; enum rtx_code reversed; @@ -4633,24 +4358,6 @@ emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1, if (!target) target = gen_reg_rtx (mode); - /* If the insn doesn't accept these operands, put them in pseudos. */ - - if (!insn_data[icode].operand[0].predicate - (target, insn_data[icode].operand[0].mode)) - subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode); - else - subtarget = target; - - if (!insn_data[icode].operand[2].predicate - (op2, insn_data[icode].operand[2].mode)) - op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); - - if (!insn_data[icode].operand[3].predicate - (op3, insn_data[icode].operand[3].mode)) - op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3); - - /* Everything should now be in the suitable form. */ - code = unsignedp ? unsigned_condition (code) : code; comparison = simplify_gen_relational (code, VOIDmode, cmode, op0, op1); @@ -4661,30 +4368,27 @@ emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1, return NULL_RTX; do_pending_stack_adjust (); - start_sequence (); + last = get_last_insn (); prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1), GET_CODE (comparison), NULL_RTX, unsignedp, OPTAB_WIDEN, &comparison, &cmode); - if (!comparison) - insn = NULL_RTX; - else - insn = GEN_FCN (icode) (subtarget, comparison, op2, op3); - - /* If that failed, then give up. */ - if (insn == 0) + if (comparison) { - end_sequence (); - return 0; - } - - emit_insn (insn); - insn = get_insns (); - end_sequence (); - emit_insn (insn); - if (subtarget != target) - convert_move (target, subtarget, 0); + struct expand_operand ops[4]; - return target; + create_output_operand (&ops[0], target, mode); + create_fixed_operand (&ops[1], comparison); + create_input_operand (&ops[2], op2, mode); + create_input_operand (&ops[3], op3, mode); + if (maybe_expand_insn (icode, 4, ops)) + { + if (ops[0].value != target) + convert_move (target, ops[0].value, false); + return target; + } + } + delete_insns_since (last); + return NULL_RTX; } /* These functions attempt to generate an insn body, rather than @@ -6713,6 +6417,7 @@ get_rtx_code (enum tree_code tcode, bool unsignedp) static rtx vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode) { + struct expand_operand ops[2]; enum rtx_code rcode; tree t_op0, t_op1; rtx rtx_op0, rtx_op1; @@ -6731,15 +6436,11 @@ vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode) rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), EXPAND_STACK_PARM); - if (!insn_data[icode].operand[4].predicate (rtx_op0, GET_MODE (rtx_op0)) - && GET_MODE (rtx_op0) != VOIDmode) - rtx_op0 = force_reg (GET_MODE (rtx_op0), rtx_op0); - - if (!insn_data[icode].operand[5].predicate (rtx_op1, GET_MODE (rtx_op1)) - && GET_MODE (rtx_op1) != VOIDmode) - rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1); - - return gen_rtx_fmt_ee (rcode, VOIDmode, rtx_op0, rtx_op1); + create_input_operand (&ops[0], rtx_op0, GET_MODE (rtx_op0)); + create_input_operand (&ops[1], rtx_op1, GET_MODE (rtx_op1)); + if (!maybe_legitimize_operands (icode, 4, 2, ops)) + gcc_unreachable (); + return gen_rtx_fmt_ee (rcode, VOIDmode, ops[0].value, ops[1].value); } /* Return insn code for TYPE, the type of a VEC_COND_EXPR. */ @@ -6774,8 +6475,9 @@ rtx expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2, rtx target) { + struct expand_operand ops[6]; enum insn_code icode; - rtx comparison, rtx_op1, rtx_op2, cc_op0, cc_op1; + rtx comparison, rtx_op1, rtx_op2; enum machine_mode mode = TYPE_MODE (vec_cond_type); bool unsignedp = TYPE_UNSIGNED (vec_cond_type); @@ -6783,30 +6485,18 @@ expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2, if (icode == CODE_FOR_nothing) return 0; - if (!target || !insn_data[icode].operand[0].predicate (target, mode)) - target = gen_reg_rtx (mode); - - /* Get comparison rtx. First expand both cond expr operands. */ - comparison = vector_compare_rtx (op0, - unsignedp, icode); - cc_op0 = XEXP (comparison, 0); - cc_op1 = XEXP (comparison, 1); - /* Expand both operands and force them in reg, if required. */ + comparison = vector_compare_rtx (op0, unsignedp, icode); rtx_op1 = expand_normal (op1); - if (!insn_data[icode].operand[1].predicate (rtx_op1, mode) - && mode != VOIDmode) - rtx_op1 = force_reg (mode, rtx_op1); - rtx_op2 = expand_normal (op2); - if (!insn_data[icode].operand[2].predicate (rtx_op2, mode) - && mode != VOIDmode) - rtx_op2 = force_reg (mode, rtx_op2); - - /* Emit instruction! */ - emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2, - comparison, cc_op0, cc_op1)); - return target; + create_output_operand (&ops[0], target, mode); + create_input_operand (&ops[1], rtx_op1, mode); + create_input_operand (&ops[2], rtx_op2, mode); + create_fixed_operand (&ops[3], comparison); + create_fixed_operand (&ops[4], XEXP (comparison, 0)); + create_fixed_operand (&ops[5], XEXP (comparison, 1)); + expand_insn (icode, 6, ops); + return ops[0].value; } @@ -6820,28 +6510,18 @@ static rtx expand_val_compare_and_swap_1 (rtx mem, rtx old_val, rtx new_val, rtx target, enum insn_code icode) { + struct expand_operand ops[4]; enum machine_mode mode = GET_MODE (mem); - rtx insn; - if (!target || !insn_data[icode].operand[0].predicate (target, mode)) - target = gen_reg_rtx (mode); - - if (GET_MODE (old_val) != VOIDmode && GET_MODE (old_val) != mode) - old_val = convert_modes (mode, GET_MODE (old_val), old_val, 1); - if (!insn_data[icode].operand[2].predicate (old_val, mode)) - old_val = force_reg (mode, old_val); - - if (GET_MODE (new_val) != VOIDmode && GET_MODE (new_val) != mode) - new_val = convert_modes (mode, GET_MODE (new_val), new_val, 1); - if (!insn_data[icode].operand[3].predicate (new_val, mode)) - new_val = force_reg (mode, new_val); - - insn = GEN_FCN (icode) (target, mem, old_val, new_val); - if (insn == NULL_RTX) - return NULL_RTX; - emit_insn (insn); - - return target; + create_output_operand (&ops[0], target, mode); + create_fixed_operand (&ops[1], mem); + /* OLD_VAL and NEW_VAL may have been promoted to a wider mode. + Shrink them if so. */ + create_convert_operand_to (&ops[2], old_val, mode, true); + create_convert_operand_to (&ops[3], new_val, mode, true); + if (maybe_expand_insn (icode, 4, ops)) + return ops[0].value; + return NULL_RTX; } /* Expand a compare-and-swap operation and return its value. */ @@ -7046,17 +6726,13 @@ expand_sync_operation (rtx mem, rtx val, enum rtx_code code) /* Generate the direct operation, if present. */ if (icode != CODE_FOR_nothing) { - if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) - val = convert_modes (mode, GET_MODE (val), val, 1); - if (!insn_data[icode].operand[1].predicate (val, mode)) - val = force_reg (mode, val); + struct expand_operand ops[2]; - insn = GEN_FCN (icode) (mem, val); - if (insn) - { - emit_insn (insn); - return const0_rtx; - } + create_fixed_operand (&ops[0], mem); + /* VAL may have been promoted to a wider mode. Shrink it if so. */ + create_convert_operand_to (&ops[1], val, mode, true); + if (maybe_expand_insn (icode, 2, ops)) + return const0_rtx; } /* Failing that, generate a compare-and-swap loop in which we perform the @@ -7179,19 +6855,16 @@ expand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code, /* If we found something supported, great. */ if (icode != CODE_FOR_nothing) { - if (!target || !insn_data[icode].operand[0].predicate (target, mode)) - target = gen_reg_rtx (mode); + struct expand_operand ops[3]; - if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) - val = convert_modes (mode, GET_MODE (val), val, 1); - if (!insn_data[icode].operand[2].predicate (val, mode)) - val = force_reg (mode, val); - - insn = GEN_FCN (icode) (target, mem, val); - if (insn) + create_output_operand (&ops[0], target, mode); + create_fixed_operand (&ops[1], mem); + /* VAL may have been promoted to a wider mode. Shrink it if so. */ + create_convert_operand_to (&ops[2], val, mode, true); + if (maybe_expand_insn (icode, 3, ops)) { - emit_insn (insn); - + target = ops[0].value; + val = ops[2].value; /* If we need to compensate for using an operation with the wrong return value, do so now. */ if (compensate) @@ -7271,26 +6944,19 @@ expand_sync_lock_test_and_set (rtx mem, rtx val, rtx target) { enum machine_mode mode = GET_MODE (mem); enum insn_code icode; - rtx insn; /* If the target supports the test-and-set directly, great. */ icode = direct_optab_handler (sync_lock_test_and_set_optab, mode); if (icode != CODE_FOR_nothing) { - if (!target || !insn_data[icode].operand[0].predicate (target, mode)) - target = gen_reg_rtx (mode); - - if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) - val = convert_modes (mode, GET_MODE (val), val, 1); - if (!insn_data[icode].operand[2].predicate (val, mode)) - val = force_reg (mode, val); + struct expand_operand ops[3]; - insn = GEN_FCN (icode) (target, mem, val); - if (insn) - { - emit_insn (insn); - return target; - } + create_output_operand (&ops[0], target, mode); + create_fixed_operand (&ops[1], mem); + /* VAL may have been promoted to a wider mode. Shrink it if so. */ + create_convert_operand_to (&ops[2], val, mode, true); + if (maybe_expand_insn (icode, 3, ops)) + return ops[0].value; } /* Otherwise, use a compare-and-swap loop for the exchange. */ @@ -7318,5 +6984,201 @@ insn_operand_matches (enum insn_code icode, unsigned int opno, rtx operand) || (insn_data[(int) icode].operand[opno].predicate (operand, insn_data[(int) icode].operand[opno].mode))); } + +/* Try to make OP match operand OPNO of instruction ICODE. Return true + on success, storing the new operand value back in OP. */ + +static bool +maybe_legitimize_operand (enum insn_code icode, unsigned int opno, + struct expand_operand *op) +{ + enum machine_mode mode, imode; + bool old_volatile_ok, result; + + old_volatile_ok = volatile_ok; + mode = op->mode; + result = false; + switch (op->type) + { + case EXPAND_FIXED: + volatile_ok = true; + break; + + case EXPAND_OUTPUT: + gcc_assert (mode != VOIDmode); + if (!op->value + || op->value == const0_rtx + || GET_MODE (op->value) != mode + || !insn_operand_matches (icode, opno, op->value)) + op->value = gen_reg_rtx (mode); + break; + + case EXPAND_INPUT: + input: + gcc_assert (mode != VOIDmode); + gcc_assert (GET_MODE (op->value) == VOIDmode + || GET_MODE (op->value) == mode); + result = insn_operand_matches (icode, opno, op->value); + if (!result) + op->value = copy_to_mode_reg (mode, op->value); + break; + + case EXPAND_CONVERT_TO: + gcc_assert (mode != VOIDmode); + op->value = convert_to_mode (mode, op->value, op->unsigned_p); + goto input; + + case EXPAND_CONVERT_FROM: + if (GET_MODE (op->value) != VOIDmode) + mode = GET_MODE (op->value); + else + /* The caller must tell us what mode this value has. */ + gcc_assert (mode != VOIDmode); + + imode = insn_data[(int) icode].operand[opno].mode; + if (imode != VOIDmode && imode != mode) + { + op->value = convert_modes (imode, mode, op->value, op->unsigned_p); + mode = imode; + } + goto input; + + case EXPAND_ADDRESS: + gcc_assert (mode != VOIDmode); + op->value = convert_memory_address (mode, op->value); + goto input; + + case EXPAND_INTEGER: + mode = insn_data[(int) icode].operand[opno].mode; + if (mode != VOIDmode && const_int_operand (op->value, mode)) + goto input; + break; + } + if (!result) + result = insn_operand_matches (icode, opno, op->value); + volatile_ok = old_volatile_ok; + return result; +} + +/* Make OP describe an input operand that should have the same value + as VALUE, after any mode conversion that the target might request. + TYPE is the type of VALUE. */ + +void +create_convert_operand_from_type (struct expand_operand *op, + rtx value, tree type) +{ + create_convert_operand_from (op, value, TYPE_MODE (type), + TYPE_UNSIGNED (type)); +} + +/* Try to make operands [OPS, OPS + NOPS) match operands [OPNO, OPNO + NOPS) + of instruction ICODE. Return true on success, leaving the new operand + values in the OPS themselves. Emit no code on failure. */ + +bool +maybe_legitimize_operands (enum insn_code icode, unsigned int opno, + unsigned int nops, struct expand_operand *ops) +{ + rtx last; + unsigned int i; + + last = get_last_insn (); + for (i = 0; i < nops; i++) + if (!maybe_legitimize_operand (icode, opno + i, &ops[i])) + { + delete_insns_since (last); + return false; + } + return true; +} + +/* Try to generate instruction ICODE, using operands [OPS, OPS + NOPS) + as its operands. Return the instruction pattern on success, + and emit any necessary set-up code. Return null and emit no + code on failure. */ + +rtx +maybe_gen_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops) +{ + /* n_operands includes any automatically-generated match_scratches, + so we can't check for equality here. */ + gcc_assert (nops <= (unsigned int) insn_data[(int) icode].n_operands); + if (!maybe_legitimize_operands (icode, 0, nops, ops)) + return NULL_RTX; + + switch (nops) + { + case 1: + return GEN_FCN (icode) (ops[0].value); + case 2: + return GEN_FCN (icode) (ops[0].value, ops[1].value); + case 3: + return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value); + case 4: + return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value, + ops[3].value); + case 5: + return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value, + ops[3].value, ops[4].value); + case 6: + return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value, + ops[3].value, ops[4].value, ops[5].value); + } + gcc_unreachable (); +} + +/* Try to emit instruction ICODE, using operands [OPS, OPS + NOPS) + as its operands. Return true on success and emit no code on failure. */ + +bool +maybe_expand_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops) +{ + rtx pat = maybe_gen_insn (icode, nops, ops); + if (pat) + { + emit_insn (pat); + return true; + } + return false; +} + +/* Like maybe_expand_insn, but for jumps. */ + +bool +maybe_expand_jump_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops) +{ + rtx pat = maybe_gen_insn (icode, nops, ops); + if (pat) + { + emit_jump_insn (pat); + return true; + } + return false; +} + +/* Emit instruction ICODE, using operands [OPS, OPS + NOPS) + as its operands. */ + +void +expand_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops) +{ + if (!maybe_expand_insn (icode, nops, ops)) + gcc_unreachable (); +} + +/* Like expand_insn, but for jumps. */ + +void +expand_jump_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops) +{ + if (!maybe_expand_jump_insn (icode, nops, ops)) + gcc_unreachable (); +} #include "gt-optabs.h" |