X-Git-Url: https://gcc.gnu.org/git/?a=blobdiff_plain;f=gcc%2Foptabs.c;h=5d80241969bc36e42e6ea91dc0b2a216537548d7;hb=a157febd0ca69d5b4570fc714c141fd5da555a7a;hp=2b9091bcf4e05c0f59aa876dd8db646f7310a484;hpb=a59a536cdd718929962efd43f1391f567e909718;p=gcc.git diff --git a/gcc/optabs.c b/gcc/optabs.c index 2b9091bcf4e0..5d80241969bc 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -28,12 +28,15 @@ Boston, MA 02111-1307, USA. */ #include "insn-config.h" #include "rtl.h" #include "tree.h" +#include "tm_p.h" #include "flags.h" #include "insn-flags.h" #include "insn-codes.h" +#include "function.h" #include "expr.h" #include "recog.h" #include "reload.h" +#include "ggc.h" /* Each optab contains info on how this target machine can perform a particular operation @@ -44,50 +47,9 @@ Boston, MA 02111-1307, USA. */ See expr.h for documentation of these optabs. */ -optab add_optab; -optab sub_optab; -optab smul_optab; -optab smul_highpart_optab; -optab umul_highpart_optab; -optab smul_widen_optab; -optab umul_widen_optab; -optab sdiv_optab; -optab sdivmod_optab; -optab udiv_optab; -optab udivmod_optab; -optab smod_optab; -optab umod_optab; -optab flodiv_optab; -optab ftrunc_optab; -optab and_optab; -optab ior_optab; -optab xor_optab; -optab ashl_optab; -optab lshr_optab; -optab ashr_optab; -optab rotl_optab; -optab rotr_optab; -optab smin_optab; -optab smax_optab; -optab umin_optab; -optab umax_optab; - -optab mov_optab; -optab movstrict_optab; - -optab neg_optab; -optab abs_optab; -optab one_cmpl_optab; -optab ffs_optab; -optab sqrt_optab; -optab sin_optab; -optab cos_optab; - -optab cmp_optab; -optab ucmp_optab; /* Used only for libcalls for unsigned comparisons. */ -optab tst_optab; - -optab strlen_optab; +optab optab_table[OTI_MAX]; + +rtx libfunc_table[LTI_MAX]; /* Tables of patterns for extending one integer mode to another. */ enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2]; @@ -100,129 +62,6 @@ enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; /* Contains the optab used for each rtx code. */ optab code_to_optab[NUM_RTX_CODE + 1]; -/* SYMBOL_REF rtx's for the library functions that are called - implicitly and not via optabs. */ - -rtx extendsfdf2_libfunc; -rtx extendsfxf2_libfunc; -rtx extendsftf2_libfunc; -rtx extenddfxf2_libfunc; -rtx extenddftf2_libfunc; - -rtx truncdfsf2_libfunc; -rtx truncxfsf2_libfunc; -rtx trunctfsf2_libfunc; -rtx truncxfdf2_libfunc; -rtx trunctfdf2_libfunc; - -rtx memcpy_libfunc; -rtx bcopy_libfunc; -rtx memcmp_libfunc; -rtx bcmp_libfunc; -rtx memset_libfunc; -rtx bzero_libfunc; - -rtx throw_libfunc; -rtx rethrow_libfunc; -rtx sjthrow_libfunc; -rtx sjpopnthrow_libfunc; -rtx terminate_libfunc; -rtx setjmp_libfunc; -rtx longjmp_libfunc; -rtx eh_rtime_match_libfunc; - -rtx eqhf2_libfunc; -rtx nehf2_libfunc; -rtx gthf2_libfunc; -rtx gehf2_libfunc; -rtx lthf2_libfunc; -rtx lehf2_libfunc; - -rtx eqsf2_libfunc; -rtx nesf2_libfunc; -rtx gtsf2_libfunc; -rtx gesf2_libfunc; -rtx ltsf2_libfunc; -rtx lesf2_libfunc; - -rtx eqdf2_libfunc; -rtx nedf2_libfunc; -rtx gtdf2_libfunc; -rtx gedf2_libfunc; -rtx ltdf2_libfunc; -rtx ledf2_libfunc; - -rtx eqxf2_libfunc; -rtx nexf2_libfunc; -rtx gtxf2_libfunc; -rtx gexf2_libfunc; -rtx ltxf2_libfunc; -rtx lexf2_libfunc; - -rtx eqtf2_libfunc; -rtx netf2_libfunc; -rtx gttf2_libfunc; -rtx getf2_libfunc; -rtx lttf2_libfunc; -rtx letf2_libfunc; - -rtx floatsisf_libfunc; -rtx floatdisf_libfunc; -rtx floattisf_libfunc; - -rtx floatsidf_libfunc; -rtx floatdidf_libfunc; -rtx floattidf_libfunc; - -rtx floatsixf_libfunc; -rtx floatdixf_libfunc; -rtx floattixf_libfunc; - -rtx floatsitf_libfunc; -rtx floatditf_libfunc; -rtx floattitf_libfunc; - -rtx fixsfsi_libfunc; -rtx fixsfdi_libfunc; -rtx fixsfti_libfunc; - -rtx fixdfsi_libfunc; -rtx fixdfdi_libfunc; -rtx fixdfti_libfunc; - -rtx fixxfsi_libfunc; -rtx fixxfdi_libfunc; -rtx fixxfti_libfunc; - -rtx fixtfsi_libfunc; -rtx fixtfdi_libfunc; -rtx fixtfti_libfunc; - -rtx fixunssfsi_libfunc; -rtx fixunssfdi_libfunc; -rtx fixunssfti_libfunc; - -rtx fixunsdfsi_libfunc; -rtx fixunsdfdi_libfunc; -rtx fixunsdfti_libfunc; - -rtx fixunsxfsi_libfunc; -rtx fixunsxfdi_libfunc; -rtx fixunsxfti_libfunc; - -rtx fixunstfsi_libfunc; -rtx fixunstfdi_libfunc; -rtx fixunstfti_libfunc; - -rtx chkr_check_addr_libfunc; -rtx chkr_set_right_libfunc; -rtx chkr_copy_bitmap_libfunc; -rtx chkr_check_exec_libfunc; -rtx chkr_check_str_libfunc; - -rtx profile_function_entry_libfunc; -rtx profile_function_exit_libfunc; - /* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) gives the gen_function to make a branch to test that condition. */ @@ -266,6 +105,10 @@ static void init_floating_libfuncs PROTO((optab, const char *, int)); #ifdef HAVE_conditional_trap static void init_traps PROTO((void)); #endif +static void emit_cmp_and_jump_insn_1 PROTO((rtx, rtx, enum machine_mode, + enum rtx_code, int, rtx)); +static void prepare_float_lib_cmp PROTO((rtx *, rtx *, enum rtx_code *, + enum machine_mode *, int *)); /* Add a REG_EQUAL note to the last insn in SEQ. TARGET is being set to the result of operation CODE applied to OP0 (and OP1 if it is a binary @@ -830,8 +673,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { int icode = (int) binoptab->handlers[(int) mode].insn_code; - enum machine_mode mode0 = insn_operand_mode[icode][1]; - enum machine_mode mode1 = insn_operand_mode[icode][2]; + 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; @@ -870,15 +713,15 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) /* Now, if insn's predicates don't allow our operands, put them into pseudo regs. */ - if (! (*insn_operand_predicate[icode][1]) (xop0, mode0) + if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0) && mode0 != VOIDmode) xop0 = copy_to_mode_reg (mode0, xop0); - if (! (*insn_operand_predicate[icode][2]) (xop1, mode1) + if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1) && mode1 != VOIDmode) xop1 = copy_to_mode_reg (mode1, xop1); - if (! (*insn_operand_predicate[icode][0]) (temp, mode)) + if (! (*insn_data[icode].operand[0].predicate) (temp, mode)) temp = gen_reg_rtx (mode); pat = GEN_FCN (icode) (temp, xop0, xop1); @@ -1325,7 +1168,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) carry_out = gen_reg_rtx (word_mode); carry_out = emit_store_flag_force (carry_out, (binoptab == add_optab - ? LTU : GTU), + ? LT : GT), x, op0_piece, word_mode, 1, normalizep); } @@ -1348,7 +1191,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) /* Get out carry from adding/subtracting carry in. */ carry_tmp = emit_store_flag_force (carry_tmp, binoptab == add_optab - ? LTU : GTU, + ? LT : GT, x, carry_in, word_mode, 1, normalizep); @@ -1376,8 +1219,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) copy_rtx (xop0), copy_rtx (xop1))); } + return target; } + else delete_insns_since (last); } @@ -1558,6 +1403,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) copy_rtx (op0), copy_rtx (op1))); } + return product; } } @@ -2049,8 +1895,8 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp) if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { int icode = (int) binoptab->handlers[(int) mode].insn_code; - enum machine_mode mode0 = insn_operand_mode[icode][1]; - enum machine_mode mode1 = insn_operand_mode[icode][2]; + 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; @@ -2063,16 +1909,16 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp) xop1 = convert_to_mode (mode1, xop1, unsignedp); /* Now, if insn doesn't accept these operands, put them into pseudos. */ - if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) + if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) xop0 = copy_to_mode_reg (mode0, xop0); - if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)) + 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. */ - if (! (*insn_operand_predicate[icode][0]) (targ0, mode) - || ! (*insn_operand_predicate[icode][3]) (targ1, mode)) + if (! (*insn_data[icode].operand[0].predicate) (targ0, mode) + || ! (*insn_data[icode].operand[3].predicate) (targ1, mode)) abort (); pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1); @@ -2159,7 +2005,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp) if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { int icode = (int) unoptab->handlers[(int) mode].insn_code; - enum machine_mode mode0 = insn_operand_mode[icode][1]; + enum machine_mode mode0 = insn_data[icode].operand[1].mode; rtx xop0 = op0; if (target) @@ -2173,10 +2019,10 @@ expand_unop (mode, unoptab, op0, target, unsignedp) /* Now, if insn doesn't accept our operand, put it into a pseudo. */ - if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) + if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) xop0 = copy_to_mode_reg (mode0, xop0); - if (! (*insn_operand_predicate[icode][0]) (temp, mode)) + if (! (*insn_data[icode].operand[0].predicate) (temp, mode)) temp = gen_reg_rtx (mode); pat = GEN_FCN (icode) (temp, xop0); @@ -2417,10 +2263,29 @@ expand_abs (mode, op0, target, safe) if (temp != 0) return temp; + /* If we have a MAX insn, we can do this as MAX (x, -x). */ + if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) + { + rtx last = get_last_insn (); + + temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0); + if (temp != 0) + temp = expand_binop (mode, smax_optab, op0, temp, target, 0, + OPTAB_WIDEN); + + if (temp != 0) + return temp; + + delete_insns_since (last); + } + /* If this machine has expensive jumps, we can do integer absolute value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)), - where W is the width of MODE. */ + where W is the width of MODE. But don't do this if the machine has + conditional arithmetic since the branches will be converted into + a conditional negation insn. */ +#ifndef HAVE_conditional_arithmetic if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2) { rtx extended = expand_shift (RSHIFT_EXPR, mode, op0, @@ -2436,6 +2301,7 @@ expand_abs (mode, op0, target, safe) if (temp != 0) return temp; } +#endif /* If that does not win, use conditional jump and negate. */ @@ -2458,23 +2324,12 @@ expand_abs (mode, op0, target, safe) /* If this mode is an integer too wide to compare properly, compare word by word. Rely on CSE to optimize constant cases. */ - if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode)) + if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode, ccp_jump)) do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, NULL_RTX, op1); else - { - temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode, - NULL_RTX, 0); - if (temp == const1_rtx) - return target; - else if (temp != const0_rtx) - { - if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0) - emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1)); - else - abort (); - } - } + do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode, + NULL_RTX, 0, NULL_RTX, op1); op0 = expand_unop (mode, neg_optab, target, target, 0); if (op0 != target) @@ -2531,7 +2386,7 @@ expand_complex_abs (mode, op0, target, unsignedp) if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { int icode = (int) abs_optab->handlers[(int) mode].insn_code; - enum machine_mode mode0 = insn_operand_mode[icode][1]; + enum machine_mode mode0 = insn_data[icode].operand[1].mode; rtx xop0 = op0; if (target) @@ -2545,10 +2400,10 @@ expand_complex_abs (mode, op0, target, unsignedp) /* Now, if insn doesn't accept our operand, put it into a pseudo. */ - if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) + if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)) xop0 = copy_to_mode_reg (mode0, xop0); - if (! (*insn_operand_predicate[icode][0]) (temp, submode)) + if (! (*insn_data[icode].operand[0].predicate) (temp, submode)) temp = gen_reg_rtx (submode); pat = GEN_FCN (icode) (temp, xop0); @@ -2695,7 +2550,7 @@ emit_unop_insn (icode, target, op0, code) enum rtx_code code; { register rtx temp; - enum machine_mode mode0 = insn_operand_mode[icode][1]; + enum machine_mode mode0 = insn_data[icode].operand[1].mode; rtx pat; temp = target = protect_from_queue (target, 1); @@ -2710,10 +2565,10 @@ emit_unop_insn (icode, target, op0, code) /* Now, if insn does not accept our operands, put them into pseudos. */ - if (! (*insn_operand_predicate[icode][1]) (op0, mode0)) + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) op0 = copy_to_mode_reg (mode0, op0); - if (! (*insn_operand_predicate[icode][0]) (temp, GET_MODE (temp)) + if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp)) || (flag_force_mem && GET_CODE (temp) == MEM)) temp = gen_reg_rtx (GET_MODE (temp)); @@ -2782,7 +2637,8 @@ emit_no_conflict_block (insns, target, op0, op1, equiv) next = NEXT_INSN (insn); - if (GET_CODE (PATTERN (insn)) == SET) + if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE + || GET_CODE (PATTERN (insn)) == CLOBBER) set = PATTERN (insn); else if (GET_CODE (PATTERN (insn)) == PARALLEL) { @@ -2982,31 +2838,68 @@ emit_0_to_1_insn (x) emit_move_insn (x, const1_rtx); } -/* Generate code to compare X with Y - so that the condition codes are set. +/* Nonzero if we can perform a comparison of mode MODE straightforwardly. + If FOR_JUMP is nonzero, we will be generating a jump based on this + comparison, otherwise a store-flags operation. */ + +int +can_compare_p (mode, purpose) + enum machine_mode mode; + enum can_compare_purpose purpose; +{ + do + { + if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) + return 1; + if (purpose == ccp_jump + && cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) + return 1; + if (purpose == ccp_cmov + && cmov_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) + return 1; + if (purpose == ccp_store_flag + && cstore_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) + return 1; - MODE is the mode of the inputs (in case they are const_int). - UNSIGNEDP nonzero says that X and Y are unsigned; + mode = GET_MODE_WIDER_MODE (mode); + } + while (mode != VOIDmode); + + return 0; +} + +/* This function is called when we are going to emit a compare instruction that + compares the values found in *PX and *PY, using the rtl operator COMPARISON. + + *PMODE is the mode of the inputs (in case they are const_int). + *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 X and Y, - and ALIGN specifies the known shared alignment of X and Y. + If they have mode BLKmode, then SIZE specifies the size of both operands, + and ALIGN specifies the known shared alignment of the operands. - COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). - It is ignored for fixed-point and block comparisons; - it is used only for floating-point comparisons. */ + 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 + comparison or emitting a library call to perform the comparison if no insn + is available to handle it. + The values which are passed in through pointers can be modified; the caller + should perform the comparison on the modified values. */ void -emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) - rtx x, y; - enum rtx_code comparison; +prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align, + purpose) + rtx *px, *py; + enum rtx_code *pcomparison; rtx size; - enum machine_mode mode; - int unsignedp; + enum machine_mode *pmode; + int *punsignedp; int align; + enum can_compare_purpose purpose; { + enum machine_mode mode = *pmode; + rtx x = *px, y = *py; + int unsignedp = *punsignedp; enum mode_class class; - enum machine_mode wider_mode; class = GET_MODE_CLASS (mode); @@ -3045,6 +2938,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) if (mode == BLKmode) { + rtx result; + enum machine_mode result_mode; + emit_queue (); x = protect_from_queue (x, 0); y = protect_from_queue (y, 0); @@ -3056,12 +2952,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) && GET_CODE (size) == CONST_INT && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode))) { - enum machine_mode result_mode - = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0]; - rtx result = gen_reg_rtx (result_mode); + result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode; + result = gen_reg_rtx (result_mode); emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align))); - emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX, - result_mode, 0, 0); } else #endif @@ -3070,33 +2963,25 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) && GET_CODE (size) == CONST_INT && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode))) { - enum machine_mode result_mode - = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0]; - rtx result = gen_reg_rtx (result_mode); + result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode; + result = gen_reg_rtx (result_mode); emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align))); - emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX, - result_mode, 0, 0); } else #endif #ifdef HAVE_cmpstrsi if (HAVE_cmpstrsi) { - enum machine_mode result_mode - = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0]; - rtx result = gen_reg_rtx (result_mode); + result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; + result = gen_reg_rtx (result_mode); size = protect_from_queue (size, 0); emit_insn (gen_cmpstrsi (result, x, y, convert_to_mode (SImode, size, 1), GEN_INT (align))); - emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX, - result_mode, 0, 0); } else #endif { - rtx result; - #ifdef TARGET_MEM_FUNCTIONS emit_library_call (memcmp_libfunc, 0, TYPE_MODE (integer_type_node), 3, @@ -3118,83 +3003,24 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) register so reload doesn't clobber the value if it needs the return register for a spill reg. */ result = gen_reg_rtx (TYPE_MODE (integer_type_node)); + result_mode = TYPE_MODE (integer_type_node); emit_move_insn (result, - hard_libcall_value (TYPE_MODE (integer_type_node))); - emit_cmp_insn (result, - const0_rtx, comparison, NULL_RTX, - TYPE_MODE (integer_type_node), 0, 0); + hard_libcall_value (result_mode)); } + *px = result; + *py = const0_rtx; + *pmode = result_mode; return; } - /* Handle some compares against zero. */ - - if (y == CONST0_RTX (mode) - && tst_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) - { - int icode = (int) tst_optab->handlers[(int) mode].insn_code; - - emit_queue (); - x = protect_from_queue (x, 0); - y = protect_from_queue (y, 0); - - /* Now, if insn does accept these operands, put them into pseudos. */ - if (! (*insn_operand_predicate[icode][0]) - (x, insn_operand_mode[icode][0])) - x = copy_to_mode_reg (insn_operand_mode[icode][0], x); - - emit_insn (GEN_FCN (icode) (x)); - return; - } - - /* Handle compares for which there is a directly suitable insn. */ - - if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) - { - int icode = (int) cmp_optab->handlers[(int) mode].insn_code; - - emit_queue (); - x = protect_from_queue (x, 0); - y = protect_from_queue (y, 0); - - /* Now, if insn doesn't accept these operands, put them into pseudos. */ - if (! (*insn_operand_predicate[icode][0]) - (x, insn_operand_mode[icode][0])) - x = copy_to_mode_reg (insn_operand_mode[icode][0], x); - - if (! (*insn_operand_predicate[icode][1]) - (y, insn_operand_mode[icode][1])) - y = copy_to_mode_reg (insn_operand_mode[icode][1], y); - - emit_insn (GEN_FCN (icode) (x, y)); - return; - } - - /* Try widening if we can find a direct insn that way. */ - - if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) - { - for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; - wider_mode = GET_MODE_WIDER_MODE (wider_mode)) - { - if (cmp_optab->handlers[(int) wider_mode].insn_code - != CODE_FOR_nothing) - { - x = protect_from_queue (x, 0); - y = protect_from_queue (y, 0); - x = convert_modes (wider_mode, mode, x, unsignedp); - y = convert_modes (wider_mode, mode, y, unsignedp); - emit_cmp_insn (x, y, comparison, NULL_RTX, - wider_mode, unsignedp, align); - return; - } - } - } + *px = x; + *py = y; + if (can_compare_p (mode, purpose)) + return; /* Handle a lib call just for the mode we are using. */ - if (cmp_optab->handlers[(int) mode].libfunc - && class != MODE_FLOAT) + if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT) { rtx libfunc = cmp_optab->handlers[(int) mode].libfunc; rtx result; @@ -3216,18 +3042,113 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) /* Integer comparison returns a result that must be compared against 1, so that even if we do an unsigned compare afterward, there is still a value that can represent the result "less than". */ - emit_cmp_insn (result, const1_rtx, - comparison, NULL_RTX, word_mode, unsignedp, 0); + *px = result; + *py = const1_rtx; + *pmode = word_mode; return; } if (class == MODE_FLOAT) - emit_float_lib_cmp (x, y, comparison); + prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp); else abort (); } +/* 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 + that it is accepted by the operand predicate. Return the new value. */ +rtx +prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp) + int icode; + rtx x; + int opnum; + enum machine_mode mode, wider_mode; + int unsignedp; +{ + x = protect_from_queue (x, 0); + + if (mode != wider_mode) + x = convert_modes (wider_mode, mode, x, unsignedp); + + if (! (*insn_data[icode].operand[opnum].predicate) + (x, insn_data[icode].operand[opnum].mode)) + x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x); + return x; +} + +/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know + we can do the comparison. + The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may + be NULL_RTX which indicates that only a comparison is to be generated. */ + +static void +emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label) + rtx x, y; + enum machine_mode mode; + enum rtx_code comparison; + int unsignedp; + rtx label; +{ + rtx test = gen_rtx_fmt_ee (comparison, mode, x, y); + enum mode_class class = GET_MODE_CLASS (mode); + enum machine_mode wider_mode = mode; + + /* Try combined insns first. */ + do + { + enum insn_code icode; + PUT_MODE (test, wider_mode); + + if (label) + { + icode = cbranch_optab->handlers[(int)wider_mode].insn_code; + + if (icode != CODE_FOR_nothing + && (*insn_data[icode].operand[0].predicate) (test, wider_mode)) + { + x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp); + y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp); + emit_jump_insn (GEN_FCN (icode) (test, x, y, label)); + return; + } + } + + /* Handle some compares against zero. */ + icode = (int) tst_optab->handlers[(int) wider_mode].insn_code; + if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing) + { + x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); + emit_insn (GEN_FCN (icode) (x)); + if (label) + emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label)); + return; + } + + /* Handle compares for which there is a directly suitable insn. */ + + icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code; + if (icode != CODE_FOR_nothing) + { + x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); + y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp); + emit_insn (GEN_FCN (icode) (x, y)); + if (label) + emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label)); + return; + } + + if (class != MODE_INT && class != MODE_FLOAT + && class != MODE_COMPLEX_FLOAT) + break; + + wider_mode = GET_MODE_WIDER_MODE (wider_mode); + } while (wider_mode != VOIDmode); + + abort (); +} + /* Generate code to compare X with Y so that the condition codes are set and to jump to LABEL if the condition is true. If X is a constant and Y is not a constant, then the comparison is swapped to @@ -3259,7 +3180,8 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label) rtx op0; rtx op1; - if (CONSTANT_P (x)) + if ((CONSTANT_P (x) && ! CONSTANT_P (y)) + || (GET_CODE (x) == CONST_INT && GET_CODE (y) != CONST_INT)) { /* Swap operands and condition to ensure canonical RTL. */ op0 = y; @@ -3280,39 +3202,39 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label) op0 = force_reg (mode, op0); #endif - emit_cmp_insn (op0, op1, comparison, size, mode, unsignedp, align); - + emit_queue (); if (unsignedp) comparison = unsigned_condition (comparison); - emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label)); + prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, align, + ccp_jump); + emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label); } - -/* Nonzero if a compare of mode MODE can be done straightforwardly - (without splitting it into pieces). */ - -int -can_compare_p (mode) +/* Like emit_cmp_and_jump_insns, but generate only the comparison. */ +void +emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) + rtx x, y; + enum rtx_code comparison; + rtx size; enum machine_mode mode; + int unsignedp; + int align; { - do - { - if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) - return 1; - mode = GET_MODE_WIDER_MODE (mode); - } while (mode != VOIDmode); - - return 0; + emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, 0); } /* Emit a library call comparison between floating point X and Y. COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */ -void -emit_float_lib_cmp (x, y, comparison) - rtx x, y; - enum rtx_code comparison; +static void +prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp) + rtx *px, *py; + enum rtx_code *pcomparison; + enum machine_mode *pmode; + int *punsignedp; { + enum rtx_code comparison = *pcomparison; + rtx x = *px, y = *py; enum machine_mode mode = GET_MODE (x); rtx libfunc = 0; rtx result; @@ -3480,9 +3402,9 @@ emit_float_lib_cmp (x, y, comparison) { x = protect_from_queue (x, 0); y = protect_from_queue (y, 0); - x = convert_to_mode (wider_mode, x, 0); - y = convert_to_mode (wider_mode, y, 0); - emit_float_lib_cmp (x, y, comparison); + *px = convert_to_mode (wider_mode, x, 0); + *py = convert_to_mode (wider_mode, y, 0); + prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp); return; } } @@ -3500,9 +3422,14 @@ emit_float_lib_cmp (x, y, comparison) the return register for a spill reg. */ result = gen_reg_rtx (word_mode); emit_move_insn (result, hard_libcall_value (word_mode)); - - emit_cmp_insn (result, const0_rtx, comparison, - NULL_RTX, word_mode, 0, 0); + *px = result; + *py = const0_rtx; + *pmode = word_mode; +#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL + if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison)) + *pcomparison = NE; +#endif + *punsignedp = 0; } /* Generate code to indirectly jump to a location given in the rtx LOC. */ @@ -3511,7 +3438,7 @@ void emit_indirect_jump (loc) rtx loc; { - if (! ((*insn_operand_predicate[(int)CODE_FOR_indirect_jump][0]) + if (! ((*insn_data[(int)CODE_FOR_indirect_jump].operand[0].predicate) (loc, Pmode))) loc = copy_to_mode_reg (Pmode, loc); @@ -3561,6 +3488,14 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode, code = swap_condition (code); } + /* get_condition will prefer to generate LT and GT even if the old + comparison was against zero, so undo that canonicalization here since + comparisons against zero are cheaper. */ + if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1) + code = LE, op1 = const0_rtx; + else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1) + code = GE, op1 = const0_rtx; + if (cmode == VOIDmode) cmode = GET_MODE (op0); @@ -3603,17 +3538,17 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode, /* If the insn doesn't accept these operands, put them in pseudos. */ - if (! (*insn_operand_predicate[icode][0]) - (subtarget, insn_operand_mode[icode][0])) - subtarget = gen_reg_rtx (insn_operand_mode[icode][0]); + 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_operand_predicate[icode][2]) - (op2, insn_operand_mode[icode][2])) - op2 = copy_to_mode_reg (insn_operand_mode[icode][2], op2); + 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_operand_predicate[icode][3]) - (op3, insn_operand_mode[icode][3])) - op3 = copy_to_mode_reg (insn_operand_mode[icode][3], op3); + 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, so emit the compare insn and then the conditional move. */ @@ -3675,9 +3610,12 @@ gen_add2_insn (x, y) { int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; - if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0]) - || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1]) - || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2])) + 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))) abort (); return (GEN_FCN (icode) (x, x, y)); @@ -3698,9 +3636,12 @@ gen_sub2_insn (x, y) { int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; - if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0]) - || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1]) - || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2])) + 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))) abort (); return (GEN_FCN (icode) (x, x, y)); @@ -3959,8 +3900,8 @@ expand_float (to, from, unsignedp) do_pending_stack_adjust (); /* Test whether the sign bit is set. */ - emit_cmp_insn (from, const0_rtx, GE, NULL_RTX, imode, 0, 0); - emit_jump_insn (gen_blt (neglabel)); + emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode, + 0, 0, neglabel); /* The sign bit is not set. Convert as signed. */ expand_float (target, from, 0); @@ -4250,6 +4191,7 @@ expand_fix (to, from, unsignedp) GET_MODE (to), copy_rtx (from))); } + return; } #endif @@ -4394,10 +4336,10 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix) for (mode = first_mode; (int) mode <= (int) last_mode; mode = (enum machine_mode) ((int) mode + 1)) { - register char *mname = mode_name[(int) mode]; + register const char *mname = GET_MODE_NAME(mode); register unsigned mname_len = strlen (mname); register char *libfunc_name - = (char *) xmalloc (2 + opname_len + mname_len + 1 + 1); + = ggc_alloc_string (NULL, 2 + opname_len + mname_len + 1 + 1); register char *p; register const char *q; @@ -4407,9 +4349,10 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix) for (q = opname; *q; ) *p++ = *q++; for (q = mname; *q; q++) - *p++ = tolower ((unsigned char)*q); + *p++ = TOLOWER (*q); *p++ = suffix; *p++ = '\0'; + optable->handlers[(int) mode].libfunc = gen_rtx_SYMBOL_REF (Pmode, libfunc_name); } @@ -4443,6 +4386,27 @@ init_floating_libfuncs (optable, opname, suffix) init_libfuncs (optable, SFmode, TFmode, opname, suffix); } +rtx +init_one_libfunc (name) + register const char *name; +{ + if (ggc_p) + name = ggc_alloc_string (name, -1); + return gen_rtx_SYMBOL_REF (Pmode, name); +} + +/* Mark ARG (which is really an OPTAB *) for GC. */ + +void +mark_optab (arg) + void *arg; +{ + optab o = *(optab *) arg; + int i; + + for (i = 0; i < NUM_MACHINE_MODES; ++i) + ggc_mark_rtx (o->handlers[i].libfunc); +} /* Call this once to initialize the contents of the optabs appropriately for the current target machine. */ @@ -4527,6 +4491,9 @@ init_optabs () sin_optab = init_optab (UNKNOWN); cos_optab = init_optab (UNKNOWN); strlen_optab = init_optab (UNKNOWN); + cbranch_optab = init_optab (UNKNOWN); + cmov_optab = init_optab (UNKNOWN); + cstore_optab = init_optab (UNKNOWN); for (i = 0; i < NUM_MACHINE_MODES; i++) { @@ -4549,10 +4516,6 @@ init_optabs () fixtrunctab[i][j][1] = fixtrunctab[i][j][0]; #endif -#ifdef EXTRA_CC_MODES - init_mov_optab (); -#endif - /* Initialize the optabs with the names of the library functions. */ init_integral_libfuncs (add_optab, "add", '3'); init_floating_libfuncs (add_optab, "add", '3'); @@ -4592,189 +4555,189 @@ init_optabs () #ifdef MULSI3_LIBCALL smul_optab->handlers[(int) SImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, MULSI3_LIBCALL); + = init_one_libfunc (MULSI3_LIBCALL); #endif #ifdef MULDI3_LIBCALL smul_optab->handlers[(int) DImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, MULDI3_LIBCALL); + = init_one_libfunc (MULDI3_LIBCALL); #endif #ifdef DIVSI3_LIBCALL sdiv_optab->handlers[(int) SImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, DIVSI3_LIBCALL); + = init_one_libfunc (DIVSI3_LIBCALL); #endif #ifdef DIVDI3_LIBCALL sdiv_optab->handlers[(int) DImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, DIVDI3_LIBCALL); + = init_one_libfunc (DIVDI3_LIBCALL); #endif #ifdef UDIVSI3_LIBCALL udiv_optab->handlers[(int) SImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, UDIVSI3_LIBCALL); + = init_one_libfunc (UDIVSI3_LIBCALL); #endif #ifdef UDIVDI3_LIBCALL udiv_optab->handlers[(int) DImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, UDIVDI3_LIBCALL); + = init_one_libfunc (UDIVDI3_LIBCALL); #endif #ifdef MODSI3_LIBCALL smod_optab->handlers[(int) SImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, MODSI3_LIBCALL); + = init_one_libfunc (MODSI3_LIBCALL); #endif #ifdef MODDI3_LIBCALL smod_optab->handlers[(int) DImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, MODDI3_LIBCALL); + = init_one_libfunc (MODDI3_LIBCALL); #endif #ifdef UMODSI3_LIBCALL umod_optab->handlers[(int) SImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, UMODSI3_LIBCALL); + = init_one_libfunc (UMODSI3_LIBCALL); #endif #ifdef UMODDI3_LIBCALL umod_optab->handlers[(int) DImode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, UMODDI3_LIBCALL); + = init_one_libfunc (UMODDI3_LIBCALL); #endif /* Use cabs for DC complex abs, since systems generally have cabs. Don't define any libcall for SCmode, so that cabs will be used. */ abs_optab->handlers[(int) DCmode].libfunc - = gen_rtx_SYMBOL_REF (Pmode, "cabs"); + = init_one_libfunc ("cabs"); /* The ffs function operates on `int'. */ #ifndef INT_TYPE_SIZE #define INT_TYPE_SIZE BITS_PER_WORD #endif - ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)] .libfunc - = gen_rtx_SYMBOL_REF (Pmode, "ffs"); - - extendsfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsfdf2"); - extendsfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsfxf2"); - extendsftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsftf2"); - extenddfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddfxf2"); - extenddftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddftf2"); - - truncdfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncdfsf2"); - truncxfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfsf2"); - trunctfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfsf2"); - truncxfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfdf2"); - trunctfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfdf2"); - - memcpy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcpy"); - bcopy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bcopy"); - memcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcmp"); - bcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gcc_bcmp"); - memset_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memset"); - bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero"); - - throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw"); - rethrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__rethrow"); - sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow"); - sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow"); - terminate_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__terminate"); - eh_rtime_match_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eh_rtime_match"); + ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc + = init_one_libfunc ("ffs"); + + extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2"); + extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2"); + extendsftf2_libfunc = init_one_libfunc ("__extendsftf2"); + extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2"); + extenddftf2_libfunc = init_one_libfunc ("__extenddftf2"); + + truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2"); + truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2"); + trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2"); + truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2"); + trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2"); + + memcpy_libfunc = init_one_libfunc ("memcpy"); + bcopy_libfunc = init_one_libfunc ("bcopy"); + memcmp_libfunc = init_one_libfunc ("memcmp"); + bcmp_libfunc = init_one_libfunc ("__gcc_bcmp"); + memset_libfunc = init_one_libfunc ("memset"); + bzero_libfunc = init_one_libfunc ("bzero"); + + throw_libfunc = init_one_libfunc ("__throw"); + rethrow_libfunc = init_one_libfunc ("__rethrow"); + sjthrow_libfunc = init_one_libfunc ("__sjthrow"); + sjpopnthrow_libfunc = init_one_libfunc ("__sjpopnthrow"); + terminate_libfunc = init_one_libfunc ("__terminate"); + eh_rtime_match_libfunc = init_one_libfunc ("__eh_rtime_match"); #ifndef DONT_USE_BUILTIN_SETJMP - setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__builtin_setjmp"); - longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__builtin_longjmp"); + setjmp_libfunc = init_one_libfunc ("__builtin_setjmp"); + longjmp_libfunc = init_one_libfunc ("__builtin_longjmp"); #else - setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "setjmp"); - longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "longjmp"); + setjmp_libfunc = init_one_libfunc ("setjmp"); + longjmp_libfunc = init_one_libfunc ("longjmp"); #endif - eqhf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqhf2"); - nehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nehf2"); - gthf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gthf2"); - gehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gehf2"); - lthf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lthf2"); - lehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lehf2"); - - eqsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqsf2"); - nesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nesf2"); - gtsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtsf2"); - gesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gesf2"); - ltsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltsf2"); - lesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lesf2"); - - eqdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqdf2"); - nedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nedf2"); - gtdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtdf2"); - gedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gedf2"); - ltdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltdf2"); - ledf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ledf2"); - - eqxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqxf2"); - nexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nexf2"); - gtxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtxf2"); - gexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gexf2"); - ltxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltxf2"); - lexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lexf2"); - - eqtf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqtf2"); - netf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__netf2"); - gttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gttf2"); - getf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__getf2"); - lttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lttf2"); - letf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__letf2"); - - floatsisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsisf"); - floatdisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdisf"); - floattisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattisf"); - - floatsidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsidf"); - floatdidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdidf"); - floattidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattidf"); - - floatsixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsixf"); - floatdixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdixf"); - floattixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattixf"); - - floatsitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsitf"); - floatditf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatditf"); - floattitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattitf"); - - fixsfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfsi"); - fixsfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfdi"); - fixsfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfti"); - - fixdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfsi"); - fixdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfdi"); - fixdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfti"); - - fixxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfsi"); - fixxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfdi"); - fixxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfti"); - - fixtfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfsi"); - fixtfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfdi"); - fixtfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfti"); - - fixunssfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfsi"); - fixunssfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfdi"); - fixunssfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfti"); - - fixunsdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfsi"); - fixunsdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfdi"); - fixunsdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfti"); - - fixunsxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfsi"); - fixunsxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfdi"); - fixunsxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfti"); - - fixunstfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfsi"); - fixunstfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfdi"); - fixunstfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfti"); + eqhf2_libfunc = init_one_libfunc ("__eqhf2"); + nehf2_libfunc = init_one_libfunc ("__nehf2"); + gthf2_libfunc = init_one_libfunc ("__gthf2"); + gehf2_libfunc = init_one_libfunc ("__gehf2"); + lthf2_libfunc = init_one_libfunc ("__lthf2"); + lehf2_libfunc = init_one_libfunc ("__lehf2"); + + eqsf2_libfunc = init_one_libfunc ("__eqsf2"); + nesf2_libfunc = init_one_libfunc ("__nesf2"); + gtsf2_libfunc = init_one_libfunc ("__gtsf2"); + gesf2_libfunc = init_one_libfunc ("__gesf2"); + ltsf2_libfunc = init_one_libfunc ("__ltsf2"); + lesf2_libfunc = init_one_libfunc ("__lesf2"); + + eqdf2_libfunc = init_one_libfunc ("__eqdf2"); + nedf2_libfunc = init_one_libfunc ("__nedf2"); + gtdf2_libfunc = init_one_libfunc ("__gtdf2"); + gedf2_libfunc = init_one_libfunc ("__gedf2"); + ltdf2_libfunc = init_one_libfunc ("__ltdf2"); + ledf2_libfunc = init_one_libfunc ("__ledf2"); + + eqxf2_libfunc = init_one_libfunc ("__eqxf2"); + nexf2_libfunc = init_one_libfunc ("__nexf2"); + gtxf2_libfunc = init_one_libfunc ("__gtxf2"); + gexf2_libfunc = init_one_libfunc ("__gexf2"); + ltxf2_libfunc = init_one_libfunc ("__ltxf2"); + lexf2_libfunc = init_one_libfunc ("__lexf2"); + + eqtf2_libfunc = init_one_libfunc ("__eqtf2"); + netf2_libfunc = init_one_libfunc ("__netf2"); + gttf2_libfunc = init_one_libfunc ("__gttf2"); + getf2_libfunc = init_one_libfunc ("__getf2"); + lttf2_libfunc = init_one_libfunc ("__lttf2"); + letf2_libfunc = init_one_libfunc ("__letf2"); + + floatsisf_libfunc = init_one_libfunc ("__floatsisf"); + floatdisf_libfunc = init_one_libfunc ("__floatdisf"); + floattisf_libfunc = init_one_libfunc ("__floattisf"); + + floatsidf_libfunc = init_one_libfunc ("__floatsidf"); + floatdidf_libfunc = init_one_libfunc ("__floatdidf"); + floattidf_libfunc = init_one_libfunc ("__floattidf"); + + floatsixf_libfunc = init_one_libfunc ("__floatsixf"); + floatdixf_libfunc = init_one_libfunc ("__floatdixf"); + floattixf_libfunc = init_one_libfunc ("__floattixf"); + + floatsitf_libfunc = init_one_libfunc ("__floatsitf"); + floatditf_libfunc = init_one_libfunc ("__floatditf"); + floattitf_libfunc = init_one_libfunc ("__floattitf"); + + fixsfsi_libfunc = init_one_libfunc ("__fixsfsi"); + fixsfdi_libfunc = init_one_libfunc ("__fixsfdi"); + fixsfti_libfunc = init_one_libfunc ("__fixsfti"); + + fixdfsi_libfunc = init_one_libfunc ("__fixdfsi"); + fixdfdi_libfunc = init_one_libfunc ("__fixdfdi"); + fixdfti_libfunc = init_one_libfunc ("__fixdfti"); + + fixxfsi_libfunc = init_one_libfunc ("__fixxfsi"); + fixxfdi_libfunc = init_one_libfunc ("__fixxfdi"); + fixxfti_libfunc = init_one_libfunc ("__fixxfti"); + + fixtfsi_libfunc = init_one_libfunc ("__fixtfsi"); + fixtfdi_libfunc = init_one_libfunc ("__fixtfdi"); + fixtfti_libfunc = init_one_libfunc ("__fixtfti"); + + fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi"); + fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi"); + fixunssfti_libfunc = init_one_libfunc ("__fixunssfti"); + + fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi"); + fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi"); + fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti"); + + fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi"); + fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi"); + fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti"); + + fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi"); + fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi"); + fixunstfti_libfunc = init_one_libfunc ("__fixunstfti"); /* For check-memory-usage. */ - chkr_check_addr_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_addr"); - chkr_set_right_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_set_right"); - chkr_copy_bitmap_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_copy_bitmap"); - chkr_check_exec_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_exec"); - chkr_check_str_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_str"); + 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 - = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_enter"); + = init_one_libfunc ("__cyg_profile_func_enter"); profile_function_exit_libfunc - = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_exit"); + = init_one_libfunc ("__cyg_profile_func_exit"); #ifdef HAVE_conditional_trap init_traps (); @@ -4784,6 +4747,10 @@ init_optabs () /* Allow the target to add more libcalls or rename some, etc. */ INIT_TARGET_OPTABS; #endif + + /* Add these GC roots. */ + ggc_add_root (optab_table, OTI_MAX, sizeof(optab), mark_optab); + ggc_add_rtx_root (libfunc_table, LTI_MAX); } #ifdef BROKEN_LDEXP @@ -4807,16 +4774,17 @@ ldexp(x,n) /* The insn generating function can not take an rtx_code argument. TRAP_RTX is used as an rtx argument. Its code is replaced with the code to be used in the trap insn and all other fields are - ignored. - - ??? Will need to change to support garbage collection. */ + ignored. */ static rtx trap_rtx; static void init_traps () { if (HAVE_conditional_trap) - trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX); + { + trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX); + ggc_add_rtx_root (&trap_rtx, 1); + } } #endif @@ -4838,11 +4806,17 @@ gen_cond_trap (code, op1, op2, tcode) && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { rtx insn; + start_sequence(); emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2)); PUT_CODE (trap_rtx, code); insn = gen_conditional_trap (trap_rtx, tcode); if (insn) - return insn; + { + emit_insn (insn); + insn = gen_sequence (); + } + end_sequence(); + return insn; } #endif