From a5c7d693b920b650fb863e4b9a41b01c199f698f Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 23 Mar 2011 09:30:58 +0000 Subject: [PATCH] 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): Use nonmemory_operand rather than const_int_operand for operand 2. From-SVN: r171341 --- gcc/ChangeLog | 46 ++ gcc/builtins.c | 150 +++---- gcc/config/i386/i386.md | 2 +- gcc/explow.c | 30 +- gcc/expmed.c | 225 +++------- gcc/expr.c | 192 +++------ gcc/optabs.c | 918 +++++++++++++++++----------------------- gcc/optabs.h | 146 ++++++- 8 files changed, 766 insertions(+), 943 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ee72d4e3b1b..14f8008214c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,49 @@ +2011-03-23 Richard Sandiford + + * 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): Use nonmemory_operand rather + than const_int_operand for operand 2. + 2011-03-23 Andreas Krebbel * dwarf2out.c (const_ok_for_output_1): Print the unspec enum name diff --git a/gcc/builtins.c b/gcc/builtins.c index ad21b2d6163..f2b5130b837 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -1143,15 +1143,13 @@ expand_builtin_prefetch (tree exp) #ifdef HAVE_prefetch if (HAVE_prefetch) { - if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate) - (op0, - insn_data[(int) CODE_FOR_prefetch].operand[0].mode)) - || (GET_MODE (op0) != Pmode)) - { - op0 = convert_memory_address (Pmode, op0); - op0 = force_reg (Pmode, op0); - } - emit_insn (gen_prefetch (op0, op1, op2)); + struct expand_operand ops[3]; + + create_address_operand (&ops[0], op0); + create_integer_operand (&ops[1], INTVAL (op1)); + create_integer_operand (&ops[2], INTVAL (op2)); + if (maybe_expand_insn (CODE_FOR_prefetch, 3, ops)) + return; } #endif @@ -2431,16 +2429,9 @@ expand_builtin_interclass_mathfn (tree exp, rtx target) if (icode != CODE_FOR_nothing) { + struct expand_operand ops[1]; rtx last = get_last_insn (); tree orig_arg = arg; - /* Make a suitable register to place result in. */ - if (!target - || GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)) - || !insn_data[icode].operand[0].predicate (target, GET_MODE (target))) - target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp))); - - gcc_assert (insn_data[icode].operand[0].predicate - (target, GET_MODE (target))); /* Wrap the computation of the argument in a SAVE_EXPR, as we may need to expand the argument again. This way, we will not perform @@ -2452,10 +2443,11 @@ expand_builtin_interclass_mathfn (tree exp, rtx target) if (mode != GET_MODE (op0)) op0 = convert_to_mode (mode, op0, 0); - /* Compute into TARGET. - Set TARGET to wherever the result comes back. */ - if (maybe_emit_unop_insn (icode, target, op0, UNKNOWN)) - return target; + create_output_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (exp))); + if (maybe_legitimize_operands (icode, 0, 1, ops) + && maybe_emit_unop_insn (icode, ops[0].value, op0, UNKNOWN)) + return ops[0].value; + delete_insns_since (last); CALL_EXPR_ARG (exp, 0) = orig_arg; } @@ -3362,11 +3354,12 @@ expand_builtin_strlen (tree exp, rtx target, return NULL_RTX; else { + struct expand_operand ops[4]; rtx pat; tree len; tree src = CALL_EXPR_ARG (exp, 0); - rtx result, src_reg, char_rtx, before_strlen; - enum machine_mode insn_mode = target_mode, char_mode; + rtx src_reg, before_strlen; + enum machine_mode insn_mode = target_mode; enum insn_code icode = CODE_FOR_nothing; unsigned int align; @@ -3405,14 +3398,6 @@ expand_builtin_strlen (tree exp, rtx target, if (insn_mode == VOIDmode) return NULL_RTX; - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && REG_P (result) - && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); - /* Make a place to hold the source address. We will not expand the actual source until we are sure that the expansion will not fail -- there are trees that cannot be expanded twice. */ @@ -3422,17 +3407,12 @@ expand_builtin_strlen (tree exp, rtx target, source operand later. */ before_strlen = get_last_insn (); - char_rtx = const0_rtx; - char_mode = insn_data[(int) icode].operand[2].mode; - if (! (*insn_data[(int) icode].operand[2].predicate) (char_rtx, - char_mode)) - char_rtx = copy_to_mode_reg (char_mode, char_rtx); - - pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg), - char_rtx, GEN_INT (align)); - if (! pat) + create_output_operand (&ops[0], target, insn_mode); + create_fixed_operand (&ops[1], gen_rtx_MEM (BLKmode, src_reg)); + create_integer_operand (&ops[2], 0); + create_integer_operand (&ops[3], align); + if (!maybe_expand_insn (icode, 4, ops)) return NULL_RTX; - emit_insn (pat); /* Now that we are assured of success, expand the source. */ start_sequence (); @@ -3448,12 +3428,12 @@ expand_builtin_strlen (tree exp, rtx target, emit_insn_before (pat, get_insns ()); /* Return the value in the proper mode for this function. */ - if (GET_MODE (result) == target_mode) - target = result; + if (GET_MODE (ops[0].value) == target_mode) + target = ops[0].value; else if (target != 0) - convert_move (target, result, 0); + convert_move (target, ops[0].value, 0); else - target = convert_to_mode (target_mode, result, 0); + target = convert_to_mode (target_mode, ops[0].value, 0); return target; } @@ -3674,56 +3654,39 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, static rtx expand_movstr (tree dest, tree src, rtx target, int endp) { + struct expand_operand ops[3]; rtx end; rtx dest_mem; rtx src_mem; - rtx insn; - const struct insn_data_d * data; if (!HAVE_movstr) return NULL_RTX; dest_mem = get_memory_rtx (dest, NULL); src_mem = get_memory_rtx (src, NULL); - data = insn_data + CODE_FOR_movstr; if (!endp) { target = force_reg (Pmode, XEXP (dest_mem, 0)); dest_mem = replace_equiv_address (dest_mem, target); - end = gen_reg_rtx (Pmode); - } - else - { - if (target == 0 - || target == const0_rtx - || ! (*data->operand[0].predicate) (target, Pmode)) - { - end = gen_reg_rtx (Pmode); - if (target != const0_rtx) - target = end; - } - else - end = target; } - if (data->operand[0].mode != VOIDmode) - end = gen_lowpart (data->operand[0].mode, end); - - insn = data->genfun (end, dest_mem, src_mem); - - gcc_assert (insn); + create_output_operand (&ops[0], endp ? target : NULL_RTX, Pmode); + create_fixed_operand (&ops[1], dest_mem); + create_fixed_operand (&ops[2], src_mem); + expand_insn (CODE_FOR_movstr, 3, ops); - emit_insn (insn); - - /* movstr is supposed to set end to the address of the NUL - terminator. If the caller requested a mempcpy-like return value, - adjust it. */ - if (endp == 1 && target != const0_rtx) + if (endp && target != const0_rtx) { - rtx tem = plus_constant (gen_lowpart (GET_MODE (target), end), 1); - emit_move_insn (target, force_operand (tem, NULL_RTX)); + target = ops[0].value; + /* movstr is supposed to set end to the address of the NUL + terminator. If the caller requested a mempcpy-like return value, + adjust it. */ + if (endp == 1) + { + rtx tem = plus_constant (gen_lowpart (GET_MODE (target), end), 1); + emit_move_insn (target, force_operand (tem, NULL_RTX)); + } } - return target; } @@ -5223,7 +5186,6 @@ expand_builtin___clear_cache (tree exp ATTRIBUTE_UNUSED) /* We have a "clear_cache" insn, and it will handle everything. */ tree begin, end; rtx begin_rtx, end_rtx; - enum insn_code icode; /* We must not expand to a library call. If we did, any fallback library function in libgcc that might contain a call to @@ -5236,21 +5198,18 @@ expand_builtin___clear_cache (tree exp ATTRIBUTE_UNUSED) if (HAVE_clear_cache) { - icode = CODE_FOR_clear_cache; + struct expand_operand ops[2]; begin = CALL_EXPR_ARG (exp, 0); begin_rtx = expand_expr (begin, NULL_RTX, Pmode, EXPAND_NORMAL); - begin_rtx = convert_memory_address (Pmode, begin_rtx); - if (!insn_data[icode].operand[0].predicate (begin_rtx, Pmode)) - begin_rtx = copy_to_mode_reg (Pmode, begin_rtx); end = CALL_EXPR_ARG (exp, 1); end_rtx = expand_expr (end, NULL_RTX, Pmode, EXPAND_NORMAL); - end_rtx = convert_memory_address (Pmode, end_rtx); - if (!insn_data[icode].operand[1].predicate (end_rtx, Pmode)) - end_rtx = copy_to_mode_reg (Pmode, end_rtx); - emit_insn (gen_clear_cache (begin_rtx, end_rtx)); + create_address_operand (&ops[0], begin_rtx); + create_address_operand (&ops[1], end_rtx); + if (maybe_expand_insn (CODE_FOR_clear_cache, 2, ops)) + return const0_rtx; } return const0_rtx; #endif /* HAVE_clear_cache */ @@ -5748,9 +5707,9 @@ expand_builtin_synchronize (void) static void expand_builtin_lock_release (enum machine_mode mode, tree exp) { + struct expand_operand ops[2]; enum insn_code icode; - rtx mem, insn; - rtx val = const0_rtx; + rtx mem; /* Expand the operands. */ mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); @@ -5759,21 +5718,16 @@ expand_builtin_lock_release (enum machine_mode mode, tree exp) icode = direct_optab_handler (sync_lock_release_optab, mode); if (icode != CODE_FOR_nothing) { - if (!insn_data[icode].operand[1].predicate (val, mode)) - val = force_reg (mode, val); - - insn = GEN_FCN (icode) (mem, val); - if (insn) - { - emit_insn (insn); - return; - } + create_fixed_operand (&ops[0], mem); + create_input_operand (&ops[1], const0_rtx, mode); + if (maybe_expand_insn (icode, 2, ops)) + return; } /* Otherwise we can implement this operation by emitting a barrier followed by a store of zero. */ expand_builtin_synchronize (); - emit_move_insn (mem, val); + emit_move_insn (mem, const0_rtx); } /* Expand an expression EXP that calls a built-in function, diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index c9761a46e4c..c2901decdf3 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -15793,7 +15793,7 @@ (define_expand "setmem" [(use (match_operand:BLK 0 "memory_operand" "")) (use (match_operand:SWI48 1 "nonmemory_operand" "")) - (use (match_operand 2 "const_int_operand" "")) + (use (match_operand:QI 2 "nonmemory_operand" "")) (use (match_operand 3 "const_int_operand" "")) (use (match_operand:SI 4 "const_int_operand" "")) (use (match_operand:SI 5 "const_int_operand" ""))] diff --git a/gcc/explow.c b/gcc/explow.c index 34adcb93281..a0a160dd2bd 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -1379,21 +1379,13 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align, #ifdef HAVE_allocate_stack if (HAVE_allocate_stack) { - enum machine_mode mode = STACK_SIZE_MODE; - insn_operand_predicate_fn pred; - + struct expand_operand ops[2]; /* We don't have to check against the predicate for operand 0 since TARGET is known to be a pseudo of the proper mode, which must - be valid for the operand. For operand 1, convert to the - proper mode and validate. */ - if (mode == VOIDmode) - mode = insn_data[(int) CODE_FOR_allocate_stack].operand[1].mode; - - pred = insn_data[(int) CODE_FOR_allocate_stack].operand[1].predicate; - if (pred && ! ((*pred) (size, mode))) - size = copy_to_mode_reg (mode, convert_to_mode (mode, size, 1)); - - emit_insn (gen_allocate_stack (target, size)); + be valid for the operand. */ + create_fixed_operand (&ops[0], target); + create_convert_operand_to (&ops[1], size, STACK_SIZE_MODE, true); + expand_insn (CODE_FOR_allocate_stack, 2, ops); } else #endif @@ -1544,22 +1536,22 @@ probe_stack_range (HOST_WIDE_INT first, rtx size) plus_constant (size, first))); emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr, Pmode); + return; } /* Next see if we have an insn to check the stack. */ #ifdef HAVE_check_stack - else if (HAVE_check_stack) + if (HAVE_check_stack) { + struct expand_operand ops[1]; rtx addr = memory_address (Pmode, gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, stack_pointer_rtx, plus_constant (size, first))); - insn_operand_predicate_fn pred - = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate; - if (pred && !((*pred) (addr, Pmode))) - addr = copy_to_mode_reg (Pmode, addr); - emit_insn (gen_check_stack (addr)); + create_input_operand (&ops[0], addr, Pmode); + if (maybe_expand_insn (CODE_FOR_check_stack, 1, ops)) + return; } #endif diff --git a/gcc/expmed.c b/gcc/expmed.c index b0c1e235dd7..6218f3d4ce8 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -323,22 +323,6 @@ mode_for_extraction (enum extraction_pattern pattern, int opno) return word_mode; return data->operand[opno].mode; } - -/* Return true if X, of mode MODE, matches the predicate for operand - OPNO of instruction ICODE. Allow volatile memories, regardless of - the ambient volatile_ok setting. */ - -static bool -check_predicate_volatile_ok (enum insn_code icode, int opno, - rtx x, enum machine_mode mode) -{ - bool save_volatile_ok, result; - - save_volatile_ok = volatile_ok; - result = insn_data[(int) icode].operand[opno].predicate (x, mode); - volatile_ok = save_volatile_ok; - return result; -} /* A subroutine of store_bit_field, with the same arguments. Return true if the operation could be implemented. @@ -405,40 +389,17 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, && bitsize == GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0))) && !(bitnum % GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0))))) { + struct expand_operand ops[3]; enum machine_mode outermode = GET_MODE (op0); enum machine_mode innermode = GET_MODE_INNER (outermode); - int icode = (int) optab_handler (vec_set_optab, outermode); + enum insn_code icode = optab_handler (vec_set_optab, outermode); int pos = bitnum / GET_MODE_BITSIZE (innermode); - rtx rtxpos = GEN_INT (pos); - rtx src = value; - rtx dest = op0; - rtx pat, seq; - enum machine_mode mode0 = insn_data[icode].operand[0].mode; - enum machine_mode mode1 = insn_data[icode].operand[1].mode; - enum machine_mode mode2 = insn_data[icode].operand[2].mode; - - start_sequence (); - if (! (*insn_data[icode].operand[1].predicate) (src, mode1)) - src = copy_to_mode_reg (mode1, src); - - if (! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2)) - rtxpos = copy_to_mode_reg (mode1, rtxpos); - - /* 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) (dest, mode0) - && (*insn_data[icode].operand[1].predicate) (src, mode1) - && (*insn_data[icode].operand[2].predicate) (rtxpos, mode2)); - pat = GEN_FCN (icode) (dest, src, rtxpos); - seq = get_insns (); - end_sequence (); - if (pat) - { - emit_insn (seq); - emit_insn (pat); - return true; - } + create_fixed_operand (&ops[0], op0); + create_input_operand (&ops[1], value, innermode); + create_integer_operand (&ops[2], pos); + if (maybe_expand_insn (icode, 3, ops)) + return true; } /* If the target is a register, overwriting the entire object, or storing @@ -515,44 +476,30 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, && bitsize == GET_MODE_BITSIZE (fieldmode) && optab_handler (movstrict_optab, fieldmode) != CODE_FOR_nothing) { - int icode = optab_handler (movstrict_optab, fieldmode); - rtx insn; - rtx start = get_last_insn (); + struct expand_operand ops[2]; + enum insn_code icode = optab_handler (movstrict_optab, fieldmode); rtx arg0 = op0; - /* Get appropriate low part of the value being stored. */ - if (CONST_INT_P (value) || REG_P (value)) - value = gen_lowpart (fieldmode, value); - else if (!(GET_CODE (value) == SYMBOL_REF - || GET_CODE (value) == LABEL_REF - || GET_CODE (value) == CONST)) - value = convert_to_mode (fieldmode, value, 0); - - if (! (*insn_data[icode].operand[1].predicate) (value, fieldmode)) - value = copy_to_mode_reg (fieldmode, value); - - if (GET_CODE (op0) == SUBREG) + if (GET_CODE (arg0) == SUBREG) { /* Else we've got some float mode source being extracted into a different float mode destination -- this combination of subregs results in Severe Tire Damage. */ - gcc_assert (GET_MODE (SUBREG_REG (op0)) == fieldmode + gcc_assert (GET_MODE (SUBREG_REG (arg0)) == fieldmode || GET_MODE_CLASS (fieldmode) == MODE_INT || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT); - arg0 = SUBREG_REG (op0); + arg0 = SUBREG_REG (arg0); } - insn = (GEN_FCN (icode) - (gen_rtx_SUBREG (fieldmode, arg0, - (bitnum % BITS_PER_WORD) / BITS_PER_UNIT - + (offset * UNITS_PER_WORD)), - value)); - if (insn) - { - emit_insn (insn); - return true; - } - delete_insns_since (start); + arg0 = gen_rtx_SUBREG (fieldmode, arg0, + (bitnum % BITS_PER_WORD) / BITS_PER_UNIT + + (offset * UNITS_PER_WORD)); + + create_fixed_operand (&ops[0], arg0); + /* Shrink the source operand to FIELDMODE. */ + create_convert_operand_to (&ops[1], value, fieldmode, false); + if (maybe_expand_insn (icode, 2, ops)) + return true; } /* Handle fields bigger than a word. */ @@ -653,16 +600,13 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, && bitsize > 0 && GET_MODE_BITSIZE (op_mode) >= bitsize && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG) - && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode))) - && insn_data[CODE_FOR_insv].operand[1].predicate (GEN_INT (bitsize), - VOIDmode) - && check_predicate_volatile_ok (CODE_FOR_insv, 0, op0, VOIDmode)) + && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))) { + struct expand_operand ops[4]; int xbitpos = bitpos; rtx value1; rtx xop0 = op0; rtx last = get_last_insn (); - rtx pat; bool copy_back = false; /* Add OFFSET into OP0's address. */ @@ -743,17 +687,12 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, gcc_assert (CONSTANT_P (value)); } - /* If this machine's insv insists on a register, - get VALUE1 into a register. */ - if (! ((*insn_data[(int) CODE_FOR_insv].operand[3].predicate) - (value1, op_mode))) - value1 = force_reg (op_mode, value1); - - pat = gen_insv (xop0, GEN_INT (bitsize), GEN_INT (xbitpos), value1); - if (pat) + create_fixed_operand (&ops[0], xop0); + create_integer_operand (&ops[1], bitsize); + create_integer_operand (&ops[2], xbitpos); + create_input_operand (&ops[3], value1, op_mode); + if (maybe_expand_insn (CODE_FOR_insv, 4, ops)) { - emit_insn (pat); - if (copy_back) convert_move (op0, xop0, true); return true; @@ -1235,50 +1174,21 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, && ((bitnum + bitsize - 1) / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0))) == bitnum / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0))))) { + struct expand_operand ops[3]; enum machine_mode outermode = GET_MODE (op0); enum machine_mode innermode = GET_MODE_INNER (outermode); - int icode = (int) optab_handler (vec_extract_optab, outermode); + enum insn_code icode = optab_handler (vec_extract_optab, outermode); unsigned HOST_WIDE_INT pos = bitnum / GET_MODE_BITSIZE (innermode); - rtx rtxpos = GEN_INT (pos); - rtx src = op0; - rtx dest = NULL, pat, seq; - enum machine_mode mode0 = insn_data[icode].operand[0].mode; - enum machine_mode mode1 = insn_data[icode].operand[1].mode; - enum machine_mode mode2 = insn_data[icode].operand[2].mode; - - if (innermode == tmode || innermode == mode) - dest = target; - - if (!dest) - dest = gen_reg_rtx (innermode); - - start_sequence (); - - if (! (*insn_data[icode].operand[0].predicate) (dest, mode0)) - dest = copy_to_mode_reg (mode0, dest); - if (! (*insn_data[icode].operand[1].predicate) (src, mode1)) - src = copy_to_mode_reg (mode1, src); - - if (! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2)) - rtxpos = copy_to_mode_reg (mode1, rtxpos); - - /* 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) (dest, mode0) - && (*insn_data[icode].operand[1].predicate) (src, mode1) - && (*insn_data[icode].operand[2].predicate) (rtxpos, mode2)); - - pat = GEN_FCN (icode) (dest, src, rtxpos); - seq = get_insns (); - end_sequence (); - if (pat) + create_output_operand (&ops[0], target, innermode); + create_input_operand (&ops[1], op0, outermode); + create_integer_operand (&ops[2], pos); + if (maybe_expand_insn (icode, 3, ops)) { - emit_insn (seq); - emit_insn (pat); - if (mode0 != mode) - return gen_lowpart (tmode, dest); - return dest; + target = ops[0].value; + if (GET_MODE (target) != mode) + return gen_lowpart (tmode, target); + return target; } } @@ -1517,17 +1427,14 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, acceptable to the format of ext(z)v. */ && !(GET_CODE (op0) == SUBREG && GET_MODE (op0) != ext_mode) && !((REG_P (op0) || GET_CODE (op0) == SUBREG) - && (bitsize + bitpos > GET_MODE_BITSIZE (ext_mode))) - && check_predicate_volatile_ok (icode, 1, op0, GET_MODE (op0))) + && (bitsize + bitpos > GET_MODE_BITSIZE (ext_mode)))) { + struct expand_operand ops[4]; unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset; - rtx bitsize_rtx, bitpos_rtx; - rtx last = get_last_insn (); rtx xop0 = op0; rtx xtarget = target; rtx xspec_target = target; rtx xspec_target_subreg = 0; - rtx pat; /* If op0 is a register, we need it in EXT_MODE to make it acceptable to the format of ext(z)v. */ @@ -1570,27 +1477,20 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, xtarget = gen_reg_rtx (ext_mode); } - /* If this machine's ext(z)v insists on a register target, - make sure we have one. */ - if (!insn_data[(int) icode].operand[0].predicate (xtarget, ext_mode)) - xtarget = gen_reg_rtx (ext_mode); - - bitsize_rtx = GEN_INT (bitsize); - bitpos_rtx = GEN_INT (xbitpos); - - pat = (unsignedp - ? gen_extzv (xtarget, xop0, bitsize_rtx, bitpos_rtx) - : gen_extv (xtarget, xop0, bitsize_rtx, bitpos_rtx)); - if (pat) + create_output_operand (&ops[0], xtarget, ext_mode); + create_fixed_operand (&ops[1], xop0); + create_integer_operand (&ops[2], bitsize); + create_integer_operand (&ops[3], xbitpos); + if (maybe_expand_insn (unsignedp ? CODE_FOR_extzv : CODE_FOR_extv, + 4, ops)) { - emit_insn (pat); + xtarget = ops[0].value; if (xtarget == xspec_target) return xtarget; if (xtarget == xspec_target_subreg) return xspec_target; return convert_extracted_bit_field (xtarget, mode, tmode, unsignedp); } - delete_insns_since (last); } /* If OP0 is a memory, try copying it to a register and seeing if a @@ -5101,19 +5001,14 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code, int unsignedp, rtx x, rtx y, int normalizep, enum machine_mode target_mode) { - rtx op0, last, comparison, subtarget, pattern; + struct expand_operand ops[4]; + rtx op0, last, comparison, subtarget; enum machine_mode result_mode = insn_data[(int) icode].operand[0].mode; last = get_last_insn (); x = prepare_operand (icode, x, 2, mode, compare_mode, unsignedp); y = prepare_operand (icode, y, 3, mode, compare_mode, unsignedp); - comparison = gen_rtx_fmt_ee (code, result_mode, x, y); - if (!x || !y - || !insn_data[icode].operand[2].predicate - (x, insn_data[icode].operand[2].mode) - || !insn_data[icode].operand[3].predicate - (y, insn_data[icode].operand[3].mode) - || !insn_data[icode].operand[1].predicate (comparison, VOIDmode)) + if (!x || !y) { delete_insns_since (last); return NULL_RTX; @@ -5124,16 +5019,18 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code, if (!target) target = gen_reg_rtx (target_mode); - if (optimize - || !(insn_data[(int) icode].operand[0].predicate (target, result_mode))) - subtarget = gen_reg_rtx (result_mode); - else - subtarget = target; + comparison = gen_rtx_fmt_ee (code, result_mode, x, y); - pattern = GEN_FCN (icode) (subtarget, comparison, x, y); - if (!pattern) - return NULL_RTX; - emit_insn (pattern); + create_output_operand (&ops[0], optimize ? NULL_RTX : target, result_mode); + create_fixed_operand (&ops[1], comparison); + create_fixed_operand (&ops[2], x); + create_fixed_operand (&ops[3], y); + if (!maybe_expand_insn (icode, 4, ops)) + { + delete_insns_since (last); + return NULL_RTX; + } + subtarget = ops[0].value; /* If we are converting to a wider mode, first convert to TARGET_MODE, then normalize. This produces better combining diff --git a/gcc/expr.c b/gcc/expr.c index 2c0378c12e7..572f0f4eb60 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1258,7 +1258,6 @@ static bool emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align, unsigned int expected_align, HOST_WIDE_INT expected_size) { - rtx opalign = GEN_INT (align / BITS_PER_UNIT); int save_volatile_ok = volatile_ok; enum machine_mode mode; @@ -1276,7 +1275,6 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align, mode = GET_MODE_WIDER_MODE (mode)) { enum insn_code code = direct_optab_handler (movmem_optab, mode); - insn_operand_predicate_fn pred; if (code != CODE_FOR_nothing /* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT @@ -1286,43 +1284,32 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align, && ((CONST_INT_P (size) && ((unsigned HOST_WIDE_INT) INTVAL (size) <= (GET_MODE_MASK (mode) >> 1))) - || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD) - && ((pred = insn_data[(int) code].operand[0].predicate) == 0 - || (*pred) (x, BLKmode)) - && ((pred = insn_data[(int) code].operand[1].predicate) == 0 - || (*pred) (y, BLKmode)) - && ((pred = insn_data[(int) code].operand[3].predicate) == 0 - || (*pred) (opalign, VOIDmode))) - { - rtx op2; - rtx last = get_last_insn (); - rtx pat; - - op2 = convert_to_mode (mode, size, 1); - pred = insn_data[(int) code].operand[2].predicate; - if (pred != 0 && ! (*pred) (op2, mode)) - op2 = copy_to_mode_reg (mode, op2); + || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)) + { + struct expand_operand ops[6]; + unsigned int nops; /* ??? When called via emit_block_move_for_call, it'd be nice if there were some way to inform the backend, so that it doesn't fail the expansion because it thinks emitting the libcall would be more efficient. */ - - if (insn_data[(int) code].n_operands == 4) - pat = GEN_FCN ((int) code) (x, y, op2, opalign); - else - pat = GEN_FCN ((int) code) (x, y, op2, opalign, - GEN_INT (expected_align - / BITS_PER_UNIT), - GEN_INT (expected_size)); - if (pat) + nops = insn_data[(int) code].n_operands; + create_fixed_operand (&ops[0], x); + create_fixed_operand (&ops[1], y); + /* The check above guarantees that this size conversion is valid. */ + create_convert_operand_to (&ops[2], size, mode, true); + create_integer_operand (&ops[3], align / BITS_PER_UNIT); + if (nops != 4) + { + create_integer_operand (&ops[4], expected_align / BITS_PER_UNIT); + create_integer_operand (&ops[5], expected_size); + nops = 6; + } + if (maybe_expand_insn (code, nops, ops)) { - emit_insn (pat); volatile_ok = save_volatile_ok; return true; } - else - delete_insns_since (last); } } @@ -2705,7 +2692,6 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align, including more than one in the machine description unless the more limited one has some advantage. */ - rtx opalign = GEN_INT (align / BITS_PER_UNIT); enum machine_mode mode; if (expected_align < align) @@ -2715,7 +2701,6 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align, mode = GET_MODE_WIDER_MODE (mode)) { enum insn_code code = direct_optab_handler (setmem_optab, mode); - insn_operand_predicate_fn pred; if (code != CODE_FOR_nothing /* We don't need MODE to be narrower than @@ -2725,46 +2710,25 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align, && ((CONST_INT_P (size) && ((unsigned HOST_WIDE_INT) INTVAL (size) <= (GET_MODE_MASK (mode) >> 1))) - || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD) - && ((pred = insn_data[(int) code].operand[0].predicate) == 0 - || (*pred) (object, BLKmode)) - && ((pred = insn_data[(int) code].operand[3].predicate) == 0 - || (*pred) (opalign, VOIDmode))) - { - rtx opsize, opchar; - enum machine_mode char_mode; - rtx last = get_last_insn (); - rtx pat; - - opsize = convert_to_mode (mode, size, 1); - pred = insn_data[(int) code].operand[1].predicate; - if (pred != 0 && ! (*pred) (opsize, mode)) - opsize = copy_to_mode_reg (mode, opsize); - - opchar = val; - char_mode = insn_data[(int) code].operand[2].mode; - if (char_mode != VOIDmode) + || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)) + { + struct expand_operand ops[6]; + unsigned int nops; + + nops = insn_data[(int) code].n_operands; + create_fixed_operand (&ops[0], object); + /* The check above guarantees that this size conversion is valid. */ + create_convert_operand_to (&ops[1], size, mode, true); + create_convert_operand_from (&ops[2], val, byte_mode, true); + create_integer_operand (&ops[3], align / BITS_PER_UNIT); + if (nops != 4) { - opchar = convert_to_mode (char_mode, opchar, 1); - pred = insn_data[(int) code].operand[2].predicate; - if (pred != 0 && ! (*pred) (opchar, char_mode)) - opchar = copy_to_mode_reg (char_mode, opchar); + create_integer_operand (&ops[4], expected_align / BITS_PER_UNIT); + create_integer_operand (&ops[5], expected_size); + nops = 6; } - - if (insn_data[(int) code].n_operands == 4) - pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign); - else - pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign, - GEN_INT (expected_align - / BITS_PER_UNIT), - GEN_INT (expected_size)); - if (pat) - { - emit_insn (pat); - return true; - } - else - delete_insns_since (last); + if (maybe_expand_insn (code, nops, ops)) + return true; } } @@ -3547,7 +3511,6 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type) unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode)); rtx dest; enum insn_code icode; - insn_operand_predicate_fn pred; stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode)); /* If there is push pattern, use it. Otherwise try old way of throwing @@ -3555,11 +3518,11 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type) icode = optab_handler (push_optab, mode); if (icode != CODE_FOR_nothing) { - if (((pred = insn_data[(int) icode].operand[0].predicate) - && !((*pred) (x, mode)))) - x = force_reg (mode, x); - emit_insn (GEN_FCN (icode) (x)); - return; + struct expand_operand ops[1]; + + create_input_operand (&ops[0], x, mode); + if (maybe_expand_insn (icode, 1, ops)) + return; } if (GET_MODE_SIZE (mode) == rounded_size) dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx); @@ -4147,7 +4110,8 @@ expand_assignment (tree to, tree from, bool nontemporal) rtx to_rtx = 0; rtx result; enum machine_mode mode; - int align, icode; + int align; + enum insn_code icode; /* Don't crash if the lhs of the assignment was erroneous. */ if (TREE_CODE (to) == ERROR_MARK) @@ -4170,8 +4134,9 @@ expand_assignment (tree to, tree from, bool nontemporal) && ((icode = optab_handler (movmisalign_optab, mode)) != CODE_FOR_nothing)) { - enum machine_mode address_mode, op_mode1; - rtx insn, reg, op0, mem; + struct expand_operand ops[2]; + enum machine_mode address_mode; + rtx reg, op0, mem; reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL); reg = force_not_mem (reg); @@ -4212,16 +4177,11 @@ expand_assignment (tree to, tree from, bool nontemporal) if (TREE_THIS_VOLATILE (to)) MEM_VOLATILE_P (mem) = 1; - op_mode1 = insn_data[icode].operand[1].mode; - if (! (*insn_data[icode].operand[1].predicate) (reg, op_mode1) - && op_mode1 != VOIDmode) - reg = copy_to_mode_reg (op_mode1, reg); - - insn = GEN_FCN (icode) (mem, reg); + create_fixed_operand (&ops[0], mem); + create_input_operand (&ops[1], reg, mode); /* The movmisalign pattern cannot fail, else the assignment would silently be omitted. */ - gcc_assert (insn != NULL_RTX); - emit_insn (insn); + expand_insn (icode, 2, ops); return; } @@ -4483,31 +4443,16 @@ expand_assignment (tree to, tree from, bool nontemporal) bool emit_storent_insn (rtx to, rtx from) { - enum machine_mode mode = GET_MODE (to), imode; + struct expand_operand ops[2]; + enum machine_mode mode = GET_MODE (to); enum insn_code code = optab_handler (storent_optab, mode); - rtx pattern; if (code == CODE_FOR_nothing) return false; - imode = insn_data[code].operand[0].mode; - if (!insn_data[code].operand[0].predicate (to, imode)) - return false; - - imode = insn_data[code].operand[1].mode; - if (!insn_data[code].operand[1].predicate (from, imode)) - { - from = copy_to_mode_reg (imode, from); - if (!insn_data[code].operand[1].predicate (from, imode)) - return false; - } - - pattern = GEN_FCN (code) (to, from); - if (pattern == NULL_RTX) - return false; - - emit_insn (pattern); - return true; + create_fixed_operand (&ops[0], to); + create_input_operand (&ops[1], from, mode); + return maybe_expand_insn (code, 2, ops); } /* Generate code for computing expression EXP, @@ -10120,10 +10065,10 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range, rtx table_label ATTRIBUTE_UNUSED, rtx default_label, rtx fallback_label ATTRIBUTE_UNUSED) { + struct expand_operand ops[5]; enum machine_mode index_mode = SImode; int index_bits = GET_MODE_BITSIZE (index_mode); rtx op1, op2, index; - enum machine_mode op_mode; if (! HAVE_casesi) return 0; @@ -10158,32 +10103,17 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range, do_pending_stack_adjust (); - op_mode = insn_data[(int) CODE_FOR_casesi].operand[0].mode; - if (! (*insn_data[(int) CODE_FOR_casesi].operand[0].predicate) - (index, op_mode)) - index = copy_to_mode_reg (op_mode, index); - op1 = expand_normal (minval); - - op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode; - op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)), - op1, TYPE_UNSIGNED (TREE_TYPE (minval))); - if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate) - (op1, op_mode)) - op1 = copy_to_mode_reg (op_mode, op1); - op2 = expand_normal (range); - op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode; - op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)), - op2, TYPE_UNSIGNED (TREE_TYPE (range))); - if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate) - (op2, op_mode)) - op2 = copy_to_mode_reg (op_mode, op2); - - emit_jump_insn (gen_casesi (index, op1, op2, - table_label, !default_label - ? fallback_label : default_label)); + create_input_operand (&ops[0], index, index_mode); + create_convert_operand_from_type (&ops[1], op1, TREE_TYPE (minval)); + create_convert_operand_from_type (&ops[2], op2, TREE_TYPE (range)); + create_fixed_operand (&ops[3], table_label); + create_fixed_operand (&ops[4], (default_label + ? default_label + : fallback_label)); + expand_jump_insn (CODE_FOR_casesi, 5, ops); return 1; } diff --git a/gcc/optabs.c b/gcc/optabs.c index a874c427e43..d1cfd3a3f9b 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" diff --git a/gcc/optabs.h b/gcc/optabs.h index 1849a30bfe5..be61f549fd4 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -791,8 +791,8 @@ extern rtx expand_copysign (rtx, rtx, rtx); /* Generate an instruction with a given INSN_CODE with an output and an input. */ -extern void emit_unop_insn (int, rtx, rtx, enum rtx_code); -extern bool maybe_emit_unop_insn (int, rtx, rtx, enum rtx_code); +extern void emit_unop_insn (enum insn_code, rtx, rtx, enum rtx_code); +extern bool maybe_emit_unop_insn (enum insn_code, rtx, rtx, enum rtx_code); /* An extra flag to control optab_for_tree_code's behavior. This is needed to distinguish between machines with a vector shift that takes a scalar for the @@ -926,6 +926,148 @@ extern rtx convert_optab_libfunc (convert_optab optab, enum machine_mode mode1, extern bool insn_operand_matches (enum insn_code icode, unsigned int opno, rtx operand); + +/* Describes the type of an expand_operand. Each value is associated + with a create_*_operand function; see the comments above those + functions for details. */ +enum expand_operand_type { + EXPAND_FIXED, + EXPAND_OUTPUT, + EXPAND_INPUT, + EXPAND_CONVERT_TO, + EXPAND_CONVERT_FROM, + EXPAND_ADDRESS, + EXPAND_INTEGER +}; + +/* Information about an operand for instruction expansion. */ +struct expand_operand { + /* The type of operand. */ + ENUM_BITFIELD (expand_operand_type) type : 8; + + /* True if any conversion should treat VALUE as being unsigned + rather than signed. Only meaningful for certain types. */ + unsigned int unsigned_p : 1; + + /* Unused; available for future use. */ + unsigned int unused : 7; + + /* The mode passed to the convert_*_operand function. It has a + type-dependent meaning. */ + ENUM_BITFIELD (machine_mode) mode : 16; + + /* The value of the operand. */ + rtx value; +}; + +/* Initialize OP with the given fields. Initialise the other fields + to their default values. */ + +static inline void +create_expand_operand (struct expand_operand *op, + enum expand_operand_type type, + rtx value, enum machine_mode mode, + bool unsigned_p) +{ + op->type = type; + op->unsigned_p = unsigned_p; + op->unused = 0; + op->mode = mode; + op->value = value; +} + +/* Make OP describe an operand that must use rtx X, even if X is volatile. */ + +static inline void +create_fixed_operand (struct expand_operand *op, rtx x) +{ + create_expand_operand (op, EXPAND_FIXED, x, VOIDmode, false); +} + +/* Make OP describe an output operand that must have mode MODE. + X, if nonnull, is a suggestion for where the output should be stored. + It is OK for VALUE to be inconsistent with MODE, although it will just + be ignored in that case. */ + +static inline void +create_output_operand (struct expand_operand *op, rtx x, + enum machine_mode mode) +{ + create_expand_operand (op, EXPAND_OUTPUT, x, mode, false); +} + +/* Make OP describe an input operand that must have mode MODE and + value VALUE; MODE cannot be VOIDmode. The backend may request that + VALUE be copied into a different kind of rtx before being passed + as an operand. */ + +static inline void +create_input_operand (struct expand_operand *op, rtx value, + enum machine_mode mode) +{ + create_expand_operand (op, EXPAND_INPUT, value, mode, false); +} + +/* Like create_input_operand, except that VALUE must first be converted + to mode MODE. UNSIGNED_P says whether VALUE is unsigned. */ + +static inline void +create_convert_operand_to (struct expand_operand *op, rtx value, + enum machine_mode mode, bool unsigned_p) +{ + create_expand_operand (op, EXPAND_CONVERT_TO, value, mode, unsigned_p); +} + +/* Make OP describe an input operand that should have the same value + as VALUE, after any mode conversion that the backend might request. + If VALUE is a CONST_INT, it should be treated as having mode MODE. + UNSIGNED_P says whether VALUE is unsigned. */ + +static inline void +create_convert_operand_from (struct expand_operand *op, rtx value, + enum machine_mode mode, bool unsigned_p) +{ + create_expand_operand (op, EXPAND_CONVERT_FROM, value, mode, unsigned_p); +} + +extern void create_convert_operand_from_type (struct expand_operand *op, + rtx value, tree type); + +/* Make OP describe an input Pmode address operand. VALUE is the value + of the address, but it may need to be converted to Pmode first. */ + +static inline void +create_address_operand (struct expand_operand *op, rtx value) +{ + create_expand_operand (op, EXPAND_ADDRESS, value, Pmode, false); +} + +/* Make OP describe an input operand that has value INTVAL and that has + no inherent mode. This function should only be used for operands that + are always expand-time constants. The backend may request that INTVAL + be copied into a different kind of rtx, but it must specify the mode + of that rtx if so. */ + +static inline void +create_integer_operand (struct expand_operand *op, HOST_WIDE_INT intval) +{ + create_expand_operand (op, EXPAND_INTEGER, GEN_INT (intval), VOIDmode, false); +} + +extern bool maybe_legitimize_operands (enum insn_code icode, + unsigned int opno, unsigned int nops, + struct expand_operand *ops); +extern rtx maybe_gen_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops); +extern bool maybe_expand_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops); +extern bool maybe_expand_jump_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops); +extern void expand_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops); +extern void expand_jump_insn (enum insn_code icode, unsigned int nops, + struct expand_operand *ops); + extern rtx prepare_operand (enum insn_code, rtx, int, enum machine_mode, enum machine_mode, int); -- 2.30.2