X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Foptabs.c;h=2a2ebb3a8dfb579dc3fcfccb37d00e3f7866393f;hb=76ab50f8c432c2bd5c347c2f7fd63b8fce30a494;hp=a2a42c636b162aadc44abe38cd3da370d1b40de9;hpb=09f800b9baea8ff279f12fc8dd31e75620156cd4;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/optabs.c b/gcc/optabs.c index a2a42c636b1..2a2ebb3a8df 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -2,22 +2,22 @@ Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #include "config.h" @@ -25,7 +25,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" /* Include insn-config.h before expr.h so that HAVE_conditional_move - is properly defined. */ + is properly defined. */ #include "insn-config.h" #include "rtl.h" #include "tree.h" @@ -34,6 +34,8 @@ Boston, MA 02111-1307, USA. */ #include "function.h" #include "except.h" #include "expr.h" +#include "optabs.h" +#include "libfuncs.h" #include "recog.h" #include "reload.h" #include "ggc.h" @@ -94,12 +96,18 @@ static int expand_cmplxdiv_wide PARAMS ((rtx, rtx, rtx, rtx, rtx, rtx, enum machine_mode, int, enum optab_methods, enum mode_class, optab)); +static void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx, + enum machine_mode *, int *, + enum can_compare_purpose)); static enum insn_code can_fix_p PARAMS ((enum machine_mode, enum machine_mode, int, int *)); -static enum insn_code can_float_p PARAMS ((enum machine_mode, enum machine_mode, - int)); +static enum insn_code can_float_p PARAMS ((enum machine_mode, + enum machine_mode, + int)); static rtx ftruncify PARAMS ((rtx)); -static optab init_optab PARAMS ((enum rtx_code)); +static optab new_optab PARAMS ((void)); +static inline optab init_optab PARAMS ((enum rtx_code)); +static inline optab init_optabv PARAMS ((enum rtx_code)); static void init_libfuncs PARAMS ((optab, int, int, const char *, int)); static void init_integral_libfuncs PARAMS ((optab, const char *, int)); static void init_floating_libfuncs PARAMS ((optab, const char *, int)); @@ -348,7 +356,6 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, rtx real_t, imag_t; rtx temp1, temp2, lab1, lab2; enum machine_mode mode; - int align; rtx res; optab this_add_optab = add_optab; optab this_sub_optab = sub_optab; @@ -388,10 +395,9 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, return 0; mode = GET_MODE (temp1); - align = GET_MODE_ALIGNMENT (mode); lab1 = gen_label_rtx (); emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX, - mode, unsignedp, align, lab1); + mode, unsignedp, lab1); /* |c| >= |d|; use ratio d/c to scale dividend and divisor. */ @@ -597,6 +603,25 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, return 1; } +/* Wrapper around expand_binop which takes an rtx code to specify + the operation to perform, not an optab pointer. All other + arguments are the same. */ +rtx +expand_simple_binop (mode, code, op0, op1, target, unsignedp, methods) + enum machine_mode mode; + enum rtx_code code; + rtx op0, op1; + rtx target; + int unsignedp; + enum optab_methods methods; +{ + optab binop = code_to_optab [(int) code]; + if (binop == 0) + abort (); + + return expand_binop (mode, binop, op0, op1, target, unsignedp, methods); +} + /* Generate code to perform an operation specified by BINOPTAB on operands OP0 and OP1, with result having machine-mode MODE. @@ -622,7 +647,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) ? OPTAB_WIDEN : methods); enum mode_class class; enum machine_mode wider_mode; - register rtx temp; + rtx temp; int commutative_op = 0; int shift_op = (binoptab->code == ASHIFT || binoptab->code == ASHIFTRT @@ -715,7 +740,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1 && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0) { - register rtx tmp; + rtx tmp; tmp = op0; op0 = op1; op1 = tmp; tmp = xop0; xop0 = xop1; xop1 = tmp; @@ -830,7 +855,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) /* For certain integer operations, we need not actually extend the narrow operands, as long as we will truncate - the results to the same narrowness. */ + the results to the same narrowness. */ if ((binoptab == ior_optab || binoptab == and_optab || binoptab == xor_optab @@ -870,7 +895,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) && GET_MODE_SIZE (mode) > UNITS_PER_WORD && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) { - unsigned int i; + int i; rtx insns; rtx equiv_value; @@ -1161,8 +1186,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) { - unsigned int i; - rtx carry_tmp = gen_reg_rtx (word_mode); + int i; optab otheroptab = binoptab == add_optab ? sub_optab : add_optab; unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; rtx carry_in = NULL_RTX, carry_out = NULL_RTX; @@ -1218,24 +1242,22 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) if (i > 0) { + rtx newx; + /* Add/subtract previous carry to main result. */ - x = expand_binop (word_mode, - normalizep == 1 ? binoptab : otheroptab, - x, carry_in, - target_piece, 1, next_methods); - if (x == 0) - break; - else if (target_piece != x) - emit_move_insn (target_piece, x); + newx = expand_binop (word_mode, + normalizep == 1 ? binoptab : otheroptab, + x, carry_in, + NULL_RTX, 1, next_methods); if (i + 1 < nwords) { - /* THIS CODE HAS NOT BEEN TESTED. */ /* Get out carry from adding/subtracting carry in. */ + rtx carry_tmp = gen_reg_rtx (word_mode); carry_tmp = emit_store_flag_force (carry_tmp, - binoptab == add_optab - ? LT : GT, - x, carry_in, + (binoptab == add_optab + ? LT : GT), + newx, x, word_mode, 1, normalizep); /* Logical-ior the two poss. carry together. */ @@ -1245,6 +1267,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) if (carry_out == 0) break; } + emit_move_insn (target_piece, newx); } carry_in = carry_out; @@ -1841,7 +1864,7 @@ sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods) int unsignedp; enum optab_methods methods; { - register rtx temp; + rtx temp; optab direct_optab = unsignedp ? uoptab : soptab; struct optab wide_soptab; @@ -1990,14 +2013,12 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp) if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) { - register rtx t0 = gen_reg_rtx (wider_mode); - register rtx t1 = gen_reg_rtx (wider_mode); - - if (expand_twoval_binop (binoptab, - convert_modes (wider_mode, mode, op0, - unsignedp), - convert_modes (wider_mode, mode, op1, - unsignedp), + rtx t0 = gen_reg_rtx (wider_mode); + rtx t1 = gen_reg_rtx (wider_mode); + rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp); + rtx cop1 = convert_modes (wider_mode, mode, op1, unsignedp); + + if (expand_twoval_binop (binoptab, cop0, cop1, t0, t1, unsignedp)) { convert_move (targ0, t0, unsignedp); @@ -2014,6 +2035,24 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp) return 0; } +/* Wrapper around expand_unop which takes an rtx code to specify + the operation to perform, not an optab pointer. All other + arguments are the same. */ +rtx +expand_simple_unop (mode, code, op0, target, unsignedp) + enum machine_mode mode; + enum rtx_code code; + rtx op0; + rtx target; + int unsignedp; +{ + optab unop = code_to_optab [(int) code]; + if (unop == 0) + abort (); + + return expand_unop (mode, unop, op0, target, unsignedp); +} + /* Generate code to perform an operation specified by UNOPTAB on operand OP0, with result having machine-mode MODE. @@ -2035,7 +2074,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp) { enum mode_class class; enum machine_mode wider_mode; - register rtx temp; + rtx temp; rtx last = get_last_insn (); rtx pat; @@ -2137,7 +2176,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp) && GET_MODE_SIZE (mode) > UNITS_PER_WORD && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) { - unsigned int i; + int i; rtx insns; if (target == 0 || target == op0) @@ -2152,6 +2191,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp) rtx x = expand_unop (word_mode, unoptab, operand_subword_force (op0, i, mode), target_piece, unsignedp); + if (target_piece != x) emit_move_insn (target_piece, x); } @@ -2382,7 +2422,7 @@ expand_abs (mode, op0, target, result_unsignedp, safe) NULL_RTX, op1); else do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode, - NULL_RTX, 0, NULL_RTX, op1); + NULL_RTX, NULL_RTX, op1); op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab, target, target, 0); @@ -2411,7 +2451,7 @@ expand_complex_abs (mode, op0, target, unsignedp) { enum mode_class class = GET_MODE_CLASS (mode); enum machine_mode wider_mode; - register rtx temp; + rtx temp; rtx entry_last = get_last_insn (); rtx last; rtx pat; @@ -2612,7 +2652,7 @@ emit_unop_insn (icode, target, op0, code) rtx op0; enum rtx_code code; { - register rtx temp; + rtx temp; enum machine_mode mode0 = insn_data[icode].operand[1].mode; rtx pat; @@ -2822,23 +2862,36 @@ emit_libcall_block (insns, target, result, equiv) into a MEM later. Protect the libcall block from this change. */ if (! REG_P (target) || REG_USERVAR_P (target)) target = gen_reg_rtx (GET_MODE (target)); - + + /* If we're using non-call exceptions, a libcall corresponding to an + operation that may trap may also trap. */ + if (flag_non_call_exceptions && may_trap_p (equiv)) + { + for (insn = insns; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == CALL_INSN) + { + rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); + + if (note != 0 && INTVAL (XEXP (note, 0)) <= 0) + remove_note (insn, note); + } + } + else /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION reg note to indicate that this call cannot throw or execute a nonlocal goto (unless there is already a REG_EH_REGION note, in which case we update it). */ - - for (insn = insns; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN) - { - rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); - - if (note != 0) - XEXP (note, 0) = GEN_INT (-1); - else - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1), - REG_NOTES (insn)); - } + for (insn = insns; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == CALL_INSN) + { + rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); + + if (note != 0) + XEXP (note, 0) = GEN_INT (-1); + else + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1), + REG_NOTES (insn)); + } /* First emit all insns that set pseudos. Remove them from the list as we go. Avoid insns that set pseudos which were referenced in previous @@ -2907,9 +2960,13 @@ emit_libcall_block (insns, target, result, equiv) first = NEXT_INSN (prev); /* Encapsulate the block so it gets manipulated as a unit. */ - REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, - REG_NOTES (first)); - REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last)); + if (!flag_non_call_exceptions || !may_trap_p (equiv)) + { + REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, + REG_NOTES (first)); + REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, + REG_NOTES (last)); + } } /* Generate code to store zero in X. */ @@ -2981,8 +3038,7 @@ can_compare_p (code, mode, purpose) *PUNSIGNEDP nonzero says that the operands are unsigned; this matters if they need to be widened. - If they have mode BLKmode, then SIZE specifies the size of both operands, - and ALIGN specifies the known shared alignment of the operands. + If they have mode BLKmode, then SIZE specifies the size of both operands. This function performs all the setup necessary so that the caller only has to emit a single comparison insn. This setup can involve doing a BLKmode @@ -2991,22 +3047,19 @@ can_compare_p (code, mode, purpose) The values which are passed in through pointers can be modified; the caller should perform the comparison on the modified values. */ -void -prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align, - purpose) +static void +prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose) rtx *px, *py; enum rtx_code *pcomparison; rtx size; enum machine_mode *pmode; int *punsignedp; - int align ATTRIBUTE_UNUSED; enum can_compare_purpose purpose; { enum machine_mode mode = *pmode; rtx x = *px, y = *py; int unsignedp = *punsignedp; enum mode_class class; - rtx opalign ATTRIBUTE_UNUSED = GEN_INT (align / BITS_PER_UNIT);; class = GET_MODE_CLASS (mode); @@ -3049,6 +3102,8 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align, { rtx result; enum machine_mode result_mode; + rtx opalign ATTRIBUTE_UNUSED + = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT); emit_queue (); x = protect_from_queue (x, 0); @@ -3139,8 +3194,8 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align, if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc) libfunc = ucmp_optab->handlers[(int) mode].libfunc; - emit_library_call (libfunc, 1, - word_mode, 2, x, mode, y, mode); + emit_library_call (libfunc, LCT_CONST_MAKE_BLOCK, word_mode, 2, x, mode, + y, mode); /* Immediately move the result of the libcall into a pseudo register so reload doesn't clobber the value if it needs @@ -3166,7 +3221,7 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align, /* Before emitting an insn with code ICODE, make sure that X, which is going to be used for operand OPNUM of the insn, is converted from mode MODE to - WIDER_MODE (UNSIGNEDP determines whether it is a unsigned conversion), and + WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and that it is accepted by the operand predicate. Return the new value. */ rtx @@ -3268,8 +3323,7 @@ emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label) need to be widened by emit_cmp_insn. UNSIGNEDP is also used to select the proper branch condition code. - If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y, - and ALIGN specifies the known shared alignment of X and Y. + If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y. MODE is the mode of the inputs (in case they are const_int). @@ -3278,30 +3332,27 @@ emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label) unsigned variant based on UNSIGNEDP to select a proper jump instruction. */ void -emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label) +emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label) rtx x, y; enum rtx_code comparison; rtx size; enum machine_mode mode; int unsignedp; - unsigned int align; rtx label; { - rtx op0; - rtx op1; - + rtx op0 = x, op1 = y; + + /* Swap operands and condition to ensure canonical RTL. */ if (swap_commutative_operands_p (x, y)) { - /* Swap operands and condition to ensure canonical RTL. */ - op0 = y; - op1 = x; + /* If we're not emitting a branch, this means some caller + is out of sync. */ + if (! label) + abort (); + + op0 = y, op1 = x; comparison = swap_condition (comparison); } - else - { - op0 = x; - op1 = y; - } #ifdef HAVE_cc0 /* If OP0 is still a constant, then both X and Y must be constants. Force @@ -3314,7 +3365,8 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label) emit_queue (); if (unsignedp) comparison = unsigned_condition (comparison); - prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, align, + + prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, ccp_jump); emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label); } @@ -3322,15 +3374,14 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label) /* Like emit_cmp_and_jump_insns, but generate only the comparison. */ void -emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) +emit_cmp_insn (x, y, comparison, size, mode, unsignedp) rtx x, y; enum rtx_code comparison; rtx size; enum machine_mode mode; int unsignedp; - unsigned int align; { - emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, 0); + emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0); } /* Emit a library call comparison between floating point X and Y. @@ -3686,7 +3737,7 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode, and then the conditional move. */ comparison - = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX, 0); + = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX); /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */ /* We can get const0_rtx or const_true_rtx in some circumstances. Just @@ -3729,7 +3780,7 @@ can_conditionally_move_p (mode) #endif /* HAVE_conditional_move */ -/* These three functions generate an insn body and return it +/* These functions generate an insn body and return it rather than emitting the insn. They do not protect from queued increments, @@ -3755,11 +3806,49 @@ gen_add2_insn (x, y) return (GEN_FCN (icode) (x, x, y)); } +/* Generate and return an insn body to add r1 and c, + storing the result in r0. */ +rtx +gen_add3_insn (r0, r1, c) + rtx r0, r1, c; +{ + int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code; + + if (icode == CODE_FOR_nothing + || ! ((*insn_data[icode].operand[0].predicate) + (r0, insn_data[icode].operand[0].mode)) + || ! ((*insn_data[icode].operand[1].predicate) + (r1, insn_data[icode].operand[1].mode)) + || ! ((*insn_data[icode].operand[2].predicate) + (c, insn_data[icode].operand[2].mode))) + return NULL_RTX; + + return (GEN_FCN (icode) (r0, r1, c)); +} + int -have_add2_insn (mode) - enum machine_mode mode; +have_add2_insn (x, y) + rtx x, y; { - return add_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing; + int icode; + + if (GET_MODE (x) == VOIDmode) + abort (); + + icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; + + if (icode == CODE_FOR_nothing) + return 0; + + if (! ((*insn_data[icode].operand[0].predicate) + (x, insn_data[icode].operand[0].mode)) + || ! ((*insn_data[icode].operand[1].predicate) + (x, insn_data[icode].operand[1].mode)) + || ! ((*insn_data[icode].operand[2].predicate) + (y, insn_data[icode].operand[2].mode))) + return 0; + + return 1; } /* Generate and return an insn body to subtract Y from X. */ @@ -3781,11 +3870,49 @@ gen_sub2_insn (x, y) return (GEN_FCN (icode) (x, x, y)); } +/* Generate and return an insn body to subtract r1 and c, + storing the result in r0. */ +rtx +gen_sub3_insn (r0, r1, c) + rtx r0, r1, c; +{ + int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code; + + if (icode == CODE_FOR_nothing + || ! ((*insn_data[icode].operand[0].predicate) + (r0, insn_data[icode].operand[0].mode)) + || ! ((*insn_data[icode].operand[1].predicate) + (r1, insn_data[icode].operand[1].mode)) + || ! ((*insn_data[icode].operand[2].predicate) + (c, insn_data[icode].operand[2].mode))) + return NULL_RTX; + + return (GEN_FCN (icode) (r0, r1, c)); +} + int -have_sub2_insn (mode) - enum machine_mode mode; +have_sub2_insn (x, y) + rtx x, y; { - return sub_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing; + int icode; + + if (GET_MODE (x) == VOIDmode) + abort (); + + icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; + + if (icode == CODE_FOR_nothing) + return 0; + + if (! ((*insn_data[icode].operand[0].predicate) + (x, insn_data[icode].operand[0].mode)) + || ! ((*insn_data[icode].operand[1].predicate) + (x, insn_data[icode].operand[1].mode)) + || ! ((*insn_data[icode].operand[2].predicate) + (y, insn_data[icode].operand[2].mode))) + return 0; + + return 1; } /* Generate the body of an instruction to copy Y into X. @@ -3795,7 +3922,7 @@ rtx gen_move_insn (x, y) rtx x, y; { - register enum machine_mode mode = GET_MODE (x); + enum machine_mode mode = GET_MODE (x); enum insn_code insn_code; rtx seq; @@ -3837,16 +3964,14 @@ gen_move_insn (x, y) x = gen_lowpart_common (tmode, x1); if (x == 0 && GET_CODE (x1) == MEM) { - x = gen_rtx_MEM (tmode, XEXP (x1, 0)); - MEM_COPY_ATTRIBUTES (x, x1); + x = adjust_address_nv (x1, tmode, 0); copy_replacements (x1, x); } y = gen_lowpart_common (tmode, y1); if (y == 0 && GET_CODE (y1) == MEM) { - y = gen_rtx_MEM (tmode, XEXP (y1, 0)); - MEM_COPY_ATTRIBUTES (y, y1); + y = adjust_address_nv (y1, tmode, 0); copy_replacements (y1, y); } } @@ -3876,7 +4001,12 @@ can_extend_p (to_mode, from_mode, unsignedp) enum machine_mode to_mode, from_mode; int unsignedp; { - return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0]; +#ifdef HAVE_ptr_extend + if (unsignedp < 0) + return CODE_FOR_ptr_extend; + else +#endif + return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0]; } /* Generate the body of an insn to extend Y (with mode MFROM) @@ -3939,7 +4069,7 @@ expand_float (to, from, unsignedp) int unsignedp; { enum insn_code icode; - register rtx target = to; + rtx target = to; enum machine_mode fmode, imode; /* Crash now, because we won't be able to decide which mode to use. */ @@ -4038,7 +4168,7 @@ expand_float (to, from, unsignedp) /* Test whether the sign bit is set. */ emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode, - 0, 0, neglabel); + 0, neglabel); /* The sign bit is not set. Convert as signed. */ expand_float (target, from, 0); @@ -4086,7 +4216,7 @@ expand_float (to, from, unsignedp) do_pending_stack_adjust (); emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), - 0, 0, label); + 0, label); /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1). Rather than setting up a dconst_dot_5, let's hope SCO @@ -4206,11 +4336,11 @@ ftruncify (x) void expand_fix (to, from, unsignedp) - register rtx to, from; + rtx to, from; int unsignedp; { enum insn_code icode; - register rtx target = to; + rtx target = to; enum machine_mode fmode, imode; int must_trunc = 0; rtx libfcn = 0; @@ -4220,10 +4350,10 @@ expand_fix (to, from, unsignedp) this conversion. If the integer mode is wider than the mode of TO, we can do the conversion either signed or unsigned. */ - for (imode = GET_MODE (to); imode != VOIDmode; - imode = GET_MODE_WIDER_MODE (imode)) - for (fmode = GET_MODE (from); fmode != VOIDmode; - fmode = GET_MODE_WIDER_MODE (fmode)) + for (fmode = GET_MODE (from); fmode != VOIDmode; + fmode = GET_MODE_WIDER_MODE (fmode)) + for (imode = GET_MODE (to); imode != VOIDmode; + imode = GET_MODE_WIDER_MODE (imode)) { int doing_unsigned = unsignedp; @@ -4294,7 +4424,7 @@ expand_fix (to, from, unsignedp) /* See if we need to do the subtraction. */ do_pending_stack_adjust (); emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from), - 0, 0, lab1); + 0, lab1); /* If not, do the signed "fix" and branch around fixup code. */ expand_fix (to, from, 0); @@ -4425,22 +4555,53 @@ expand_fix (to, from, unsignedp) } } -static optab -init_optab (code) +/* Report whether we have an instruction to perform the operation + specified by CODE on operands of mode MODE. */ +int +have_insn_for (code, mode) enum rtx_code code; + enum machine_mode mode; +{ + return (code_to_optab[(int) code] != 0 + && (code_to_optab[(int) code]->handlers[(int) mode].insn_code + != CODE_FOR_nothing)); +} + +/* Create a blank optab. */ +static optab +new_optab () { int i; optab op = (optab) xmalloc (sizeof (struct optab)); - op->code = code; for (i = 0; i < NUM_MACHINE_MODES; i++) { op->handlers[i].insn_code = CODE_FOR_nothing; op->handlers[i].libfunc = 0; } - if (code != UNKNOWN) - code_to_optab[(int) code] = op; + return op; +} + +/* Same, but fill in its code as CODE, and write it into the + code_to_optab table. */ +static inline optab +init_optab (code) + enum rtx_code code; +{ + optab op = new_optab (); + op->code = code; + code_to_optab[(int) code] = op; + return op; +} +/* Same, but fill in its code as CODE, and do _not_ write it into + the code_to_optab table. */ +static inline optab +init_optabv (code) + enum rtx_code code; +{ + optab op = new_optab (); + op->code = code; return op; } @@ -4463,23 +4624,23 @@ init_optab (code) static void init_libfuncs (optable, first_mode, last_mode, opname, suffix) - register optab optable; - register int first_mode; - register int last_mode; - register const char *opname; - register int suffix; + optab optable; + int first_mode; + int last_mode; + const char *opname; + int suffix; { - register int mode; - register unsigned opname_len = strlen (opname); + int mode; + unsigned opname_len = strlen (opname); for (mode = first_mode; (int) mode <= (int) last_mode; mode = (enum machine_mode) ((int) mode + 1)) { - register const char *mname = GET_MODE_NAME(mode); - register unsigned mname_len = strlen (mname); - register char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1); - register char *p; - register const char *q; + const char *mname = GET_MODE_NAME(mode); + unsigned mname_len = strlen (mname); + char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1); + char *p; + const char *q; p = libfunc_name; *p++ = '_'; @@ -4504,9 +4665,9 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix) static void init_integral_libfuncs (optable, opname, suffix) - register optab optable; - register const char *opname; - register int suffix; + optab optable; + const char *opname; + int suffix; { init_libfuncs (optable, SImode, TImode, opname, suffix); } @@ -4518,20 +4679,28 @@ init_integral_libfuncs (optable, opname, suffix) static void init_floating_libfuncs (optable, opname, suffix) - register optab optable; - register const char *opname; - register int suffix; + optab optable; + const char *opname; + int suffix; { init_libfuncs (optable, SFmode, TFmode, opname, suffix); } rtx init_one_libfunc (name) - register const char *name; + const char *name; { - name = ggc_strdup (name); - - return gen_rtx_SYMBOL_REF (Pmode, name); + /* Create a FUNCTION_DECL that can be passed to ENCODE_SECTION_INFO. */ + /* ??? We don't have any type information except for this is + a function. Pretend this is "int foo()". */ + tree decl = build_decl (FUNCTION_DECL, get_identifier (name), + build_function_type (integer_type_node, NULL_TREE)); + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + /* Return the symbol_ref from the mem rtx. */ + return XEXP (DECL_RTL (decl), 0); } /* Mark ARG (which is really an OPTAB *) for GC. */ @@ -4586,23 +4755,22 @@ init_optabs () #endif add_optab = init_optab (PLUS); - addv_optab = init_optab (PLUS); + addv_optab = init_optabv (PLUS); sub_optab = init_optab (MINUS); - subv_optab = init_optab (MINUS); + subv_optab = init_optabv (MINUS); smul_optab = init_optab (MULT); - smulv_optab = init_optab (MULT); + smulv_optab = init_optabv (MULT); smul_highpart_optab = init_optab (UNKNOWN); umul_highpart_optab = init_optab (UNKNOWN); smul_widen_optab = init_optab (UNKNOWN); umul_widen_optab = init_optab (UNKNOWN); sdiv_optab = init_optab (DIV); - sdivv_optab = init_optab (DIV); + sdivv_optab = init_optabv (DIV); sdivmod_optab = init_optab (UNKNOWN); udiv_optab = init_optab (UDIV); udivmod_optab = init_optab (UNKNOWN); smod_optab = init_optab (MOD); umod_optab = init_optab (UMOD); - flodiv_optab = init_optab (DIV); ftrunc_optab = init_optab (UNKNOWN); and_optab = init_optab (AND); ior_optab = init_optab (IOR); @@ -4616,15 +4784,19 @@ init_optabs () smax_optab = init_optab (SMAX); umin_optab = init_optab (UMIN); umax_optab = init_optab (UMAX); - mov_optab = init_optab (UNKNOWN); - movstrict_optab = init_optab (UNKNOWN); - cmp_optab = init_optab (UNKNOWN); + + /* These three have codes assigned exclusively for the sake of + have_insn_for. */ + mov_optab = init_optab (SET); + movstrict_optab = init_optab (STRICT_LOW_PART); + cmp_optab = init_optab (COMPARE); + ucmp_optab = init_optab (UNKNOWN); tst_optab = init_optab (UNKNOWN); neg_optab = init_optab (NEG); - negv_optab = init_optab (NEG); + negv_optab = init_optabv (NEG); abs_optab = init_optab (ABS); - absv_optab = init_optab (ABS); + absv_optab = init_optabv (ABS); one_cmpl_optab = init_optab (NOT); ffs_optab = init_optab (FFS); sqrt_optab = init_optab (SQRT); @@ -4634,6 +4806,7 @@ init_optabs () cbranch_optab = init_optab (UNKNOWN); cmov_optab = init_optab (UNKNOWN); cstore_optab = init_optab (UNKNOWN); + push_optab = init_optab (UNKNOWN); for (i = 0; i < NUM_MACHINE_MODES; i++) { @@ -4670,13 +4843,13 @@ init_optabs () init_integral_libfuncs (smulv_optab, "mulv", '3'); init_floating_libfuncs (smulv_optab, "mul", '3'); init_integral_libfuncs (sdiv_optab, "div", '3'); + init_floating_libfuncs (sdiv_optab, "div", '3'); init_integral_libfuncs (sdivv_optab, "divv", '3'); init_integral_libfuncs (udiv_optab, "udiv", '3'); init_integral_libfuncs (sdivmod_optab, "divmod", '4'); init_integral_libfuncs (udivmod_optab, "udivmod", '4'); init_integral_libfuncs (smod_optab, "mod", '3'); init_integral_libfuncs (umod_optab, "umod", '3'); - init_floating_libfuncs (flodiv_optab, "div", '3'); init_floating_libfuncs (ftrunc_optab, "ftrunc", '2'); init_integral_libfuncs (and_optab, "and", '3'); init_integral_libfuncs (ior_optab, "ior", '3'); @@ -4878,13 +5051,6 @@ init_optabs () fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi"); fixunstfti_libfunc = init_one_libfunc ("__fixunstfti"); - /* For check-memory-usage. */ - chkr_check_addr_libfunc = init_one_libfunc ("chkr_check_addr"); - chkr_set_right_libfunc = init_one_libfunc ("chkr_set_right"); - chkr_copy_bitmap_libfunc = init_one_libfunc ("chkr_copy_bitmap"); - chkr_check_exec_libfunc = init_one_libfunc ("chkr_check_exec"); - chkr_check_str_libfunc = init_one_libfunc ("chkr_check_str"); - /* For function entry/exit instrumentation. */ profile_function_entry_libfunc = init_one_libfunc ("__cyg_profile_func_enter");