optabs.c revision 52284
118334Speter/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
252284Sobrien   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
318334Speter
418334SpeterThis file is part of GNU CC.
518334Speter
618334SpeterGNU CC is free software; you can redistribute it and/or modify
718334Speterit under the terms of the GNU General Public License as published by
818334Speterthe Free Software Foundation; either version 2, or (at your option)
918334Speterany later version.
1018334Speter
1118334SpeterGNU CC is distributed in the hope that it will be useful,
1218334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1318334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1418334SpeterGNU General Public License for more details.
1518334Speter
1618334SpeterYou should have received a copy of the GNU General Public License
1718334Speteralong with GNU CC; see the file COPYING.  If not, write to
1818334Speterthe Free Software Foundation, 59 Temple Place - Suite 330,
1918334SpeterBoston, MA 02111-1307, USA.  */
2018334Speter
2118334Speter
2218334Speter#include "config.h"
2350397Sobrien#include "system.h"
2452284Sobrien#include "toplev.h"
2552284Sobrien
2652284Sobrien/* Include insn-config.h before expr.h so that HAVE_conditional_move
2752284Sobrien   is properly defined. */
2852284Sobrien#include "insn-config.h"
2918334Speter#include "rtl.h"
3018334Speter#include "tree.h"
3118334Speter#include "flags.h"
3218334Speter#include "insn-flags.h"
3318334Speter#include "insn-codes.h"
3418334Speter#include "expr.h"
3518334Speter#include "recog.h"
3618334Speter#include "reload.h"
3718334Speter
3818334Speter/* Each optab contains info on how this target machine
3918334Speter   can perform a particular operation
4018334Speter   for all sizes and kinds of operands.
4118334Speter
4218334Speter   The operation to be performed is often specified
4318334Speter   by passing one of these optabs as an argument.
4418334Speter
4518334Speter   See expr.h for documentation of these optabs.  */
4618334Speter
4718334Speteroptab add_optab;
4818334Speteroptab sub_optab;
4918334Speteroptab smul_optab;
5018334Speteroptab smul_highpart_optab;
5118334Speteroptab umul_highpart_optab;
5218334Speteroptab smul_widen_optab;
5318334Speteroptab umul_widen_optab;
5418334Speteroptab sdiv_optab;
5518334Speteroptab sdivmod_optab;
5618334Speteroptab udiv_optab;
5718334Speteroptab udivmod_optab;
5818334Speteroptab smod_optab;
5918334Speteroptab umod_optab;
6018334Speteroptab flodiv_optab;
6118334Speteroptab ftrunc_optab;
6218334Speteroptab and_optab;
6318334Speteroptab ior_optab;
6418334Speteroptab xor_optab;
6518334Speteroptab ashl_optab;
6618334Speteroptab lshr_optab;
6718334Speteroptab ashr_optab;
6818334Speteroptab rotl_optab;
6918334Speteroptab rotr_optab;
7018334Speteroptab smin_optab;
7118334Speteroptab smax_optab;
7218334Speteroptab umin_optab;
7318334Speteroptab umax_optab;
7418334Speter
7518334Speteroptab mov_optab;
7618334Speteroptab movstrict_optab;
7718334Speter
7818334Speteroptab neg_optab;
7918334Speteroptab abs_optab;
8018334Speteroptab one_cmpl_optab;
8118334Speteroptab ffs_optab;
8218334Speteroptab sqrt_optab;
8318334Speteroptab sin_optab;
8418334Speteroptab cos_optab;
8518334Speter
8618334Speteroptab cmp_optab;
8718334Speteroptab ucmp_optab;  /* Used only for libcalls for unsigned comparisons.  */
8818334Speteroptab tst_optab;
8918334Speter
9018334Speteroptab strlen_optab;
9118334Speter
9218334Speter/* Tables of patterns for extending one integer mode to another.  */
9318334Speterenum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
9418334Speter
9550397Sobrien/* Tables of patterns for converting between fixed and floating point.  */
9618334Speterenum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
9718334Speterenum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
9818334Speterenum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
9918334Speter
10018334Speter/* Contains the optab used for each rtx code.  */
10118334Speteroptab code_to_optab[NUM_RTX_CODE + 1];
10218334Speter
10318334Speter/* SYMBOL_REF rtx's for the library functions that are called
10418334Speter   implicitly and not via optabs.  */
10518334Speter
10618334Speterrtx extendsfdf2_libfunc;
10718334Speterrtx extendsfxf2_libfunc;
10818334Speterrtx extendsftf2_libfunc;
10918334Speterrtx extenddfxf2_libfunc;
11018334Speterrtx extenddftf2_libfunc;
11118334Speter
11218334Speterrtx truncdfsf2_libfunc;
11318334Speterrtx truncxfsf2_libfunc;
11418334Speterrtx trunctfsf2_libfunc;
11518334Speterrtx truncxfdf2_libfunc;
11618334Speterrtx trunctfdf2_libfunc;
11718334Speter
11818334Speterrtx memcpy_libfunc;
11918334Speterrtx bcopy_libfunc;
12018334Speterrtx memcmp_libfunc;
12118334Speterrtx bcmp_libfunc;
12218334Speterrtx memset_libfunc;
12318334Speterrtx bzero_libfunc;
12418334Speter
12550397Sobrienrtx throw_libfunc;
12652284Sobrienrtx rethrow_libfunc;
12750397Sobrienrtx sjthrow_libfunc;
12850397Sobrienrtx sjpopnthrow_libfunc;
12950397Sobrienrtx terminate_libfunc;
13050397Sobrienrtx setjmp_libfunc;
13150397Sobrienrtx longjmp_libfunc;
13252284Sobrienrtx eh_rtime_match_libfunc;
13350397Sobrien
13418334Speterrtx eqhf2_libfunc;
13518334Speterrtx nehf2_libfunc;
13618334Speterrtx gthf2_libfunc;
13718334Speterrtx gehf2_libfunc;
13818334Speterrtx lthf2_libfunc;
13918334Speterrtx lehf2_libfunc;
14018334Speter
14118334Speterrtx eqsf2_libfunc;
14218334Speterrtx nesf2_libfunc;
14318334Speterrtx gtsf2_libfunc;
14418334Speterrtx gesf2_libfunc;
14518334Speterrtx ltsf2_libfunc;
14618334Speterrtx lesf2_libfunc;
14718334Speter
14818334Speterrtx eqdf2_libfunc;
14918334Speterrtx nedf2_libfunc;
15018334Speterrtx gtdf2_libfunc;
15118334Speterrtx gedf2_libfunc;
15218334Speterrtx ltdf2_libfunc;
15318334Speterrtx ledf2_libfunc;
15418334Speter
15518334Speterrtx eqxf2_libfunc;
15618334Speterrtx nexf2_libfunc;
15718334Speterrtx gtxf2_libfunc;
15818334Speterrtx gexf2_libfunc;
15918334Speterrtx ltxf2_libfunc;
16018334Speterrtx lexf2_libfunc;
16118334Speter
16218334Speterrtx eqtf2_libfunc;
16318334Speterrtx netf2_libfunc;
16418334Speterrtx gttf2_libfunc;
16518334Speterrtx getf2_libfunc;
16618334Speterrtx lttf2_libfunc;
16718334Speterrtx letf2_libfunc;
16818334Speter
16918334Speterrtx floatsisf_libfunc;
17018334Speterrtx floatdisf_libfunc;
17118334Speterrtx floattisf_libfunc;
17218334Speter
17318334Speterrtx floatsidf_libfunc;
17418334Speterrtx floatdidf_libfunc;
17518334Speterrtx floattidf_libfunc;
17618334Speter
17718334Speterrtx floatsixf_libfunc;
17818334Speterrtx floatdixf_libfunc;
17918334Speterrtx floattixf_libfunc;
18018334Speter
18118334Speterrtx floatsitf_libfunc;
18218334Speterrtx floatditf_libfunc;
18318334Speterrtx floattitf_libfunc;
18418334Speter
18518334Speterrtx fixsfsi_libfunc;
18618334Speterrtx fixsfdi_libfunc;
18718334Speterrtx fixsfti_libfunc;
18818334Speter
18918334Speterrtx fixdfsi_libfunc;
19018334Speterrtx fixdfdi_libfunc;
19118334Speterrtx fixdfti_libfunc;
19218334Speter
19318334Speterrtx fixxfsi_libfunc;
19418334Speterrtx fixxfdi_libfunc;
19518334Speterrtx fixxfti_libfunc;
19618334Speter
19718334Speterrtx fixtfsi_libfunc;
19818334Speterrtx fixtfdi_libfunc;
19918334Speterrtx fixtfti_libfunc;
20018334Speter
20118334Speterrtx fixunssfsi_libfunc;
20218334Speterrtx fixunssfdi_libfunc;
20318334Speterrtx fixunssfti_libfunc;
20418334Speter
20518334Speterrtx fixunsdfsi_libfunc;
20618334Speterrtx fixunsdfdi_libfunc;
20718334Speterrtx fixunsdfti_libfunc;
20818334Speter
20918334Speterrtx fixunsxfsi_libfunc;
21018334Speterrtx fixunsxfdi_libfunc;
21118334Speterrtx fixunsxfti_libfunc;
21218334Speter
21318334Speterrtx fixunstfsi_libfunc;
21418334Speterrtx fixunstfdi_libfunc;
21518334Speterrtx fixunstfti_libfunc;
21618334Speter
21750397Sobrienrtx chkr_check_addr_libfunc;
21850397Sobrienrtx chkr_set_right_libfunc;
21950397Sobrienrtx chkr_copy_bitmap_libfunc;
22050397Sobrienrtx chkr_check_exec_libfunc;
22150397Sobrienrtx chkr_check_str_libfunc;
22250397Sobrien
22352284Sobrienrtx profile_function_entry_libfunc;
22452284Sobrienrtx profile_function_exit_libfunc;
22552284Sobrien
22618334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
22718334Speter   gives the gen_function to make a branch to test that condition.  */
22818334Speter
22918334Speterrtxfun bcc_gen_fctn[NUM_RTX_CODE];
23018334Speter
23118334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
23218334Speter   gives the insn code to make a store-condition insn
23318334Speter   to test that condition.  */
23418334Speter
23518334Speterenum insn_code setcc_gen_code[NUM_RTX_CODE];
23618334Speter
23718334Speter#ifdef HAVE_conditional_move
23818334Speter/* Indexed by the machine mode, gives the insn code to make a conditional
23918334Speter   move insn.  This is not indexed by the rtx-code like bcc_gen_fctn and
24018334Speter   setcc_gen_code to cut down on the number of named patterns.  Consider a day
24118334Speter   when a lot more rtx codes are conditional (eg: for the ARM).  */
24218334Speter
24318334Speterenum insn_code movcc_gen_code[NUM_MACHINE_MODES];
24418334Speter#endif
24518334Speter
24618334Speterstatic int add_equal_note	PROTO((rtx, rtx, enum rtx_code, rtx, rtx));
24718334Speterstatic rtx widen_operand	PROTO((rtx, enum machine_mode,
24818334Speter				       enum machine_mode, int, int));
24952284Sobrienstatic int expand_cmplxdiv_straight PROTO((rtx, rtx, rtx, rtx,
25052284Sobrien					   rtx, rtx, enum machine_mode,
25152284Sobrien					   int, enum optab_methods,
25252284Sobrien					   enum mode_class, optab));
25352284Sobrienstatic int expand_cmplxdiv_wide PROTO((rtx, rtx, rtx, rtx,
25452284Sobrien				       rtx, rtx, enum machine_mode,
25552284Sobrien				       int, enum optab_methods,
25652284Sobrien				       enum mode_class, optab));
25718334Speterstatic enum insn_code can_fix_p	PROTO((enum machine_mode, enum machine_mode,
25818334Speter				       int, int *));
25918334Speterstatic enum insn_code can_float_p PROTO((enum machine_mode, enum machine_mode,
26018334Speter					 int));
26118334Speterstatic rtx ftruncify	PROTO((rtx));
26218334Speterstatic optab init_optab	PROTO((enum rtx_code));
26352284Sobrienstatic void init_libfuncs PROTO((optab, int, int, const char *, int));
26452284Sobrienstatic void init_integral_libfuncs PROTO((optab, const char *, int));
26552284Sobrienstatic void init_floating_libfuncs PROTO((optab, const char *, int));
26650397Sobrien#ifdef HAVE_conditional_trap
26750397Sobrienstatic void init_traps PROTO((void));
26850397Sobrien#endif
26918334Speter
27018334Speter/* Add a REG_EQUAL note to the last insn in SEQ.  TARGET is being set to
27118334Speter   the result of operation CODE applied to OP0 (and OP1 if it is a binary
27218334Speter   operation).
27318334Speter
27418334Speter   If the last insn does not set TARGET, don't do anything, but return 1.
27518334Speter
27618334Speter   If a previous insn sets TARGET and TARGET is one of OP0 or OP1,
27718334Speter   don't add the REG_EQUAL note but return 0.  Our caller can then try
27818334Speter   again, ensuring that TARGET is not one of the operands.  */
27918334Speter
28018334Speterstatic int
28118334Speteradd_equal_note (seq, target, code, op0, op1)
28218334Speter     rtx seq;
28318334Speter     rtx target;
28418334Speter     enum rtx_code code;
28518334Speter     rtx op0, op1;
28618334Speter{
28718334Speter  rtx set;
28818334Speter  int i;
28918334Speter  rtx note;
29018334Speter
29118334Speter  if ((GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2'
29218334Speter       && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<')
29318334Speter      || GET_CODE (seq) != SEQUENCE
29418334Speter      || (set = single_set (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))) == 0
29518334Speter      || GET_CODE (target) == ZERO_EXTRACT
29618334Speter      || (! rtx_equal_p (SET_DEST (set), target)
29718334Speter	  /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the
29818334Speter	     SUBREG.  */
29918334Speter	  && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
30018334Speter	      || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
30118334Speter				target))))
30218334Speter    return 1;
30318334Speter
30418334Speter  /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET
30518334Speter     besides the last insn.  */
30618334Speter  if (reg_overlap_mentioned_p (target, op0)
30718334Speter      || (op1 && reg_overlap_mentioned_p (target, op1)))
30818334Speter    for (i = XVECLEN (seq, 0) - 2; i >= 0; i--)
30918334Speter      if (reg_set_p (target, XVECEXP (seq, 0, i)))
31018334Speter	return 0;
31118334Speter
31218334Speter  if (GET_RTX_CLASS (code) == '1')
31350397Sobrien    note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0));
31418334Speter  else
31550397Sobrien    note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
31618334Speter
31752284Sobrien  set_unique_reg_note (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1), REG_EQUAL, note);
31818334Speter
31918334Speter  return 1;
32018334Speter}
32118334Speter
32218334Speter/* Widen OP to MODE and return the rtx for the widened operand.  UNSIGNEDP
32318334Speter   says whether OP is signed or unsigned.  NO_EXTEND is nonzero if we need
32418334Speter   not actually do a sign-extend or zero-extend, but can leave the
32518334Speter   higher-order bits of the result rtx undefined, for example, in the case
32618334Speter   of logical operations, but not right shifts.  */
32718334Speter
32818334Speterstatic rtx
32918334Speterwiden_operand (op, mode, oldmode, unsignedp, no_extend)
33018334Speter     rtx op;
33118334Speter     enum machine_mode mode, oldmode;
33218334Speter     int unsignedp;
33318334Speter     int no_extend;
33418334Speter{
33518334Speter  rtx result;
33618334Speter
33718334Speter  /* If we must extend do so.  If OP is either a constant or a SUBREG
33818334Speter     for a promoted object, also extend since it will be more efficient to
33918334Speter     do so.  */
34018334Speter  if (! no_extend
34118334Speter      || GET_MODE (op) == VOIDmode
34218334Speter      || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)))
34318334Speter    return convert_modes (mode, oldmode, op, unsignedp);
34418334Speter
34518334Speter  /* If MODE is no wider than a single word, we return a paradoxical
34618334Speter     SUBREG.  */
34718334Speter  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
34850397Sobrien    return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0);
34918334Speter
35018334Speter  /* Otherwise, get an object of MODE, clobber it, and set the low-order
35118334Speter     part to OP.  */
35218334Speter
35318334Speter  result = gen_reg_rtx (mode);
35450397Sobrien  emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
35518334Speter  emit_move_insn (gen_lowpart (GET_MODE (op), result), op);
35618334Speter  return result;
35718334Speter}
35818334Speter
35952284Sobrien/* Generate code to perform a straightforward complex divide.  */
36052284Sobrien
36152284Sobrienstatic int
36252284Sobrienexpand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
36352284Sobrien			  unsignedp, methods, class, binoptab)
36452284Sobrien  rtx real0, real1, imag0, imag1, realr, imagr;
36552284Sobrien  enum machine_mode submode;
36652284Sobrien  int unsignedp;
36752284Sobrien  enum optab_methods methods;
36852284Sobrien  enum mode_class class;
36952284Sobrien  optab binoptab;
37052284Sobrien{
37152284Sobrien  rtx divisor;
37252284Sobrien  rtx real_t, imag_t;
37352284Sobrien  rtx temp1, temp2;
37452284Sobrien  rtx res;
37552284Sobrien
37652284Sobrien  /* Don't fetch these from memory more than once.  */
37752284Sobrien  real0 = force_reg (submode, real0);
37852284Sobrien  real1 = force_reg (submode, real1);
37952284Sobrien
38052284Sobrien  if (imag0 != 0)
38152284Sobrien    imag0 = force_reg (submode, imag0);
38252284Sobrien
38352284Sobrien  imag1 = force_reg (submode, imag1);
38452284Sobrien
38552284Sobrien  /* Divisor: c*c + d*d.  */
38652284Sobrien  temp1 = expand_binop (submode, smul_optab, real1, real1,
38752284Sobrien			NULL_RTX, unsignedp, methods);
38852284Sobrien
38952284Sobrien  temp2 = expand_binop (submode, smul_optab, imag1, imag1,
39052284Sobrien			NULL_RTX, unsignedp, methods);
39152284Sobrien
39252284Sobrien  if (temp1 == 0 || temp2 == 0)
39352284Sobrien    return 0;
39452284Sobrien
39552284Sobrien  divisor = expand_binop (submode, add_optab, temp1, temp2,
39652284Sobrien			  NULL_RTX, unsignedp, methods);
39752284Sobrien  if (divisor == 0)
39852284Sobrien    return 0;
39952284Sobrien
40052284Sobrien  if (imag0 == 0)
40152284Sobrien    {
40252284Sobrien      /* Mathematically, ((a)(c-id))/divisor.  */
40352284Sobrien      /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
40452284Sobrien
40552284Sobrien      /* Calculate the dividend.  */
40652284Sobrien      real_t = expand_binop (submode, smul_optab, real0, real1,
40752284Sobrien			     NULL_RTX, unsignedp, methods);
40852284Sobrien
40952284Sobrien      imag_t = expand_binop (submode, smul_optab, real0, imag1,
41052284Sobrien			     NULL_RTX, unsignedp, methods);
41152284Sobrien
41252284Sobrien      if (real_t == 0 || imag_t == 0)
41352284Sobrien	return 0;
41452284Sobrien
41552284Sobrien      imag_t = expand_unop (submode, neg_optab, imag_t,
41652284Sobrien			    NULL_RTX, unsignedp);
41752284Sobrien    }
41852284Sobrien  else
41952284Sobrien    {
42052284Sobrien      /* Mathematically, ((a+ib)(c-id))/divider.  */
42152284Sobrien      /* Calculate the dividend.  */
42252284Sobrien      temp1 = expand_binop (submode, smul_optab, real0, real1,
42352284Sobrien			    NULL_RTX, unsignedp, methods);
42452284Sobrien
42552284Sobrien      temp2 = expand_binop (submode, smul_optab, imag0, imag1,
42652284Sobrien			    NULL_RTX, unsignedp, methods);
42752284Sobrien
42852284Sobrien      if (temp1 == 0 || temp2 == 0)
42952284Sobrien	return 0;
43052284Sobrien
43152284Sobrien      real_t = expand_binop (submode, add_optab, temp1, temp2,
43252284Sobrien			     NULL_RTX, unsignedp, methods);
43352284Sobrien
43452284Sobrien      temp1 = expand_binop (submode, smul_optab, imag0, real1,
43552284Sobrien			    NULL_RTX, unsignedp, methods);
43652284Sobrien
43752284Sobrien      temp2 = expand_binop (submode, smul_optab, real0, imag1,
43852284Sobrien			    NULL_RTX, unsignedp, methods);
43952284Sobrien
44052284Sobrien      if (temp1 == 0 || temp2 == 0)
44152284Sobrien	return 0;
44252284Sobrien
44352284Sobrien      imag_t = expand_binop (submode, sub_optab, temp1, temp2,
44452284Sobrien			     NULL_RTX, unsignedp, methods);
44552284Sobrien
44652284Sobrien      if (real_t == 0 || imag_t == 0)
44752284Sobrien	return 0;
44852284Sobrien    }
44952284Sobrien
45052284Sobrien  if (class == MODE_COMPLEX_FLOAT)
45152284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
45252284Sobrien			realr, unsignedp, methods);
45352284Sobrien  else
45452284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
45552284Sobrien			 real_t, divisor, realr, unsignedp);
45652284Sobrien
45752284Sobrien  if (res == 0)
45852284Sobrien    return 0;
45952284Sobrien
46052284Sobrien  if (res != realr)
46152284Sobrien    emit_move_insn (realr, res);
46252284Sobrien
46352284Sobrien  if (class == MODE_COMPLEX_FLOAT)
46452284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
46552284Sobrien			imagr, unsignedp, methods);
46652284Sobrien  else
46752284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
46852284Sobrien			 imag_t, divisor, imagr, unsignedp);
46952284Sobrien
47052284Sobrien  if (res == 0)
47152284Sobrien    return 0;
47252284Sobrien
47352284Sobrien  if (res != imagr)
47452284Sobrien    emit_move_insn (imagr, res);
47552284Sobrien
47652284Sobrien  return 1;
47752284Sobrien}
47852284Sobrien
47952284Sobrien/* Generate code to perform a wide-input-range-acceptable complex divide.  */
48052284Sobrien
48152284Sobrienstatic int
48252284Sobrienexpand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
48352284Sobrien		      unsignedp, methods, class, binoptab)
48452284Sobrien  rtx real0, real1, imag0, imag1, realr, imagr;
48552284Sobrien  enum machine_mode submode;
48652284Sobrien  int unsignedp;
48752284Sobrien  enum optab_methods methods;
48852284Sobrien  enum mode_class class;
48952284Sobrien  optab binoptab;
49052284Sobrien{
49152284Sobrien  rtx ratio, divisor;
49252284Sobrien  rtx real_t, imag_t;
49352284Sobrien  rtx temp1, temp2, lab1, lab2;
49452284Sobrien  enum machine_mode mode;
49552284Sobrien  int align;
49652284Sobrien  rtx res;
49752284Sobrien
49852284Sobrien  /* Don't fetch these from memory more than once.  */
49952284Sobrien  real0 = force_reg (submode, real0);
50052284Sobrien  real1 = force_reg (submode, real1);
50152284Sobrien
50252284Sobrien  if (imag0 != 0)
50352284Sobrien    imag0 = force_reg (submode, imag0);
50452284Sobrien
50552284Sobrien  imag1 = force_reg (submode, imag1);
50652284Sobrien
50752284Sobrien  /* XXX What's an "unsigned" complex number?  */
50852284Sobrien  if (unsignedp)
50952284Sobrien    {
51052284Sobrien      temp1 = real1;
51152284Sobrien      temp2 = imag1;
51252284Sobrien    }
51352284Sobrien  else
51452284Sobrien    {
51552284Sobrien      temp1 = expand_abs (submode, real1, NULL_RTX, 1);
51652284Sobrien      temp2 = expand_abs (submode, imag1, NULL_RTX, 1);
51752284Sobrien    }
51852284Sobrien
51952284Sobrien  if (temp1 == 0 || temp2 == 0)
52052284Sobrien    return 0;
52152284Sobrien
52252284Sobrien  mode = GET_MODE (temp1);
52352284Sobrien  align = GET_MODE_ALIGNMENT (mode);
52452284Sobrien  lab1 = gen_label_rtx ();
52552284Sobrien  emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX,
52652284Sobrien			   mode, unsignedp, align, lab1);
52752284Sobrien
52852284Sobrien  /* |c| >= |d|; use ratio d/c to scale dividend and divisor.  */
52952284Sobrien
53052284Sobrien  if (class == MODE_COMPLEX_FLOAT)
53152284Sobrien    ratio = expand_binop (submode, binoptab, imag1, real1,
53252284Sobrien			  NULL_RTX, unsignedp, methods);
53352284Sobrien  else
53452284Sobrien    ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
53552284Sobrien			   imag1, real1, NULL_RTX, unsignedp);
53652284Sobrien
53752284Sobrien  if (ratio == 0)
53852284Sobrien    return 0;
53952284Sobrien
54052284Sobrien  /* Calculate divisor.  */
54152284Sobrien
54252284Sobrien  temp1 = expand_binop (submode, smul_optab, imag1, ratio,
54352284Sobrien			NULL_RTX, unsignedp, methods);
54452284Sobrien
54552284Sobrien  if (temp1 == 0)
54652284Sobrien    return 0;
54752284Sobrien
54852284Sobrien  divisor = expand_binop (submode, add_optab, temp1, real1,
54952284Sobrien			  NULL_RTX, unsignedp, methods);
55052284Sobrien
55152284Sobrien  if (divisor == 0)
55252284Sobrien    return 0;
55352284Sobrien
55452284Sobrien  /* Calculate dividend.  */
55552284Sobrien
55652284Sobrien  if (imag0 == 0)
55752284Sobrien    {
55852284Sobrien      real_t = real0;
55952284Sobrien
56052284Sobrien      /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)).  */
56152284Sobrien
56252284Sobrien      imag_t = expand_binop (submode, smul_optab, real0, ratio,
56352284Sobrien			     NULL_RTX, unsignedp, methods);
56452284Sobrien
56552284Sobrien      if (imag_t == 0)
56652284Sobrien	return 0;
56752284Sobrien
56852284Sobrien      imag_t = expand_unop (submode, neg_optab, imag_t,
56952284Sobrien			    NULL_RTX, unsignedp);
57052284Sobrien
57152284Sobrien      if (real_t == 0 || imag_t == 0)
57252284Sobrien	return 0;
57352284Sobrien    }
57452284Sobrien  else
57552284Sobrien    {
57652284Sobrien      /* Compute (a+ib)/(c+id) as
57752284Sobrien	 (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)).  */
57852284Sobrien
57952284Sobrien      temp1 = expand_binop (submode, smul_optab, imag0, ratio,
58052284Sobrien			    NULL_RTX, unsignedp, methods);
58152284Sobrien
58252284Sobrien      if (temp1 == 0)
58352284Sobrien	return 0;
58452284Sobrien
58552284Sobrien      real_t = expand_binop (submode, add_optab, temp1, real0,
58652284Sobrien			     NULL_RTX, unsignedp, methods);
58752284Sobrien
58852284Sobrien      temp1 = expand_binop (submode, smul_optab, real0, ratio,
58952284Sobrien			    NULL_RTX, unsignedp, methods);
59052284Sobrien
59152284Sobrien      if (temp1 == 0)
59252284Sobrien	return 0;
59352284Sobrien
59452284Sobrien      imag_t = expand_binop (submode, sub_optab, imag0, temp1,
59552284Sobrien			     NULL_RTX, unsignedp, methods);
59652284Sobrien
59752284Sobrien      if (real_t == 0 || imag_t == 0)
59852284Sobrien	return 0;
59952284Sobrien    }
60052284Sobrien
60152284Sobrien  if (class == MODE_COMPLEX_FLOAT)
60252284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
60352284Sobrien			realr, unsignedp, methods);
60452284Sobrien  else
60552284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
60652284Sobrien			 real_t, divisor, realr, unsignedp);
60752284Sobrien
60852284Sobrien  if (res == 0)
60952284Sobrien    return 0;
61052284Sobrien
61152284Sobrien  if (res != realr)
61252284Sobrien    emit_move_insn (realr, res);
61352284Sobrien
61452284Sobrien  if (class == MODE_COMPLEX_FLOAT)
61552284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
61652284Sobrien			imagr, unsignedp, methods);
61752284Sobrien  else
61852284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
61952284Sobrien			 imag_t, divisor, imagr, unsignedp);
62052284Sobrien
62152284Sobrien  if (res == 0)
62252284Sobrien    return 0;
62352284Sobrien
62452284Sobrien  if (res != imagr)
62552284Sobrien    emit_move_insn (imagr, res);
62652284Sobrien
62752284Sobrien  lab2 = gen_label_rtx ();
62852284Sobrien  emit_jump_insn (gen_jump (lab2));
62952284Sobrien  emit_barrier ();
63052284Sobrien
63152284Sobrien  emit_label (lab1);
63252284Sobrien
63352284Sobrien  /* |d| > |c|; use ratio c/d to scale dividend and divisor.  */
63452284Sobrien
63552284Sobrien  if (class == MODE_COMPLEX_FLOAT)
63652284Sobrien    ratio = expand_binop (submode, binoptab, real1, imag1,
63752284Sobrien			  NULL_RTX, unsignedp, methods);
63852284Sobrien  else
63952284Sobrien    ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
64052284Sobrien			   real1, imag1, NULL_RTX, unsignedp);
64152284Sobrien
64252284Sobrien  if (ratio == 0)
64352284Sobrien    return 0;
64452284Sobrien
64552284Sobrien  /* Calculate divisor.  */
64652284Sobrien
64752284Sobrien  temp1 = expand_binop (submode, smul_optab, real1, ratio,
64852284Sobrien			NULL_RTX, unsignedp, methods);
64952284Sobrien
65052284Sobrien  if (temp1 == 0)
65152284Sobrien    return 0;
65252284Sobrien
65352284Sobrien  divisor = expand_binop (submode, add_optab, temp1, imag1,
65452284Sobrien			  NULL_RTX, unsignedp, methods);
65552284Sobrien
65652284Sobrien  if (divisor == 0)
65752284Sobrien    return 0;
65852284Sobrien
65952284Sobrien  /* Calculate dividend.  */
66052284Sobrien
66152284Sobrien  if (imag0 == 0)
66252284Sobrien    {
66352284Sobrien      /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
66452284Sobrien
66552284Sobrien      real_t = expand_binop (submode, smul_optab, real0, ratio,
66652284Sobrien			     NULL_RTX, unsignedp, methods);
66752284Sobrien
66852284Sobrien      imag_t = expand_unop (submode, neg_optab, real0,
66952284Sobrien			    NULL_RTX, unsignedp);
67052284Sobrien
67152284Sobrien      if (real_t == 0 || imag_t == 0)
67252284Sobrien	return 0;
67352284Sobrien    }
67452284Sobrien  else
67552284Sobrien    {
67652284Sobrien      /* Compute (a+ib)/(c+id) as
67752284Sobrien	 (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d).  */
67852284Sobrien
67952284Sobrien      temp1 = expand_binop (submode, smul_optab, real0, ratio,
68052284Sobrien			    NULL_RTX, unsignedp, methods);
68152284Sobrien
68252284Sobrien      if (temp1 == 0)
68352284Sobrien	return 0;
68452284Sobrien
68552284Sobrien      real_t = expand_binop (submode, add_optab, temp1, imag0,
68652284Sobrien			     NULL_RTX, unsignedp, methods);
68752284Sobrien
68852284Sobrien      temp1 = expand_binop (submode, smul_optab, imag0, ratio,
68952284Sobrien			    NULL_RTX, unsignedp, methods);
69052284Sobrien
69152284Sobrien      if (temp1 == 0)
69252284Sobrien	return 0;
69352284Sobrien
69452284Sobrien      imag_t = expand_binop (submode, sub_optab, temp1, real0,
69552284Sobrien			     NULL_RTX, unsignedp, methods);
69652284Sobrien
69752284Sobrien      if (real_t == 0 || imag_t == 0)
69852284Sobrien	return 0;
69952284Sobrien    }
70052284Sobrien
70152284Sobrien  if (class == MODE_COMPLEX_FLOAT)
70252284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
70352284Sobrien			realr, unsignedp, methods);
70452284Sobrien  else
70552284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
70652284Sobrien			 real_t, divisor, realr, unsignedp);
70752284Sobrien
70852284Sobrien  if (res == 0)
70952284Sobrien    return 0;
71052284Sobrien
71152284Sobrien  if (res != realr)
71252284Sobrien    emit_move_insn (realr, res);
71352284Sobrien
71452284Sobrien  if (class == MODE_COMPLEX_FLOAT)
71552284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
71652284Sobrien			imagr, unsignedp, methods);
71752284Sobrien  else
71852284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
71952284Sobrien			 imag_t, divisor, imagr, unsignedp);
72052284Sobrien
72152284Sobrien  if (res == 0)
72252284Sobrien    return 0;
72352284Sobrien
72452284Sobrien  if (res != imagr)
72552284Sobrien    emit_move_insn (imagr, res);
72652284Sobrien
72752284Sobrien  emit_label (lab2);
72852284Sobrien
72952284Sobrien  return 1;
73052284Sobrien}
73152284Sobrien
73218334Speter/* Generate code to perform an operation specified by BINOPTAB
73318334Speter   on operands OP0 and OP1, with result having machine-mode MODE.
73418334Speter
73518334Speter   UNSIGNEDP is for the case where we have to widen the operands
73618334Speter   to perform the operation.  It says to use zero-extension.
73718334Speter
73818334Speter   If TARGET is nonzero, the value
73918334Speter   is generated there, if it is convenient to do so.
74018334Speter   In all cases an rtx is returned for the locus of the value;
74118334Speter   this may or may not be TARGET.  */
74218334Speter
74318334Speterrtx
74418334Speterexpand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
74518334Speter     enum machine_mode mode;
74618334Speter     optab binoptab;
74718334Speter     rtx op0, op1;
74818334Speter     rtx target;
74918334Speter     int unsignedp;
75018334Speter     enum optab_methods methods;
75118334Speter{
75218334Speter  enum optab_methods next_methods
75318334Speter    = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
75418334Speter       ? OPTAB_WIDEN : methods);
75518334Speter  enum mode_class class;
75618334Speter  enum machine_mode wider_mode;
75718334Speter  register rtx temp;
75818334Speter  int commutative_op = 0;
75918334Speter  int shift_op = (binoptab->code ==  ASHIFT
76018334Speter		  || binoptab->code == ASHIFTRT
76118334Speter		  || binoptab->code == LSHIFTRT
76218334Speter		  || binoptab->code == ROTATE
76318334Speter		  || binoptab->code == ROTATERT);
76418334Speter  rtx entry_last = get_last_insn ();
76518334Speter  rtx last;
76618334Speter
76718334Speter  class = GET_MODE_CLASS (mode);
76818334Speter
76918334Speter  op0 = protect_from_queue (op0, 0);
77018334Speter  op1 = protect_from_queue (op1, 0);
77118334Speter  if (target)
77218334Speter    target = protect_from_queue (target, 1);
77318334Speter
77418334Speter  if (flag_force_mem)
77518334Speter    {
77618334Speter      op0 = force_not_mem (op0);
77718334Speter      op1 = force_not_mem (op1);
77818334Speter    }
77918334Speter
78018334Speter  /* If subtracting an integer constant, convert this into an addition of
78118334Speter     the negated constant.  */
78218334Speter
78318334Speter  if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT)
78418334Speter    {
78518334Speter      op1 = negate_rtx (mode, op1);
78618334Speter      binoptab = add_optab;
78718334Speter    }
78818334Speter
78918334Speter  /* If we are inside an appropriately-short loop and one operand is an
79018334Speter     expensive constant, force it into a register.  */
79118334Speter  if (CONSTANT_P (op0) && preserve_subexpressions_p ()
79218334Speter      && rtx_cost (op0, binoptab->code) > 2)
79318334Speter    op0 = force_reg (mode, op0);
79418334Speter
79518334Speter  if (CONSTANT_P (op1) && preserve_subexpressions_p ()
79618334Speter      && ! shift_op && rtx_cost (op1, binoptab->code) > 2)
79718334Speter    op1 = force_reg (mode, op1);
79818334Speter
79918334Speter  /* Record where to delete back to if we backtrack.  */
80018334Speter  last = get_last_insn ();
80118334Speter
80218334Speter  /* If operation is commutative,
80318334Speter     try to make the first operand a register.
80418334Speter     Even better, try to make it the same as the target.
80518334Speter     Also try to make the last operand a constant.  */
80618334Speter  if (GET_RTX_CLASS (binoptab->code) == 'c'
80718334Speter      || binoptab == smul_widen_optab
80818334Speter      || binoptab == umul_widen_optab
80918334Speter      || binoptab == smul_highpart_optab
81018334Speter      || binoptab == umul_highpart_optab)
81118334Speter    {
81218334Speter      commutative_op = 1;
81318334Speter
81418334Speter      if (((target == 0 || GET_CODE (target) == REG)
81518334Speter	   ? ((GET_CODE (op1) == REG
81618334Speter	       && GET_CODE (op0) != REG)
81718334Speter	      || target == op1)
81818334Speter	   : rtx_equal_p (op1, target))
81918334Speter	  || GET_CODE (op0) == CONST_INT)
82018334Speter	{
82118334Speter	  temp = op1;
82218334Speter	  op1 = op0;
82318334Speter	  op0 = temp;
82418334Speter	}
82518334Speter    }
82618334Speter
82718334Speter  /* If we can do it with a three-operand insn, do so.  */
82818334Speter
82918334Speter  if (methods != OPTAB_MUST_WIDEN
83018334Speter      && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
83118334Speter    {
83218334Speter      int icode = (int) binoptab->handlers[(int) mode].insn_code;
83318334Speter      enum machine_mode mode0 = insn_operand_mode[icode][1];
83418334Speter      enum machine_mode mode1 = insn_operand_mode[icode][2];
83518334Speter      rtx pat;
83618334Speter      rtx xop0 = op0, xop1 = op1;
83718334Speter
83818334Speter      if (target)
83918334Speter	temp = target;
84018334Speter      else
84118334Speter	temp = gen_reg_rtx (mode);
84218334Speter
84318334Speter      /* If it is a commutative operator and the modes would match
84450397Sobrien	 if we would swap the operands, we can save the conversions.  */
84518334Speter      if (commutative_op)
84618334Speter	{
84718334Speter	  if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
84818334Speter	      && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
84918334Speter	    {
85018334Speter	      register rtx tmp;
85118334Speter
85218334Speter	      tmp = op0; op0 = op1; op1 = tmp;
85318334Speter	      tmp = xop0; xop0 = xop1; xop1 = tmp;
85418334Speter	    }
85518334Speter	}
85618334Speter
85718334Speter      /* In case the insn wants input operands in modes different from
85818334Speter	 the result, convert the operands.  */
85918334Speter
86018334Speter      if (GET_MODE (op0) != VOIDmode
86118334Speter	  && GET_MODE (op0) != mode0
86218334Speter	  && mode0 != VOIDmode)
86318334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
86418334Speter
86518334Speter      if (GET_MODE (xop1) != VOIDmode
86618334Speter	  && GET_MODE (xop1) != mode1
86718334Speter	  && mode1 != VOIDmode)
86818334Speter	xop1 = convert_to_mode (mode1, xop1, unsignedp);
86918334Speter
87018334Speter      /* Now, if insn's predicates don't allow our operands, put them into
87118334Speter	 pseudo regs.  */
87218334Speter
87318334Speter      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)
87418334Speter	  && mode0 != VOIDmode)
87518334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
87618334Speter
87718334Speter      if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)
87818334Speter	  && mode1 != VOIDmode)
87918334Speter	xop1 = copy_to_mode_reg (mode1, xop1);
88018334Speter
88118334Speter      if (! (*insn_operand_predicate[icode][0]) (temp, mode))
88218334Speter	temp = gen_reg_rtx (mode);
88318334Speter
88418334Speter      pat = GEN_FCN (icode) (temp, xop0, xop1);
88518334Speter      if (pat)
88618334Speter	{
88718334Speter	  /* If PAT is a multi-insn sequence, try to add an appropriate
88818334Speter	     REG_EQUAL note to it.  If we can't because TEMP conflicts with an
88918334Speter	     operand, call ourselves again, this time without a target.  */
89018334Speter	  if (GET_CODE (pat) == SEQUENCE
89118334Speter	      && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
89218334Speter	    {
89318334Speter	      delete_insns_since (last);
89418334Speter	      return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
89518334Speter				   unsignedp, methods);
89618334Speter	    }
89718334Speter
89818334Speter	  emit_insn (pat);
89918334Speter	  return temp;
90018334Speter	}
90118334Speter      else
90218334Speter	delete_insns_since (last);
90318334Speter    }
90418334Speter
90518334Speter  /* If this is a multiply, see if we can do a widening operation that
90618334Speter     takes operands of this mode and makes a wider mode.  */
90718334Speter
90818334Speter  if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode
90918334Speter      && (((unsignedp ? umul_widen_optab : smul_widen_optab)
91018334Speter	   ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code)
91118334Speter	  != CODE_FOR_nothing))
91218334Speter    {
91318334Speter      temp = expand_binop (GET_MODE_WIDER_MODE (mode),
91418334Speter			   unsignedp ? umul_widen_optab : smul_widen_optab,
91518334Speter			   op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);
91618334Speter
91718334Speter      if (temp != 0)
91818334Speter	{
91918334Speter	  if (GET_MODE_CLASS (mode) == MODE_INT)
92018334Speter	    return gen_lowpart (mode, temp);
92118334Speter	  else
92218334Speter	    return convert_to_mode (mode, temp, unsignedp);
92318334Speter	}
92418334Speter    }
92518334Speter
92618334Speter  /* Look for a wider mode of the same class for which we think we
92718334Speter     can open-code the operation.  Check for a widening multiply at the
92818334Speter     wider mode as well.  */
92918334Speter
93018334Speter  if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
93118334Speter      && methods != OPTAB_DIRECT && methods != OPTAB_LIB)
93218334Speter    for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
93318334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
93418334Speter      {
93518334Speter	if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
93618334Speter	    || (binoptab == smul_optab
93718334Speter		&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
93818334Speter		&& (((unsignedp ? umul_widen_optab : smul_widen_optab)
93918334Speter		     ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code)
94018334Speter		    != CODE_FOR_nothing)))
94118334Speter	  {
94218334Speter	    rtx xop0 = op0, xop1 = op1;
94318334Speter	    int no_extend = 0;
94418334Speter
94518334Speter	    /* For certain integer operations, we need not actually extend
94618334Speter	       the narrow operands, as long as we will truncate
94718334Speter	       the results to the same narrowness.   */
94818334Speter
94918334Speter	    if ((binoptab == ior_optab || binoptab == and_optab
95018334Speter		 || binoptab == xor_optab
95118334Speter		 || binoptab == add_optab || binoptab == sub_optab
95218334Speter		 || binoptab == smul_optab || binoptab == ashl_optab)
95318334Speter		&& class == MODE_INT)
95418334Speter	      no_extend = 1;
95518334Speter
95618334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend);
95718334Speter
95818334Speter	    /* The second operand of a shift must always be extended.  */
95918334Speter	    xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
96018334Speter				  no_extend && binoptab != ashl_optab);
96118334Speter
96218334Speter	    temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
96318334Speter				 unsignedp, OPTAB_DIRECT);
96418334Speter	    if (temp)
96518334Speter	      {
96618334Speter		if (class != MODE_INT)
96718334Speter		  {
96818334Speter		    if (target == 0)
96918334Speter		      target = gen_reg_rtx (mode);
97018334Speter		    convert_move (target, temp, 0);
97118334Speter		    return target;
97218334Speter		  }
97318334Speter		else
97418334Speter		  return gen_lowpart (mode, temp);
97518334Speter	      }
97618334Speter	    else
97718334Speter	      delete_insns_since (last);
97818334Speter	  }
97918334Speter      }
98018334Speter
98118334Speter  /* These can be done a word at a time.  */
98218334Speter  if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
98318334Speter      && class == MODE_INT
98418334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
98518334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
98618334Speter    {
98718334Speter      int i;
98818334Speter      rtx insns;
98918334Speter      rtx equiv_value;
99018334Speter
99118334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
99218334Speter	 won't be accurate, so use a new target.  */
99318334Speter      if (target == 0 || target == op0 || target == op1)
99418334Speter	target = gen_reg_rtx (mode);
99518334Speter
99618334Speter      start_sequence ();
99718334Speter
99818334Speter      /* Do the actual arithmetic.  */
99918334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
100018334Speter	{
100118334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
100218334Speter	  rtx x = expand_binop (word_mode, binoptab,
100318334Speter				operand_subword_force (op0, i, mode),
100418334Speter				operand_subword_force (op1, i, mode),
100518334Speter				target_piece, unsignedp, next_methods);
100618334Speter
100718334Speter	  if (x == 0)
100818334Speter	    break;
100918334Speter
101018334Speter	  if (target_piece != x)
101118334Speter	    emit_move_insn (target_piece, x);
101218334Speter	}
101318334Speter
101418334Speter      insns = get_insns ();
101518334Speter      end_sequence ();
101618334Speter
101718334Speter      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
101818334Speter	{
101918334Speter	  if (binoptab->code != UNKNOWN)
102018334Speter	    equiv_value
102150397Sobrien	      = gen_rtx_fmt_ee (binoptab->code, mode,
102250397Sobrien				copy_rtx (op0), copy_rtx (op1));
102318334Speter	  else
102418334Speter	    equiv_value = 0;
102518334Speter
102618334Speter	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);
102718334Speter	  return target;
102818334Speter	}
102918334Speter    }
103018334Speter
103118334Speter  /* Synthesize double word shifts from single word shifts.  */
103218334Speter  if ((binoptab == lshr_optab || binoptab == ashl_optab
103318334Speter       || binoptab == ashr_optab)
103418334Speter      && class == MODE_INT
103518334Speter      && GET_CODE (op1) == CONST_INT
103618334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
103718334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
103818334Speter      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
103918334Speter      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
104018334Speter    {
104118334Speter      rtx insns, inter, equiv_value;
104218334Speter      rtx into_target, outof_target;
104318334Speter      rtx into_input, outof_input;
104418334Speter      int shift_count, left_shift, outof_word;
104518334Speter
104618334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
104718334Speter	 won't be accurate, so use a new target.  */
104818334Speter      if (target == 0 || target == op0 || target == op1)
104918334Speter	target = gen_reg_rtx (mode);
105018334Speter
105118334Speter      start_sequence ();
105218334Speter
105318334Speter      shift_count = INTVAL (op1);
105418334Speter
105518334Speter      /* OUTOF_* is the word we are shifting bits away from, and
105618334Speter	 INTO_* is the word that we are shifting bits towards, thus
105718334Speter	 they differ depending on the direction of the shift and
105818334Speter	 WORDS_BIG_ENDIAN.  */
105918334Speter
106018334Speter      left_shift = binoptab == ashl_optab;
106118334Speter      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
106218334Speter
106318334Speter      outof_target = operand_subword (target, outof_word, 1, mode);
106418334Speter      into_target = operand_subword (target, 1 - outof_word, 1, mode);
106518334Speter
106618334Speter      outof_input = operand_subword_force (op0, outof_word, mode);
106718334Speter      into_input = operand_subword_force (op0, 1 - outof_word, mode);
106818334Speter
106918334Speter      if (shift_count >= BITS_PER_WORD)
107018334Speter	{
107118334Speter	  inter = expand_binop (word_mode, binoptab,
107218334Speter			       outof_input,
107318334Speter			       GEN_INT (shift_count - BITS_PER_WORD),
107418334Speter			       into_target, unsignedp, next_methods);
107518334Speter
107618334Speter	  if (inter != 0 && inter != into_target)
107718334Speter	    emit_move_insn (into_target, inter);
107818334Speter
107918334Speter	  /* For a signed right shift, we must fill the word we are shifting
108018334Speter	     out of with copies of the sign bit.  Otherwise it is zeroed.  */
108118334Speter	  if (inter != 0 && binoptab != ashr_optab)
108218334Speter	    inter = CONST0_RTX (word_mode);
108318334Speter	  else if (inter != 0)
108418334Speter	    inter = expand_binop (word_mode, binoptab,
108518334Speter				  outof_input,
108618334Speter				  GEN_INT (BITS_PER_WORD - 1),
108718334Speter				  outof_target, unsignedp, next_methods);
108818334Speter
108918334Speter	  if (inter != 0 && inter != outof_target)
109018334Speter	    emit_move_insn (outof_target, inter);
109118334Speter	}
109218334Speter      else
109318334Speter	{
109418334Speter	  rtx carries;
109518334Speter	  optab reverse_unsigned_shift, unsigned_shift;
109618334Speter
109718334Speter	  /* For a shift of less then BITS_PER_WORD, to compute the carry,
109818334Speter	     we must do a logical shift in the opposite direction of the
109918334Speter	     desired shift.  */
110018334Speter
110118334Speter	  reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab);
110218334Speter
110318334Speter	  /* For a shift of less than BITS_PER_WORD, to compute the word
110418334Speter	     shifted towards, we need to unsigned shift the orig value of
110518334Speter	     that word.  */
110618334Speter
110718334Speter	  unsigned_shift = (left_shift ? ashl_optab : lshr_optab);
110818334Speter
110918334Speter	  carries = expand_binop (word_mode, reverse_unsigned_shift,
111018334Speter				  outof_input,
111118334Speter				  GEN_INT (BITS_PER_WORD - shift_count),
111218334Speter				  0, unsignedp, next_methods);
111318334Speter
111418334Speter	  if (carries == 0)
111518334Speter	    inter = 0;
111618334Speter	  else
111718334Speter	    inter = expand_binop (word_mode, unsigned_shift, into_input,
111818334Speter				  op1, 0, unsignedp, next_methods);
111918334Speter
112018334Speter	  if (inter != 0)
112118334Speter	    inter = expand_binop (word_mode, ior_optab, carries, inter,
112218334Speter				  into_target, unsignedp, next_methods);
112318334Speter
112418334Speter	  if (inter != 0 && inter != into_target)
112518334Speter	    emit_move_insn (into_target, inter);
112618334Speter
112718334Speter	  if (inter != 0)
112818334Speter	    inter = expand_binop (word_mode, binoptab, outof_input,
112918334Speter				  op1, outof_target, unsignedp, next_methods);
113018334Speter
113118334Speter	  if (inter != 0 && inter != outof_target)
113218334Speter	    emit_move_insn (outof_target, inter);
113318334Speter	}
113418334Speter
113518334Speter      insns = get_insns ();
113618334Speter      end_sequence ();
113718334Speter
113818334Speter      if (inter != 0)
113918334Speter	{
114018334Speter	  if (binoptab->code != UNKNOWN)
114150397Sobrien	    equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
114218334Speter	  else
114318334Speter	    equiv_value = 0;
114418334Speter
114518334Speter	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);
114618334Speter	  return target;
114718334Speter	}
114818334Speter    }
114918334Speter
115018334Speter  /* Synthesize double word rotates from single word shifts.  */
115118334Speter  if ((binoptab == rotl_optab || binoptab == rotr_optab)
115218334Speter      && class == MODE_INT
115318334Speter      && GET_CODE (op1) == CONST_INT
115418334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
115518334Speter      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
115618334Speter      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
115718334Speter    {
115818334Speter      rtx insns, equiv_value;
115918334Speter      rtx into_target, outof_target;
116018334Speter      rtx into_input, outof_input;
116118334Speter      rtx inter;
116218334Speter      int shift_count, left_shift, outof_word;
116318334Speter
116418334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
116518334Speter	 won't be accurate, so use a new target.  */
116618334Speter      if (target == 0 || target == op0 || target == op1)
116718334Speter	target = gen_reg_rtx (mode);
116818334Speter
116918334Speter      start_sequence ();
117018334Speter
117118334Speter      shift_count = INTVAL (op1);
117218334Speter
117318334Speter      /* OUTOF_* is the word we are shifting bits away from, and
117418334Speter	 INTO_* is the word that we are shifting bits towards, thus
117518334Speter	 they differ depending on the direction of the shift and
117618334Speter	 WORDS_BIG_ENDIAN.  */
117718334Speter
117818334Speter      left_shift = (binoptab == rotl_optab);
117918334Speter      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
118018334Speter
118118334Speter      outof_target = operand_subword (target, outof_word, 1, mode);
118218334Speter      into_target = operand_subword (target, 1 - outof_word, 1, mode);
118318334Speter
118418334Speter      outof_input = operand_subword_force (op0, outof_word, mode);
118518334Speter      into_input = operand_subword_force (op0, 1 - outof_word, mode);
118618334Speter
118718334Speter      if (shift_count == BITS_PER_WORD)
118818334Speter	{
118918334Speter	  /* This is just a word swap.  */
119018334Speter	  emit_move_insn (outof_target, into_input);
119118334Speter	  emit_move_insn (into_target, outof_input);
119218334Speter	  inter = const0_rtx;
119318334Speter	}
119418334Speter      else
119518334Speter	{
119618334Speter	  rtx into_temp1, into_temp2, outof_temp1, outof_temp2;
119718334Speter	  rtx first_shift_count, second_shift_count;
119818334Speter	  optab reverse_unsigned_shift, unsigned_shift;
119918334Speter
120018334Speter	  reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
120118334Speter				    ? lshr_optab : ashl_optab);
120218334Speter
120318334Speter	  unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
120418334Speter			    ? ashl_optab : lshr_optab);
120518334Speter
120618334Speter	  if (shift_count > BITS_PER_WORD)
120718334Speter	    {
120818334Speter	      first_shift_count = GEN_INT (shift_count - BITS_PER_WORD);
120918334Speter	      second_shift_count = GEN_INT (2*BITS_PER_WORD - shift_count);
121018334Speter	    }
121118334Speter	  else
121218334Speter	    {
121318334Speter	      first_shift_count = GEN_INT (BITS_PER_WORD - shift_count);
121418334Speter	      second_shift_count = GEN_INT (shift_count);
121518334Speter	    }
121618334Speter
121718334Speter	  into_temp1 = expand_binop (word_mode, unsigned_shift,
121818334Speter				     outof_input, first_shift_count,
121918334Speter				     NULL_RTX, unsignedp, next_methods);
122018334Speter	  into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
122118334Speter				     into_input, second_shift_count,
122218334Speter				     into_target, unsignedp, next_methods);
122318334Speter
122418334Speter	  if (into_temp1 != 0 && into_temp2 != 0)
122518334Speter	    inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2,
122618334Speter				  into_target, unsignedp, next_methods);
122718334Speter	  else
122818334Speter	    inter = 0;
122918334Speter
123018334Speter	  if (inter != 0 && inter != into_target)
123118334Speter	    emit_move_insn (into_target, inter);
123218334Speter
123318334Speter	  outof_temp1 = expand_binop (word_mode, unsigned_shift,
123418334Speter				      into_input, first_shift_count,
123518334Speter				      NULL_RTX, unsignedp, next_methods);
123618334Speter	  outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
123718334Speter				      outof_input, second_shift_count,
123818334Speter				      outof_target, unsignedp, next_methods);
123918334Speter
124018334Speter	  if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)
124118334Speter	    inter = expand_binop (word_mode, ior_optab,
124218334Speter				  outof_temp1, outof_temp2,
124318334Speter				  outof_target, unsignedp, next_methods);
124418334Speter
124518334Speter	  if (inter != 0 && inter != outof_target)
124618334Speter	    emit_move_insn (outof_target, inter);
124718334Speter	}
124818334Speter
124918334Speter      insns = get_insns ();
125018334Speter      end_sequence ();
125118334Speter
125218334Speter      if (inter != 0)
125318334Speter	{
125418334Speter	  if (binoptab->code != UNKNOWN)
125550397Sobrien	    equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
125618334Speter	  else
125718334Speter	    equiv_value = 0;
125818334Speter
125918334Speter	  /* We can't make this a no conflict block if this is a word swap,
126018334Speter	     because the word swap case fails if the input and output values
126118334Speter	     are in the same register.  */
126218334Speter	  if (shift_count != BITS_PER_WORD)
126318334Speter	    emit_no_conflict_block (insns, target, op0, op1, equiv_value);
126418334Speter	  else
126518334Speter	    emit_insns (insns);
126618334Speter
126718334Speter
126818334Speter	  return target;
126918334Speter	}
127018334Speter    }
127118334Speter
127218334Speter  /* These can be done a word at a time by propagating carries.  */
127318334Speter  if ((binoptab == add_optab || binoptab == sub_optab)
127418334Speter      && class == MODE_INT
127518334Speter      && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD
127618334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
127718334Speter    {
127818334Speter      int i;
127918334Speter      rtx carry_tmp = gen_reg_rtx (word_mode);
128018334Speter      optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
128118334Speter      int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
128252284Sobrien      rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
128318334Speter      rtx xop0, xop1;
128418334Speter
128518334Speter      /* We can handle either a 1 or -1 value for the carry.  If STORE_FLAG
128618334Speter	 value is one of those, use it.  Otherwise, use 1 since it is the
128718334Speter	 one easiest to get.  */
128818334Speter#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
128918334Speter      int normalizep = STORE_FLAG_VALUE;
129018334Speter#else
129118334Speter      int normalizep = 1;
129218334Speter#endif
129318334Speter
129418334Speter      /* Prepare the operands.  */
129518334Speter      xop0 = force_reg (mode, op0);
129618334Speter      xop1 = force_reg (mode, op1);
129718334Speter
129818334Speter      if (target == 0 || GET_CODE (target) != REG
129918334Speter	  || target == xop0 || target == xop1)
130018334Speter	target = gen_reg_rtx (mode);
130118334Speter
130218334Speter      /* Indicate for flow that the entire target reg is being set.  */
130318334Speter      if (GET_CODE (target) == REG)
130450397Sobrien	emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
130518334Speter
130618334Speter      /* Do the actual arithmetic.  */
130718334Speter      for (i = 0; i < nwords; i++)
130818334Speter	{
130918334Speter	  int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
131018334Speter	  rtx target_piece = operand_subword (target, index, 1, mode);
131118334Speter	  rtx op0_piece = operand_subword_force (xop0, index, mode);
131218334Speter	  rtx op1_piece = operand_subword_force (xop1, index, mode);
131318334Speter	  rtx x;
131418334Speter
131518334Speter	  /* Main add/subtract of the input operands.  */
131618334Speter	  x = expand_binop (word_mode, binoptab,
131718334Speter			    op0_piece, op1_piece,
131818334Speter			    target_piece, unsignedp, next_methods);
131918334Speter	  if (x == 0)
132018334Speter	    break;
132118334Speter
132218334Speter	  if (i + 1 < nwords)
132318334Speter	    {
132418334Speter	      /* Store carry from main add/subtract.  */
132518334Speter	      carry_out = gen_reg_rtx (word_mode);
132650397Sobrien	      carry_out = emit_store_flag_force (carry_out,
132750397Sobrien						 (binoptab == add_optab
132850397Sobrien						  ? LTU : GTU),
132950397Sobrien						 x, op0_piece,
133050397Sobrien						 word_mode, 1, normalizep);
133118334Speter	    }
133218334Speter
133318334Speter	  if (i > 0)
133418334Speter	    {
133518334Speter	      /* Add/subtract previous carry to main result.  */
133618334Speter	      x = expand_binop (word_mode,
133718334Speter				normalizep == 1 ? binoptab : otheroptab,
133818334Speter				x, carry_in,
133918334Speter				target_piece, 1, next_methods);
134018334Speter	      if (x == 0)
134118334Speter		break;
134218334Speter	      else if (target_piece != x)
134318334Speter		emit_move_insn (target_piece, x);
134418334Speter
134518334Speter	      if (i + 1 < nwords)
134618334Speter		{
134718334Speter		  /* THIS CODE HAS NOT BEEN TESTED.  */
134818334Speter		  /* Get out carry from adding/subtracting carry in.  */
134950397Sobrien		  carry_tmp = emit_store_flag_force (carry_tmp,
135050397Sobrien						     binoptab == add_optab
135150397Sobrien						     ? LTU : GTU,
135250397Sobrien						     x, carry_in,
135350397Sobrien						     word_mode, 1, normalizep);
135418334Speter
135518334Speter		  /* Logical-ior the two poss. carry together.  */
135618334Speter		  carry_out = expand_binop (word_mode, ior_optab,
135718334Speter					    carry_out, carry_tmp,
135818334Speter					    carry_out, 0, next_methods);
135918334Speter		  if (carry_out == 0)
136018334Speter		    break;
136118334Speter		}
136218334Speter	    }
136318334Speter
136418334Speter	  carry_in = carry_out;
136518334Speter	}
136618334Speter
136718334Speter      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
136818334Speter	{
136950397Sobrien	  if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
137050397Sobrien	    {
137150397Sobrien	      rtx temp = emit_move_insn (target, target);
137218334Speter
137352284Sobrien	      set_unique_reg_note (temp,
137452284Sobrien	      			   REG_EQUAL,
137552284Sobrien				   gen_rtx_fmt_ee (binoptab->code, mode,
137652284Sobrien						   copy_rtx (xop0),
137752284Sobrien						   copy_rtx (xop1)));
137850397Sobrien	    }
137918334Speter	  return target;
138018334Speter	}
138118334Speter      else
138218334Speter	delete_insns_since (last);
138318334Speter    }
138418334Speter
138518334Speter  /* If we want to multiply two two-word values and have normal and widening
138618334Speter     multiplies of single-word values, we can do this with three smaller
138718334Speter     multiplications.  Note that we do not make a REG_NO_CONFLICT block here
138818334Speter     because we are not operating on one word at a time.
138918334Speter
139018334Speter     The multiplication proceeds as follows:
139118334Speter			         _______________________
139218334Speter			        [__op0_high_|__op0_low__]
139318334Speter			         _______________________
139418334Speter        *			[__op1_high_|__op1_low__]
139518334Speter        _______________________________________________
139618334Speter			         _______________________
139718334Speter    (1)				[__op0_low__*__op1_low__]
139818334Speter		     _______________________
139918334Speter    (2a)	    [__op0_low__*__op1_high_]
140018334Speter		     _______________________
140118334Speter    (2b)	    [__op0_high_*__op1_low__]
140218334Speter         _______________________
140318334Speter    (3) [__op0_high_*__op1_high_]
140418334Speter
140518334Speter
140618334Speter    This gives a 4-word result.  Since we are only interested in the
140718334Speter    lower 2 words, partial result (3) and the upper words of (2a) and
140818334Speter    (2b) don't need to be calculated.  Hence (2a) and (2b) can be
140918334Speter    calculated using non-widening multiplication.
141018334Speter
141118334Speter    (1), however, needs to be calculated with an unsigned widening
141218334Speter    multiplication.  If this operation is not directly supported we
141318334Speter    try using a signed widening multiplication and adjust the result.
141418334Speter    This adjustment works as follows:
141518334Speter
141618334Speter      If both operands are positive then no adjustment is needed.
141718334Speter
141818334Speter      If the operands have different signs, for example op0_low < 0 and
141918334Speter      op1_low >= 0, the instruction treats the most significant bit of
142018334Speter      op0_low as a sign bit instead of a bit with significance
142118334Speter      2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low
142218334Speter      with 2**BITS_PER_WORD - op0_low, and two's complements the
142318334Speter      result.  Conclusion: We need to add op1_low * 2**BITS_PER_WORD to
142418334Speter      the result.
142518334Speter
142618334Speter      Similarly, if both operands are negative, we need to add
142718334Speter      (op0_low + op1_low) * 2**BITS_PER_WORD.
142818334Speter
142918334Speter      We use a trick to adjust quickly.  We logically shift op0_low right
143018334Speter      (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to
143118334Speter      op0_high (op1_high) before it is used to calculate 2b (2a).  If no
143218334Speter      logical shift exists, we do an arithmetic right shift and subtract
143318334Speter      the 0 or -1.  */
143418334Speter
143518334Speter  if (binoptab == smul_optab
143618334Speter      && class == MODE_INT
143718334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
143818334Speter      && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
143918334Speter      && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
144018334Speter      && ((umul_widen_optab->handlers[(int) mode].insn_code
144118334Speter	   != CODE_FOR_nothing)
144218334Speter	  || (smul_widen_optab->handlers[(int) mode].insn_code
144318334Speter	      != CODE_FOR_nothing)))
144418334Speter    {
144518334Speter      int low = (WORDS_BIG_ENDIAN ? 1 : 0);
144618334Speter      int high = (WORDS_BIG_ENDIAN ? 0 : 1);
144718334Speter      rtx op0_high = operand_subword_force (op0, high, mode);
144818334Speter      rtx op0_low = operand_subword_force (op0, low, mode);
144918334Speter      rtx op1_high = operand_subword_force (op1, high, mode);
145018334Speter      rtx op1_low = operand_subword_force (op1, low, mode);
145118334Speter      rtx product = 0;
145252284Sobrien      rtx op0_xhigh = NULL_RTX;
145352284Sobrien      rtx op1_xhigh = NULL_RTX;
145418334Speter
145518334Speter      /* If the target is the same as one of the inputs, don't use it.  This
145618334Speter	 prevents problems with the REG_EQUAL note.  */
145718334Speter      if (target == op0 || target == op1
145818334Speter	  || (target != 0 && GET_CODE (target) != REG))
145918334Speter	target = 0;
146018334Speter
146118334Speter      /* Multiply the two lower words to get a double-word product.
146218334Speter	 If unsigned widening multiplication is available, use that;
146318334Speter	 otherwise use the signed form and compensate.  */
146418334Speter
146518334Speter      if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
146618334Speter	{
146718334Speter	  product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,
146818334Speter				  target, 1, OPTAB_DIRECT);
146918334Speter
147018334Speter	  /* If we didn't succeed, delete everything we did so far.  */
147118334Speter	  if (product == 0)
147218334Speter	    delete_insns_since (last);
147318334Speter	  else
147418334Speter	    op0_xhigh = op0_high, op1_xhigh = op1_high;
147518334Speter	}
147618334Speter
147718334Speter      if (product == 0
147818334Speter	  && smul_widen_optab->handlers[(int) mode].insn_code
147918334Speter	       != CODE_FOR_nothing)
148018334Speter	{
148118334Speter	  rtx wordm1 = GEN_INT (BITS_PER_WORD - 1);
148218334Speter	  product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
148318334Speter				  target, 1, OPTAB_DIRECT);
148418334Speter	  op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
148518334Speter				    NULL_RTX, 1, next_methods);
148618334Speter	  if (op0_xhigh)
148718334Speter	    op0_xhigh = expand_binop (word_mode, add_optab, op0_high,
148818334Speter				      op0_xhigh, op0_xhigh, 0, next_methods);
148918334Speter	  else
149018334Speter	    {
149118334Speter	      op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
149218334Speter					NULL_RTX, 0, next_methods);
149318334Speter	      if (op0_xhigh)
149418334Speter		op0_xhigh = expand_binop (word_mode, sub_optab, op0_high,
149518334Speter					  op0_xhigh, op0_xhigh, 0,
149618334Speter					  next_methods);
149718334Speter	    }
149818334Speter
149918334Speter	  op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
150018334Speter				    NULL_RTX, 1, next_methods);
150118334Speter	  if (op1_xhigh)
150218334Speter	    op1_xhigh = expand_binop (word_mode, add_optab, op1_high,
150318334Speter				      op1_xhigh, op1_xhigh, 0, next_methods);
150418334Speter	  else
150518334Speter	    {
150618334Speter	      op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
150718334Speter					NULL_RTX, 0, next_methods);
150818334Speter	      if (op1_xhigh)
150918334Speter		op1_xhigh = expand_binop (word_mode, sub_optab, op1_high,
151018334Speter					  op1_xhigh, op1_xhigh, 0,
151118334Speter					  next_methods);
151218334Speter	    }
151318334Speter	}
151418334Speter
151518334Speter      /* If we have been able to directly compute the product of the
151618334Speter	 low-order words of the operands and perform any required adjustments
151718334Speter	 of the operands, we proceed by trying two more multiplications
151818334Speter	 and then computing the appropriate sum.
151918334Speter
152018334Speter	 We have checked above that the required addition is provided.
152118334Speter	 Full-word addition will normally always succeed, especially if
152218334Speter	 it is provided at all, so we don't worry about its failure.  The
152318334Speter	 multiplication may well fail, however, so we do handle that.  */
152418334Speter
152518334Speter      if (product && op0_xhigh && op1_xhigh)
152618334Speter	{
152718334Speter	  rtx product_high = operand_subword (product, high, 1, mode);
152818334Speter	  rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
152918334Speter				   NULL_RTX, 0, OPTAB_DIRECT);
153018334Speter
153118334Speter	  if (temp != 0)
153218334Speter	    temp = expand_binop (word_mode, add_optab, temp, product_high,
153318334Speter				 product_high, 0, next_methods);
153418334Speter
153518334Speter	  if (temp != 0 && temp != product_high)
153618334Speter	    emit_move_insn (product_high, temp);
153718334Speter
153818334Speter	  if (temp != 0)
153918334Speter	    temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
154018334Speter				 NULL_RTX, 0, OPTAB_DIRECT);
154118334Speter
154218334Speter	  if (temp != 0)
154318334Speter	    temp = expand_binop (word_mode, add_optab, temp,
154418334Speter				 product_high, product_high,
154518334Speter				 0, next_methods);
154618334Speter
154718334Speter	  if (temp != 0 && temp != product_high)
154818334Speter	    emit_move_insn (product_high, temp);
154918334Speter
155018334Speter	  if (temp != 0)
155118334Speter	    {
155250397Sobrien	      if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
155350397Sobrien		{
155450397Sobrien		  temp = emit_move_insn (product, product);
155552284Sobrien		  set_unique_reg_note (temp,
155652284Sobrien		  		       REG_EQUAL,
155752284Sobrien				       gen_rtx_fmt_ee (MULT, mode,
155852284Sobrien						       copy_rtx (op0),
155952284Sobrien						       copy_rtx (op1)));
156050397Sobrien		}
156118334Speter	      return product;
156218334Speter	    }
156318334Speter	}
156418334Speter
156518334Speter      /* If we get here, we couldn't do it for some reason even though we
156618334Speter	 originally thought we could.  Delete anything we've emitted in
156718334Speter	 trying to do it.  */
156818334Speter
156918334Speter      delete_insns_since (last);
157018334Speter    }
157118334Speter
157218334Speter  /* We need to open-code the complex type operations: '+, -, * and /' */
157318334Speter
157418334Speter  /* At this point we allow operations between two similar complex
157518334Speter     numbers, and also if one of the operands is not a complex number
157618334Speter     but rather of MODE_FLOAT or MODE_INT. However, the caller
157718334Speter     must make sure that the MODE of the non-complex operand matches
157818334Speter     the SUBMODE of the complex operand.  */
157918334Speter
158018334Speter  if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
158118334Speter    {
158218334Speter      rtx real0 = 0, imag0 = 0;
158318334Speter      rtx real1 = 0, imag1 = 0;
158418334Speter      rtx realr, imagr, res;
158518334Speter      rtx seq;
158618334Speter      rtx equiv_value;
158718334Speter      int ok = 0;
158818334Speter
158918334Speter      /* Find the correct mode for the real and imaginary parts */
159018334Speter      enum machine_mode submode
159118334Speter	= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
159218334Speter			 class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
159318334Speter			 0);
159418334Speter
159518334Speter      if (submode == BLKmode)
159618334Speter	abort ();
159718334Speter
159818334Speter      if (! target)
159918334Speter	target = gen_reg_rtx (mode);
160018334Speter
160118334Speter      start_sequence ();
160218334Speter
160352284Sobrien      realr = gen_realpart (submode, target);
160418334Speter      imagr = gen_imagpart (submode, target);
160518334Speter
160618334Speter      if (GET_MODE (op0) == mode)
160718334Speter	{
160852284Sobrien	  real0 = gen_realpart (submode, op0);
160918334Speter	  imag0 = gen_imagpart (submode, op0);
161018334Speter	}
161118334Speter      else
161218334Speter	real0 = op0;
161318334Speter
161418334Speter      if (GET_MODE (op1) == mode)
161518334Speter	{
161652284Sobrien	  real1 = gen_realpart (submode, op1);
161718334Speter	  imag1 = gen_imagpart (submode, op1);
161818334Speter	}
161918334Speter      else
162018334Speter	real1 = op1;
162118334Speter
162218334Speter      if (real0 == 0 || real1 == 0 || ! (imag0 != 0|| imag1 != 0))
162318334Speter	abort ();
162418334Speter
162518334Speter      switch (binoptab->code)
162618334Speter	{
162718334Speter	case PLUS:
162818334Speter	  /* (a+ib) + (c+id) = (a+c) + i(b+d) */
162918334Speter	case MINUS:
163018334Speter	  /* (a+ib) - (c+id) = (a-c) + i(b-d) */
163118334Speter	  res = expand_binop (submode, binoptab, real0, real1,
163218334Speter			      realr, unsignedp, methods);
163318334Speter
163418334Speter	  if (res == 0)
163518334Speter	    break;
163618334Speter	  else if (res != realr)
163718334Speter	    emit_move_insn (realr, res);
163818334Speter
163918334Speter	  if (imag0 && imag1)
164018334Speter	    res = expand_binop (submode, binoptab, imag0, imag1,
164118334Speter				imagr, unsignedp, methods);
164218334Speter	  else if (imag0)
164318334Speter	    res = imag0;
164418334Speter	  else if (binoptab->code == MINUS)
164518334Speter	    res = expand_unop (submode, neg_optab, imag1, imagr, unsignedp);
164618334Speter	  else
164718334Speter	    res = imag1;
164818334Speter
164918334Speter	  if (res == 0)
165018334Speter	    break;
165118334Speter	  else if (res != imagr)
165218334Speter	    emit_move_insn (imagr, res);
165318334Speter
165418334Speter	  ok = 1;
165518334Speter	  break;
165618334Speter
165718334Speter	case MULT:
165818334Speter	  /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
165918334Speter
166018334Speter	  if (imag0 && imag1)
166118334Speter	    {
166218334Speter	      rtx temp1, temp2;
166318334Speter
166418334Speter	      /* Don't fetch these from memory more than once.  */
166518334Speter	      real0 = force_reg (submode, real0);
166618334Speter	      real1 = force_reg (submode, real1);
166718334Speter	      imag0 = force_reg (submode, imag0);
166818334Speter	      imag1 = force_reg (submode, imag1);
166918334Speter
167018334Speter	      temp1 = expand_binop (submode, binoptab, real0, real1, NULL_RTX,
167118334Speter				    unsignedp, methods);
167218334Speter
167318334Speter	      temp2 = expand_binop (submode, binoptab, imag0, imag1, NULL_RTX,
167418334Speter				    unsignedp, methods);
167518334Speter
167618334Speter	      if (temp1 == 0 || temp2 == 0)
167718334Speter		break;
167818334Speter
167918334Speter	      res = expand_binop (submode, sub_optab, temp1, temp2,
168018334Speter				  realr, unsignedp, methods);
168118334Speter
168218334Speter	      if (res == 0)
168318334Speter		break;
168418334Speter	      else if (res != realr)
168518334Speter		emit_move_insn (realr, res);
168618334Speter
168718334Speter	      temp1 = expand_binop (submode, binoptab, real0, imag1,
168818334Speter				    NULL_RTX, unsignedp, methods);
168918334Speter
169018334Speter	      temp2 = expand_binop (submode, binoptab, real1, imag0,
169118334Speter				    NULL_RTX, unsignedp, methods);
169218334Speter
169318334Speter	      if (temp1 == 0 || temp2 == 0)
169418334Speter		  break;
169518334Speter
169618334Speter	      res = expand_binop (submode, add_optab, temp1, temp2,
169718334Speter				  imagr, unsignedp, methods);
169818334Speter
169918334Speter	      if (res == 0)
170018334Speter		break;
170118334Speter	      else if (res != imagr)
170218334Speter		emit_move_insn (imagr, res);
170318334Speter
170418334Speter	      ok = 1;
170518334Speter	    }
170618334Speter	  else
170718334Speter	    {
170818334Speter	      /* Don't fetch these from memory more than once.  */
170918334Speter	      real0 = force_reg (submode, real0);
171018334Speter	      real1 = force_reg (submode, real1);
171118334Speter
171218334Speter	      res = expand_binop (submode, binoptab, real0, real1,
171318334Speter				  realr, unsignedp, methods);
171418334Speter	      if (res == 0)
171518334Speter		break;
171618334Speter	      else if (res != realr)
171718334Speter		emit_move_insn (realr, res);
171818334Speter
171918334Speter	      if (imag0 != 0)
172018334Speter		res = expand_binop (submode, binoptab,
172118334Speter				    real1, imag0, imagr, unsignedp, methods);
172218334Speter	      else
172318334Speter		res = expand_binop (submode, binoptab,
172418334Speter				    real0, imag1, imagr, unsignedp, methods);
172518334Speter
172618334Speter	      if (res == 0)
172718334Speter		break;
172818334Speter	      else if (res != imagr)
172918334Speter		emit_move_insn (imagr, res);
173018334Speter
173118334Speter	      ok = 1;
173218334Speter	    }
173318334Speter	  break;
173418334Speter
173518334Speter	case DIV:
173618334Speter	  /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
173718334Speter
173818334Speter	  if (imag1 == 0)
173918334Speter	    {
174018334Speter	      /* (a+ib) / (c+i0) = (a/c) + i(b/c) */
174118334Speter
174218334Speter	      /* Don't fetch these from memory more than once.  */
174318334Speter	      real1 = force_reg (submode, real1);
174418334Speter
174518334Speter	      /* Simply divide the real and imaginary parts by `c' */
174618334Speter	      if (class == MODE_COMPLEX_FLOAT)
174718334Speter		res = expand_binop (submode, binoptab, real0, real1,
174818334Speter				    realr, unsignedp, methods);
174918334Speter	      else
175018334Speter		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
175118334Speter				     real0, real1, realr, unsignedp);
175218334Speter
175318334Speter	      if (res == 0)
175418334Speter		break;
175518334Speter	      else if (res != realr)
175618334Speter		emit_move_insn (realr, res);
175718334Speter
175818334Speter	      if (class == MODE_COMPLEX_FLOAT)
175918334Speter		res = expand_binop (submode, binoptab, imag0, real1,
176018334Speter				    imagr, unsignedp, methods);
176118334Speter	      else
176218334Speter		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
176318334Speter				     imag0, real1, imagr, unsignedp);
176418334Speter
176518334Speter	      if (res == 0)
176618334Speter		break;
176718334Speter	      else if (res != imagr)
176818334Speter		emit_move_insn (imagr, res);
176918334Speter
177018334Speter	      ok = 1;
177118334Speter	    }
177218334Speter	  else
177318334Speter	    {
177452284Sobrien	      switch (flag_complex_divide_method)
177518334Speter		{
177652284Sobrien		case 0:
177752284Sobrien		  ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1,
177852284Sobrien						 realr, imagr, submode,
177952284Sobrien						 unsignedp, methods,
178052284Sobrien						 class, binoptab);
178152284Sobrien		  break;
178218334Speter
178352284Sobrien		case 1:
178452284Sobrien		  ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1,
178552284Sobrien					     realr, imagr, submode,
178652284Sobrien					     unsignedp, methods,
178752284Sobrien					     class, binoptab);
178852284Sobrien		  break;
178918334Speter
179052284Sobrien		default:
179152284Sobrien		  abort ();
179218334Speter		}
179318334Speter	    }
179418334Speter	  break;
179518334Speter
179618334Speter	default:
179718334Speter	  abort ();
179818334Speter	}
179918334Speter
180018334Speter      seq = get_insns ();
180118334Speter      end_sequence ();
180218334Speter
180318334Speter      if (ok)
180418334Speter	{
180518334Speter	  if (binoptab->code != UNKNOWN)
180618334Speter	    equiv_value
180750397Sobrien	      = gen_rtx_fmt_ee (binoptab->code, mode,
180850397Sobrien				copy_rtx (op0), copy_rtx (op1));
180918334Speter	  else
181018334Speter	    equiv_value = 0;
181118334Speter
181218334Speter	  emit_no_conflict_block (seq, target, op0, op1, equiv_value);
181318334Speter
181418334Speter	  return target;
181518334Speter	}
181618334Speter    }
181718334Speter
181818334Speter  /* It can't be open-coded in this mode.
181918334Speter     Use a library call if one is available and caller says that's ok.  */
182018334Speter
182118334Speter  if (binoptab->handlers[(int) mode].libfunc
182218334Speter      && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
182318334Speter    {
182418334Speter      rtx insns;
182518334Speter      rtx op1x = op1;
182618334Speter      enum machine_mode op1_mode = mode;
182718334Speter      rtx value;
182818334Speter
182918334Speter      start_sequence ();
183018334Speter
183118334Speter      if (shift_op)
183218334Speter	{
183318334Speter	  op1_mode = word_mode;
183418334Speter	  /* Specify unsigned here,
183518334Speter	     since negative shift counts are meaningless.  */
183618334Speter	  op1x = convert_to_mode (word_mode, op1, 1);
183718334Speter	}
183818334Speter
183918334Speter      if (GET_MODE (op0) != VOIDmode
184018334Speter	  && GET_MODE (op0) != mode)
184118334Speter	op0 = convert_to_mode (mode, op0, unsignedp);
184218334Speter
184318334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
184418334Speter	 if the libcall is cse'd or moved.  */
184518334Speter      value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc,
184618334Speter				       NULL_RTX, 1, mode, 2,
184718334Speter				       op0, mode, op1x, op1_mode);
184818334Speter
184918334Speter      insns = get_insns ();
185018334Speter      end_sequence ();
185118334Speter
185218334Speter      target = gen_reg_rtx (mode);
185318334Speter      emit_libcall_block (insns, target, value,
185450397Sobrien			  gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
185518334Speter
185618334Speter      return target;
185718334Speter    }
185818334Speter
185918334Speter  delete_insns_since (last);
186018334Speter
186118334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
186218334Speter
186318334Speter  if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN
186418334Speter	 || methods == OPTAB_MUST_WIDEN))
186518334Speter    {
186618334Speter      /* Caller says, don't even try.  */
186718334Speter      delete_insns_since (entry_last);
186818334Speter      return 0;
186918334Speter    }
187018334Speter
187118334Speter  /* Compute the value of METHODS to pass to recursive calls.
187218334Speter     Don't allow widening to be tried recursively.  */
187318334Speter
187418334Speter  methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT);
187518334Speter
187618334Speter  /* Look for a wider mode of the same class for which it appears we can do
187718334Speter     the operation.  */
187818334Speter
187918334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
188018334Speter    {
188118334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
188218334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
188318334Speter	{
188418334Speter	  if ((binoptab->handlers[(int) wider_mode].insn_code
188518334Speter	       != CODE_FOR_nothing)
188618334Speter	      || (methods == OPTAB_LIB
188718334Speter		  && binoptab->handlers[(int) wider_mode].libfunc))
188818334Speter	    {
188918334Speter	      rtx xop0 = op0, xop1 = op1;
189018334Speter	      int no_extend = 0;
189118334Speter
189218334Speter	      /* For certain integer operations, we need not actually extend
189318334Speter		 the narrow operands, as long as we will truncate
189418334Speter		 the results to the same narrowness.  */
189518334Speter
189618334Speter	      if ((binoptab == ior_optab || binoptab == and_optab
189718334Speter		   || binoptab == xor_optab
189818334Speter		   || binoptab == add_optab || binoptab == sub_optab
189918334Speter		   || binoptab == smul_optab || binoptab == ashl_optab)
190018334Speter		  && class == MODE_INT)
190118334Speter		no_extend = 1;
190218334Speter
190318334Speter	      xop0 = widen_operand (xop0, wider_mode, mode,
190418334Speter				    unsignedp, no_extend);
190518334Speter
190618334Speter	      /* The second operand of a shift must always be extended.  */
190718334Speter	      xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
190818334Speter				    no_extend && binoptab != ashl_optab);
190918334Speter
191018334Speter	      temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
191118334Speter				   unsignedp, methods);
191218334Speter	      if (temp)
191318334Speter		{
191418334Speter		  if (class != MODE_INT)
191518334Speter		    {
191618334Speter		      if (target == 0)
191718334Speter			target = gen_reg_rtx (mode);
191818334Speter		      convert_move (target, temp, 0);
191918334Speter		      return target;
192018334Speter		    }
192118334Speter		  else
192218334Speter		    return gen_lowpart (mode, temp);
192318334Speter		}
192418334Speter	      else
192518334Speter		delete_insns_since (last);
192618334Speter	    }
192718334Speter	}
192818334Speter    }
192918334Speter
193018334Speter  delete_insns_since (entry_last);
193118334Speter  return 0;
193218334Speter}
193318334Speter
193418334Speter/* Expand a binary operator which has both signed and unsigned forms.
193518334Speter   UOPTAB is the optab for unsigned operations, and SOPTAB is for
193618334Speter   signed operations.
193718334Speter
193818334Speter   If we widen unsigned operands, we may use a signed wider operation instead
193918334Speter   of an unsigned wider operation, since the result would be the same.  */
194018334Speter
194118334Speterrtx
194218334Spetersign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
194318334Speter    enum machine_mode mode;
194418334Speter    optab uoptab, soptab;
194518334Speter    rtx op0, op1, target;
194618334Speter    int unsignedp;
194718334Speter    enum optab_methods methods;
194818334Speter{
194918334Speter  register rtx temp;
195018334Speter  optab direct_optab = unsignedp ? uoptab : soptab;
195118334Speter  struct optab wide_soptab;
195218334Speter
195318334Speter  /* Do it without widening, if possible.  */
195418334Speter  temp = expand_binop (mode, direct_optab, op0, op1, target,
195518334Speter		       unsignedp, OPTAB_DIRECT);
195618334Speter  if (temp || methods == OPTAB_DIRECT)
195718334Speter    return temp;
195818334Speter
195918334Speter  /* Try widening to a signed int.  Make a fake signed optab that
196018334Speter     hides any signed insn for direct use.  */
196118334Speter  wide_soptab = *soptab;
196218334Speter  wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing;
196318334Speter  wide_soptab.handlers[(int) mode].libfunc = 0;
196418334Speter
196518334Speter  temp = expand_binop (mode, &wide_soptab, op0, op1, target,
196618334Speter		       unsignedp, OPTAB_WIDEN);
196718334Speter
196818334Speter  /* For unsigned operands, try widening to an unsigned int.  */
196918334Speter  if (temp == 0 && unsignedp)
197018334Speter    temp = expand_binop (mode, uoptab, op0, op1, target,
197118334Speter			 unsignedp, OPTAB_WIDEN);
197218334Speter  if (temp || methods == OPTAB_WIDEN)
197318334Speter    return temp;
197418334Speter
197518334Speter  /* Use the right width lib call if that exists.  */
197618334Speter  temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB);
197718334Speter  if (temp || methods == OPTAB_LIB)
197818334Speter    return temp;
197918334Speter
198018334Speter  /* Must widen and use a lib call, use either signed or unsigned.  */
198118334Speter  temp = expand_binop (mode, &wide_soptab, op0, op1, target,
198218334Speter		       unsignedp, methods);
198318334Speter  if (temp != 0)
198418334Speter    return temp;
198518334Speter  if (unsignedp)
198618334Speter    return expand_binop (mode, uoptab, op0, op1, target,
198718334Speter			 unsignedp, methods);
198818334Speter  return 0;
198918334Speter}
199018334Speter
199118334Speter/* Generate code to perform an operation specified by BINOPTAB
199218334Speter   on operands OP0 and OP1, with two results to TARG1 and TARG2.
199318334Speter   We assume that the order of the operands for the instruction
199418334Speter   is TARG0, OP0, OP1, TARG1, which would fit a pattern like
199518334Speter   [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))].
199618334Speter
199718334Speter   Either TARG0 or TARG1 may be zero, but what that means is that
199850397Sobrien   the result is not actually wanted.  We will generate it into
199918334Speter   a dummy pseudo-reg and discard it.  They may not both be zero.
200018334Speter
200118334Speter   Returns 1 if this operation can be performed; 0 if not.  */
200218334Speter
200318334Speterint
200418334Speterexpand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
200518334Speter     optab binoptab;
200618334Speter     rtx op0, op1;
200718334Speter     rtx targ0, targ1;
200818334Speter     int unsignedp;
200918334Speter{
201018334Speter  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
201118334Speter  enum mode_class class;
201218334Speter  enum machine_mode wider_mode;
201318334Speter  rtx entry_last = get_last_insn ();
201418334Speter  rtx last;
201518334Speter
201618334Speter  class = GET_MODE_CLASS (mode);
201718334Speter
201818334Speter  op0 = protect_from_queue (op0, 0);
201918334Speter  op1 = protect_from_queue (op1, 0);
202018334Speter
202118334Speter  if (flag_force_mem)
202218334Speter    {
202318334Speter      op0 = force_not_mem (op0);
202418334Speter      op1 = force_not_mem (op1);
202518334Speter    }
202618334Speter
202718334Speter  /* If we are inside an appropriately-short loop and one operand is an
202818334Speter     expensive constant, force it into a register.  */
202918334Speter  if (CONSTANT_P (op0) && preserve_subexpressions_p ()
203018334Speter      && rtx_cost (op0, binoptab->code) > 2)
203118334Speter    op0 = force_reg (mode, op0);
203218334Speter
203318334Speter  if (CONSTANT_P (op1) && preserve_subexpressions_p ()
203418334Speter      && rtx_cost (op1, binoptab->code) > 2)
203518334Speter    op1 = force_reg (mode, op1);
203618334Speter
203718334Speter  if (targ0)
203818334Speter    targ0 = protect_from_queue (targ0, 1);
203918334Speter  else
204018334Speter    targ0 = gen_reg_rtx (mode);
204118334Speter  if (targ1)
204218334Speter    targ1 = protect_from_queue (targ1, 1);
204318334Speter  else
204418334Speter    targ1 = gen_reg_rtx (mode);
204518334Speter
204618334Speter  /* Record where to go back to if we fail.  */
204718334Speter  last = get_last_insn ();
204818334Speter
204918334Speter  if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
205018334Speter    {
205118334Speter      int icode = (int) binoptab->handlers[(int) mode].insn_code;
205218334Speter      enum machine_mode mode0 = insn_operand_mode[icode][1];
205318334Speter      enum machine_mode mode1 = insn_operand_mode[icode][2];
205418334Speter      rtx pat;
205518334Speter      rtx xop0 = op0, xop1 = op1;
205618334Speter
205718334Speter      /* In case this insn wants input operands in modes different from the
205818334Speter	 result, convert the operands.  */
205918334Speter      if (GET_MODE (op0) != VOIDmode && GET_MODE (op0) != mode0)
206018334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
206118334Speter
206218334Speter      if (GET_MODE (op1) != VOIDmode && GET_MODE (op1) != mode1)
206318334Speter	xop1 = convert_to_mode (mode1, xop1, unsignedp);
206418334Speter
206518334Speter      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
206618334Speter      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
206718334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
206818334Speter
206918334Speter      if (! (*insn_operand_predicate[icode][2]) (xop1, mode1))
207018334Speter	xop1 = copy_to_mode_reg (mode1, xop1);
207118334Speter
207218334Speter      /* We could handle this, but we should always be called with a pseudo
207318334Speter	 for our targets and all insns should take them as outputs.  */
207418334Speter      if (! (*insn_operand_predicate[icode][0]) (targ0, mode)
207518334Speter	  || ! (*insn_operand_predicate[icode][3]) (targ1, mode))
207618334Speter	abort ();
207718334Speter
207818334Speter      pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
207918334Speter      if (pat)
208018334Speter	{
208118334Speter	  emit_insn (pat);
208218334Speter	  return 1;
208318334Speter	}
208418334Speter      else
208518334Speter	delete_insns_since (last);
208618334Speter    }
208718334Speter
208818334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
208918334Speter
209018334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
209118334Speter    {
209218334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
209318334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
209418334Speter	{
209518334Speter	  if (binoptab->handlers[(int) wider_mode].insn_code
209618334Speter	      != CODE_FOR_nothing)
209718334Speter	    {
209818334Speter	      register rtx t0 = gen_reg_rtx (wider_mode);
209918334Speter	      register rtx t1 = gen_reg_rtx (wider_mode);
210018334Speter
210118334Speter	      if (expand_twoval_binop (binoptab,
210218334Speter				       convert_modes (wider_mode, mode, op0,
210318334Speter						      unsignedp),
210418334Speter				       convert_modes (wider_mode, mode, op1,
210518334Speter						      unsignedp),
210618334Speter				       t0, t1, unsignedp))
210718334Speter		{
210818334Speter		  convert_move (targ0, t0, unsignedp);
210918334Speter		  convert_move (targ1, t1, unsignedp);
211018334Speter		  return 1;
211118334Speter		}
211218334Speter	      else
211318334Speter		delete_insns_since (last);
211418334Speter	    }
211518334Speter	}
211618334Speter    }
211718334Speter
211818334Speter  delete_insns_since (entry_last);
211918334Speter  return 0;
212018334Speter}
212118334Speter
212218334Speter/* Generate code to perform an operation specified by UNOPTAB
212318334Speter   on operand OP0, with result having machine-mode MODE.
212418334Speter
212518334Speter   UNSIGNEDP is for the case where we have to widen the operands
212618334Speter   to perform the operation.  It says to use zero-extension.
212718334Speter
212818334Speter   If TARGET is nonzero, the value
212918334Speter   is generated there, if it is convenient to do so.
213018334Speter   In all cases an rtx is returned for the locus of the value;
213118334Speter   this may or may not be TARGET.  */
213218334Speter
213318334Speterrtx
213418334Speterexpand_unop (mode, unoptab, op0, target, unsignedp)
213518334Speter     enum machine_mode mode;
213618334Speter     optab unoptab;
213718334Speter     rtx op0;
213818334Speter     rtx target;
213918334Speter     int unsignedp;
214018334Speter{
214118334Speter  enum mode_class class;
214218334Speter  enum machine_mode wider_mode;
214318334Speter  register rtx temp;
214418334Speter  rtx last = get_last_insn ();
214518334Speter  rtx pat;
214618334Speter
214718334Speter  class = GET_MODE_CLASS (mode);
214818334Speter
214918334Speter  op0 = protect_from_queue (op0, 0);
215018334Speter
215118334Speter  if (flag_force_mem)
215218334Speter    {
215318334Speter      op0 = force_not_mem (op0);
215418334Speter    }
215518334Speter
215618334Speter  if (target)
215718334Speter    target = protect_from_queue (target, 1);
215818334Speter
215918334Speter  if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
216018334Speter    {
216118334Speter      int icode = (int) unoptab->handlers[(int) mode].insn_code;
216218334Speter      enum machine_mode mode0 = insn_operand_mode[icode][1];
216318334Speter      rtx xop0 = op0;
216418334Speter
216518334Speter      if (target)
216618334Speter	temp = target;
216718334Speter      else
216818334Speter	temp = gen_reg_rtx (mode);
216918334Speter
217018334Speter      if (GET_MODE (xop0) != VOIDmode
217118334Speter	  && GET_MODE (xop0) != mode0)
217218334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
217318334Speter
217418334Speter      /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
217518334Speter
217618334Speter      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
217718334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
217818334Speter
217918334Speter      if (! (*insn_operand_predicate[icode][0]) (temp, mode))
218018334Speter	temp = gen_reg_rtx (mode);
218118334Speter
218218334Speter      pat = GEN_FCN (icode) (temp, xop0);
218318334Speter      if (pat)
218418334Speter	{
218518334Speter	  if (GET_CODE (pat) == SEQUENCE
218618334Speter	      && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX))
218718334Speter	    {
218818334Speter	      delete_insns_since (last);
218918334Speter	      return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp);
219018334Speter	    }
219118334Speter
219218334Speter	  emit_insn (pat);
219318334Speter
219418334Speter	  return temp;
219518334Speter	}
219618334Speter      else
219718334Speter	delete_insns_since (last);
219818334Speter    }
219918334Speter
220018334Speter  /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
220118334Speter
220218334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
220318334Speter    for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
220418334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
220518334Speter      {
220618334Speter	if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
220718334Speter	  {
220818334Speter	    rtx xop0 = op0;
220918334Speter
221018334Speter	    /* For certain operations, we need not actually extend
221118334Speter	       the narrow operand, as long as we will truncate the
221218334Speter	       results to the same narrowness.  */
221318334Speter
221418334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
221518334Speter				  (unoptab == neg_optab
221618334Speter				   || unoptab == one_cmpl_optab)
221718334Speter				  && class == MODE_INT);
221818334Speter
221918334Speter	    temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
222018334Speter				unsignedp);
222118334Speter
222218334Speter	    if (temp)
222318334Speter	      {
222418334Speter		if (class != MODE_INT)
222518334Speter		  {
222618334Speter		    if (target == 0)
222718334Speter		      target = gen_reg_rtx (mode);
222818334Speter		    convert_move (target, temp, 0);
222918334Speter		    return target;
223018334Speter		  }
223118334Speter		else
223218334Speter		  return gen_lowpart (mode, temp);
223318334Speter	      }
223418334Speter	    else
223518334Speter	      delete_insns_since (last);
223618334Speter	  }
223718334Speter      }
223818334Speter
223918334Speter  /* These can be done a word at a time.  */
224018334Speter  if (unoptab == one_cmpl_optab
224118334Speter      && class == MODE_INT
224218334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
224318334Speter      && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
224418334Speter    {
224518334Speter      int i;
224618334Speter      rtx insns;
224718334Speter
224818334Speter      if (target == 0 || target == op0)
224918334Speter	target = gen_reg_rtx (mode);
225018334Speter
225118334Speter      start_sequence ();
225218334Speter
225318334Speter      /* Do the actual arithmetic.  */
225418334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
225518334Speter	{
225618334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
225718334Speter	  rtx x = expand_unop (word_mode, unoptab,
225818334Speter			       operand_subword_force (op0, i, mode),
225918334Speter			       target_piece, unsignedp);
226018334Speter	  if (target_piece != x)
226118334Speter	    emit_move_insn (target_piece, x);
226218334Speter	}
226318334Speter
226418334Speter      insns = get_insns ();
226518334Speter      end_sequence ();
226618334Speter
226718334Speter      emit_no_conflict_block (insns, target, op0, NULL_RTX,
226850397Sobrien			      gen_rtx_fmt_e (unoptab->code, mode,
226950397Sobrien					     copy_rtx (op0)));
227018334Speter      return target;
227118334Speter    }
227218334Speter
227318334Speter  /* Open-code the complex negation operation.  */
227418334Speter  else if (unoptab == neg_optab
227518334Speter	   && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT))
227618334Speter    {
227718334Speter      rtx target_piece;
227818334Speter      rtx x;
227918334Speter      rtx seq;
228018334Speter
228118334Speter      /* Find the correct mode for the real and imaginary parts */
228218334Speter      enum machine_mode submode
228318334Speter	= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
228418334Speter			 class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
228518334Speter			 0);
228618334Speter
228718334Speter      if (submode == BLKmode)
228818334Speter	abort ();
228918334Speter
229018334Speter      if (target == 0)
229118334Speter	target = gen_reg_rtx (mode);
229218334Speter
229318334Speter      start_sequence ();
229418334Speter
229518334Speter      target_piece = gen_imagpart (submode, target);
229618334Speter      x = expand_unop (submode, unoptab,
229718334Speter		       gen_imagpart (submode, op0),
229818334Speter		       target_piece, unsignedp);
229918334Speter      if (target_piece != x)
230018334Speter	emit_move_insn (target_piece, x);
230118334Speter
230218334Speter      target_piece = gen_realpart (submode, target);
230318334Speter      x = expand_unop (submode, unoptab,
230418334Speter		       gen_realpart (submode, op0),
230518334Speter		       target_piece, unsignedp);
230618334Speter      if (target_piece != x)
230718334Speter	emit_move_insn (target_piece, x);
230818334Speter
230918334Speter      seq = get_insns ();
231018334Speter      end_sequence ();
231118334Speter
231218334Speter      emit_no_conflict_block (seq, target, op0, 0,
231350397Sobrien			      gen_rtx_fmt_e (unoptab->code, mode,
231450397Sobrien					     copy_rtx (op0)));
231518334Speter      return target;
231618334Speter    }
231718334Speter
231818334Speter  /* Now try a library call in this mode.  */
231918334Speter  if (unoptab->handlers[(int) mode].libfunc)
232018334Speter    {
232118334Speter      rtx insns;
232218334Speter      rtx value;
232318334Speter
232418334Speter      start_sequence ();
232518334Speter
232618334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
232718334Speter	 if the libcall is cse'd or moved.  */
232818334Speter      value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
232918334Speter				       NULL_RTX, 1, mode, 1, op0, mode);
233018334Speter      insns = get_insns ();
233118334Speter      end_sequence ();
233218334Speter
233318334Speter      target = gen_reg_rtx (mode);
233418334Speter      emit_libcall_block (insns, target, value,
233550397Sobrien			  gen_rtx_fmt_e (unoptab->code, mode, op0));
233618334Speter
233718334Speter      return target;
233818334Speter    }
233918334Speter
234018334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
234118334Speter
234218334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
234318334Speter    {
234418334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
234518334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
234618334Speter	{
234718334Speter	  if ((unoptab->handlers[(int) wider_mode].insn_code
234818334Speter	       != CODE_FOR_nothing)
234918334Speter	      || unoptab->handlers[(int) wider_mode].libfunc)
235018334Speter	    {
235118334Speter	      rtx xop0 = op0;
235218334Speter
235318334Speter	      /* For certain operations, we need not actually extend
235418334Speter		 the narrow operand, as long as we will truncate the
235518334Speter		 results to the same narrowness.  */
235618334Speter
235718334Speter	      xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
235818334Speter				    (unoptab == neg_optab
235918334Speter				     || unoptab == one_cmpl_optab)
236018334Speter				    && class == MODE_INT);
236118334Speter
236218334Speter	      temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
236318334Speter				  unsignedp);
236418334Speter
236518334Speter	      if (temp)
236618334Speter		{
236718334Speter		  if (class != MODE_INT)
236818334Speter		    {
236918334Speter		      if (target == 0)
237018334Speter			target = gen_reg_rtx (mode);
237118334Speter		      convert_move (target, temp, 0);
237218334Speter		      return target;
237318334Speter		    }
237418334Speter		  else
237518334Speter		    return gen_lowpart (mode, temp);
237618334Speter		}
237718334Speter	      else
237818334Speter		delete_insns_since (last);
237918334Speter	    }
238018334Speter	}
238118334Speter    }
238218334Speter
238318334Speter  /* If there is no negate operation, try doing a subtract from zero.
238418334Speter     The US Software GOFAST library needs this.  */
238518334Speter  if (unoptab == neg_optab)
238618334Speter    {
238718334Speter      rtx temp;
238818334Speter      temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
238918334Speter			   target, unsignedp, OPTAB_LIB_WIDEN);
239018334Speter      if (temp)
239118334Speter	return temp;
239218334Speter    }
239318334Speter
239418334Speter  return 0;
239518334Speter}
239618334Speter
239718334Speter/* Emit code to compute the absolute value of OP0, with result to
239818334Speter   TARGET if convenient.  (TARGET may be 0.)  The return value says
239918334Speter   where the result actually is to be found.
240018334Speter
240118334Speter   MODE is the mode of the operand; the mode of the result is
240218334Speter   different but can be deduced from MODE.
240318334Speter
240452284Sobrien */
240518334Speter
240618334Speterrtx
240752284Sobrienexpand_abs (mode, op0, target, safe)
240818334Speter     enum machine_mode mode;
240918334Speter     rtx op0;
241018334Speter     rtx target;
241118334Speter     int safe;
241218334Speter{
241318334Speter  rtx temp, op1;
241418334Speter
241518334Speter  /* First try to do it with a special abs instruction.  */
241618334Speter  temp = expand_unop (mode, abs_optab, op0, target, 0);
241718334Speter  if (temp != 0)
241818334Speter    return temp;
241918334Speter
242018334Speter  /* If this machine has expensive jumps, we can do integer absolute
242118334Speter     value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
242218334Speter     where W is the width of MODE.  */
242318334Speter
242418334Speter  if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
242518334Speter    {
242618334Speter      rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
242718334Speter				   size_int (GET_MODE_BITSIZE (mode) - 1),
242818334Speter				   NULL_RTX, 0);
242918334Speter
243018334Speter      temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
243118334Speter			   OPTAB_LIB_WIDEN);
243218334Speter      if (temp != 0)
243318334Speter	temp = expand_binop (mode, sub_optab, temp, extended, target, 0,
243418334Speter			     OPTAB_LIB_WIDEN);
243518334Speter
243618334Speter      if (temp != 0)
243718334Speter	return temp;
243818334Speter    }
243918334Speter
244018334Speter  /* If that does not win, use conditional jump and negate.  */
244150397Sobrien
244250397Sobrien  /* It is safe to use the target if it is the same
244350397Sobrien     as the source if this is also a pseudo register */
244450397Sobrien  if (op0 == target && GET_CODE (op0) == REG
244550397Sobrien      && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
244650397Sobrien    safe = 1;
244750397Sobrien
244818334Speter  op1 = gen_label_rtx ();
244918334Speter  if (target == 0 || ! safe
245018334Speter      || GET_MODE (target) != mode
245118334Speter      || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
245218334Speter      || (GET_CODE (target) == REG
245318334Speter	  && REGNO (target) < FIRST_PSEUDO_REGISTER))
245418334Speter    target = gen_reg_rtx (mode);
245518334Speter
245618334Speter  emit_move_insn (target, op0);
245718334Speter  NO_DEFER_POP;
245818334Speter
245918334Speter  /* If this mode is an integer too wide to compare properly,
246018334Speter     compare word by word.  Rely on CSE to optimize constant cases.  */
246118334Speter  if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
246218334Speter    do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
246318334Speter				  NULL_RTX, op1);
246418334Speter  else
246518334Speter    {
246618334Speter      temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode,
246718334Speter			       NULL_RTX, 0);
246818334Speter      if (temp == const1_rtx)
246918334Speter	return target;
247018334Speter      else if (temp != const0_rtx)
247118334Speter	{
247218334Speter	  if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
247318334Speter	    emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1));
247418334Speter	  else
247518334Speter	    abort ();
247618334Speter	}
247718334Speter    }
247818334Speter
247918334Speter  op0 = expand_unop (mode, neg_optab, target, target, 0);
248018334Speter  if (op0 != target)
248118334Speter    emit_move_insn (target, op0);
248218334Speter  emit_label (op1);
248318334Speter  OK_DEFER_POP;
248418334Speter  return target;
248518334Speter}
248618334Speter
248718334Speter/* Emit code to compute the absolute value of OP0, with result to
248818334Speter   TARGET if convenient.  (TARGET may be 0.)  The return value says
248918334Speter   where the result actually is to be found.
249018334Speter
249118334Speter   MODE is the mode of the operand; the mode of the result is
249218334Speter   different but can be deduced from MODE.
249318334Speter
249418334Speter   UNSIGNEDP is relevant for complex integer modes.  */
249518334Speter
249618334Speterrtx
249718334Speterexpand_complex_abs (mode, op0, target, unsignedp)
249818334Speter     enum machine_mode mode;
249918334Speter     rtx op0;
250018334Speter     rtx target;
250118334Speter     int unsignedp;
250218334Speter{
250318334Speter  enum mode_class class = GET_MODE_CLASS (mode);
250418334Speter  enum machine_mode wider_mode;
250518334Speter  register rtx temp;
250618334Speter  rtx entry_last = get_last_insn ();
250718334Speter  rtx last;
250818334Speter  rtx pat;
250918334Speter
251018334Speter  /* Find the correct mode for the real and imaginary parts.  */
251118334Speter  enum machine_mode submode
251218334Speter    = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
251318334Speter		     class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
251418334Speter		     0);
251518334Speter
251618334Speter  if (submode == BLKmode)
251718334Speter    abort ();
251818334Speter
251918334Speter  op0 = protect_from_queue (op0, 0);
252018334Speter
252118334Speter  if (flag_force_mem)
252218334Speter    {
252318334Speter      op0 = force_not_mem (op0);
252418334Speter    }
252518334Speter
252618334Speter  last = get_last_insn ();
252718334Speter
252818334Speter  if (target)
252918334Speter    target = protect_from_queue (target, 1);
253018334Speter
253118334Speter  if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
253218334Speter    {
253318334Speter      int icode = (int) abs_optab->handlers[(int) mode].insn_code;
253418334Speter      enum machine_mode mode0 = insn_operand_mode[icode][1];
253518334Speter      rtx xop0 = op0;
253618334Speter
253718334Speter      if (target)
253818334Speter	temp = target;
253918334Speter      else
254018334Speter	temp = gen_reg_rtx (submode);
254118334Speter
254218334Speter      if (GET_MODE (xop0) != VOIDmode
254318334Speter	  && GET_MODE (xop0) != mode0)
254418334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
254518334Speter
254618334Speter      /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
254718334Speter
254818334Speter      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
254918334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
255018334Speter
255118334Speter      if (! (*insn_operand_predicate[icode][0]) (temp, submode))
255218334Speter	temp = gen_reg_rtx (submode);
255318334Speter
255418334Speter      pat = GEN_FCN (icode) (temp, xop0);
255518334Speter      if (pat)
255618334Speter	{
255718334Speter	  if (GET_CODE (pat) == SEQUENCE
255818334Speter	      && ! add_equal_note (pat, temp, abs_optab->code, xop0, NULL_RTX))
255918334Speter	    {
256018334Speter	      delete_insns_since (last);
256118334Speter	      return expand_unop (mode, abs_optab, op0, NULL_RTX, unsignedp);
256218334Speter	    }
256318334Speter
256418334Speter	  emit_insn (pat);
256518334Speter
256618334Speter	  return temp;
256718334Speter	}
256818334Speter      else
256918334Speter	delete_insns_since (last);
257018334Speter    }
257118334Speter
257218334Speter  /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
257318334Speter
257418334Speter  for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
257518334Speter       wider_mode = GET_MODE_WIDER_MODE (wider_mode))
257618334Speter    {
257718334Speter      if (abs_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
257818334Speter	{
257918334Speter	  rtx xop0 = op0;
258018334Speter
258118334Speter	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
258218334Speter	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
258318334Speter
258418334Speter	  if (temp)
258518334Speter	    {
258618334Speter	      if (class != MODE_COMPLEX_INT)
258718334Speter		{
258818334Speter		  if (target == 0)
258918334Speter		    target = gen_reg_rtx (submode);
259018334Speter		  convert_move (target, temp, 0);
259118334Speter		  return target;
259218334Speter		}
259318334Speter	      else
259418334Speter		return gen_lowpart (submode, temp);
259518334Speter	    }
259618334Speter	  else
259718334Speter	    delete_insns_since (last);
259818334Speter	}
259918334Speter    }
260018334Speter
260118334Speter  /* Open-code the complex absolute-value operation
260218334Speter     if we can open-code sqrt.  Otherwise it's not worth while.  */
260318334Speter  if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing)
260418334Speter    {
260518334Speter      rtx real, imag, total;
260618334Speter
260718334Speter      real = gen_realpart (submode, op0);
260818334Speter      imag = gen_imagpart (submode, op0);
260918334Speter
261018334Speter      /* Square both parts.  */
261118334Speter      real = expand_mult (submode, real, real, NULL_RTX, 0);
261218334Speter      imag = expand_mult (submode, imag, imag, NULL_RTX, 0);
261318334Speter
261418334Speter      /* Sum the parts.  */
261518334Speter      total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
261618334Speter			    0, OPTAB_LIB_WIDEN);
261718334Speter
261818334Speter      /* Get sqrt in TARGET.  Set TARGET to where the result is.  */
261918334Speter      target = expand_unop (submode, sqrt_optab, total, target, 0);
262018334Speter      if (target == 0)
262118334Speter	delete_insns_since (last);
262218334Speter      else
262318334Speter	return target;
262418334Speter    }
262518334Speter
262618334Speter  /* Now try a library call in this mode.  */
262718334Speter  if (abs_optab->handlers[(int) mode].libfunc)
262818334Speter    {
262918334Speter      rtx insns;
263018334Speter      rtx value;
263118334Speter
263218334Speter      start_sequence ();
263318334Speter
263418334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
263518334Speter	 if the libcall is cse'd or moved.  */
263618334Speter      value = emit_library_call_value (abs_optab->handlers[(int) mode].libfunc,
263718334Speter				       NULL_RTX, 1, submode, 1, op0, mode);
263818334Speter      insns = get_insns ();
263918334Speter      end_sequence ();
264018334Speter
264118334Speter      target = gen_reg_rtx (submode);
264218334Speter      emit_libcall_block (insns, target, value,
264350397Sobrien			  gen_rtx_fmt_e (abs_optab->code, mode, op0));
264418334Speter
264518334Speter      return target;
264618334Speter    }
264718334Speter
264818334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
264918334Speter
265018334Speter  for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
265118334Speter       wider_mode = GET_MODE_WIDER_MODE (wider_mode))
265218334Speter    {
265318334Speter      if ((abs_optab->handlers[(int) wider_mode].insn_code
265418334Speter	   != CODE_FOR_nothing)
265518334Speter	  || abs_optab->handlers[(int) wider_mode].libfunc)
265618334Speter	{
265718334Speter	  rtx xop0 = op0;
265818334Speter
265918334Speter	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
266018334Speter
266118334Speter	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
266218334Speter
266318334Speter	  if (temp)
266418334Speter	    {
266518334Speter	      if (class != MODE_COMPLEX_INT)
266618334Speter		{
266718334Speter		  if (target == 0)
266818334Speter		    target = gen_reg_rtx (submode);
266918334Speter		  convert_move (target, temp, 0);
267018334Speter		  return target;
267118334Speter		}
267218334Speter	      else
267318334Speter		return gen_lowpart (submode, temp);
267418334Speter	    }
267518334Speter	  else
267618334Speter	    delete_insns_since (last);
267718334Speter	}
267818334Speter    }
267918334Speter
268018334Speter  delete_insns_since (entry_last);
268118334Speter  return 0;
268218334Speter}
268318334Speter
268418334Speter/* Generate an instruction whose insn-code is INSN_CODE,
268518334Speter   with two operands: an output TARGET and an input OP0.
268618334Speter   TARGET *must* be nonzero, and the output is always stored there.
268718334Speter   CODE is an rtx code such that (CODE OP0) is an rtx that describes
268818334Speter   the value that is stored into TARGET.  */
268918334Speter
269018334Spetervoid
269118334Speteremit_unop_insn (icode, target, op0, code)
269218334Speter     int icode;
269318334Speter     rtx target;
269418334Speter     rtx op0;
269518334Speter     enum rtx_code code;
269618334Speter{
269718334Speter  register rtx temp;
269818334Speter  enum machine_mode mode0 = insn_operand_mode[icode][1];
269918334Speter  rtx pat;
270018334Speter
270118334Speter  temp = target = protect_from_queue (target, 1);
270218334Speter
270318334Speter  op0 = protect_from_queue (op0, 0);
270418334Speter
270550397Sobrien  /* Sign and zero extension from memory is often done specially on
270650397Sobrien     RISC machines, so forcing into a register here can pessimize
270750397Sobrien     code.  */
270850397Sobrien  if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND)
270918334Speter    op0 = force_not_mem (op0);
271018334Speter
271118334Speter  /* Now, if insn does not accept our operands, put them into pseudos.  */
271218334Speter
271318334Speter  if (! (*insn_operand_predicate[icode][1]) (op0, mode0))
271418334Speter    op0 = copy_to_mode_reg (mode0, op0);
271518334Speter
271618334Speter  if (! (*insn_operand_predicate[icode][0]) (temp, GET_MODE (temp))
271718334Speter      || (flag_force_mem && GET_CODE (temp) == MEM))
271818334Speter    temp = gen_reg_rtx (GET_MODE (temp));
271918334Speter
272018334Speter  pat = GEN_FCN (icode) (temp, op0);
272118334Speter
272218334Speter  if (GET_CODE (pat) == SEQUENCE && code != UNKNOWN)
272318334Speter    add_equal_note (pat, temp, code, op0, NULL_RTX);
272418334Speter
272518334Speter  emit_insn (pat);
272618334Speter
272718334Speter  if (temp != target)
272818334Speter    emit_move_insn (target, temp);
272918334Speter}
273018334Speter
273118334Speter/* Emit code to perform a series of operations on a multi-word quantity, one
273218334Speter   word at a time.
273318334Speter
273418334Speter   Such a block is preceded by a CLOBBER of the output, consists of multiple
273518334Speter   insns, each setting one word of the output, and followed by a SET copying
273618334Speter   the output to itself.
273718334Speter
273818334Speter   Each of the insns setting words of the output receives a REG_NO_CONFLICT
273918334Speter   note indicating that it doesn't conflict with the (also multi-word)
274018334Speter   inputs.  The entire block is surrounded by REG_LIBCALL and REG_RETVAL
274118334Speter   notes.
274218334Speter
274318334Speter   INSNS is a block of code generated to perform the operation, not including
274418334Speter   the CLOBBER and final copy.  All insns that compute intermediate values
274518334Speter   are first emitted, followed by the block as described above.
274618334Speter
274718334Speter   TARGET, OP0, and OP1 are the output and inputs of the operations,
274818334Speter   respectively.  OP1 may be zero for a unary operation.
274918334Speter
275018334Speter   EQUIV, if non-zero, is an expression to be placed into a REG_EQUAL note
275118334Speter   on the last insn.
275218334Speter
275318334Speter   If TARGET is not a register, INSNS is simply emitted with no special
275418334Speter   processing.  Likewise if anything in INSNS is not an INSN or if
275518334Speter   there is a libcall block inside INSNS.
275618334Speter
275718334Speter   The final insn emitted is returned.  */
275818334Speter
275918334Speterrtx
276018334Speteremit_no_conflict_block (insns, target, op0, op1, equiv)
276118334Speter     rtx insns;
276218334Speter     rtx target;
276318334Speter     rtx op0, op1;
276418334Speter     rtx equiv;
276518334Speter{
276618334Speter  rtx prev, next, first, last, insn;
276718334Speter
276818334Speter  if (GET_CODE (target) != REG || reload_in_progress)
276918334Speter    return emit_insns (insns);
277018334Speter  else
277118334Speter    for (insn = insns; insn; insn = NEXT_INSN (insn))
277218334Speter      if (GET_CODE (insn) != INSN
277318334Speter	  || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
277418334Speter	return emit_insns (insns);
277518334Speter
277618334Speter  /* First emit all insns that do not store into words of the output and remove
277718334Speter     these from the list.  */
277818334Speter  for (insn = insns; insn; insn = next)
277918334Speter    {
278018334Speter      rtx set = 0;
278118334Speter      int i;
278218334Speter
278318334Speter      next = NEXT_INSN (insn);
278418334Speter
278518334Speter      if (GET_CODE (PATTERN (insn)) == SET)
278618334Speter	set = PATTERN (insn);
278718334Speter      else if (GET_CODE (PATTERN (insn)) == PARALLEL)
278818334Speter	{
278918334Speter	  for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
279018334Speter	    if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
279118334Speter	      {
279218334Speter		set = XVECEXP (PATTERN (insn), 0, i);
279318334Speter		break;
279418334Speter	      }
279518334Speter	}
279618334Speter
279718334Speter      if (set == 0)
279818334Speter	abort ();
279918334Speter
280018334Speter      if (! reg_overlap_mentioned_p (target, SET_DEST (set)))
280118334Speter	{
280218334Speter	  if (PREV_INSN (insn))
280318334Speter	    NEXT_INSN (PREV_INSN (insn)) = next;
280418334Speter	  else
280518334Speter	    insns = next;
280618334Speter
280718334Speter	  if (next)
280818334Speter	    PREV_INSN (next) = PREV_INSN (insn);
280918334Speter
281018334Speter	  add_insn (insn);
281118334Speter	}
281218334Speter    }
281318334Speter
281418334Speter  prev = get_last_insn ();
281518334Speter
281618334Speter  /* Now write the CLOBBER of the output, followed by the setting of each
281718334Speter     of the words, followed by the final copy.  */
281818334Speter  if (target != op0 && target != op1)
281950397Sobrien    emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
282018334Speter
282118334Speter  for (insn = insns; insn; insn = next)
282218334Speter    {
282318334Speter      next = NEXT_INSN (insn);
282418334Speter      add_insn (insn);
282518334Speter
282618334Speter      if (op1 && GET_CODE (op1) == REG)
282750397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
282850397Sobrien					      REG_NOTES (insn));
282918334Speter
283018334Speter      if (op0 && GET_CODE (op0) == REG)
283150397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
283250397Sobrien					      REG_NOTES (insn));
283318334Speter    }
283418334Speter
283518334Speter  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
283618334Speter      != CODE_FOR_nothing)
283718334Speter    {
283818334Speter      last = emit_move_insn (target, target);
283918334Speter      if (equiv)
284052284Sobrien	set_unique_reg_note (last, REG_EQUAL, equiv);
284118334Speter    }
284218334Speter  else
284318334Speter    last = get_last_insn ();
284418334Speter
284518334Speter  if (prev == 0)
284618334Speter    first = get_insns ();
284718334Speter  else
284818334Speter    first = NEXT_INSN (prev);
284918334Speter
285018334Speter  /* Encapsulate the block so it gets manipulated as a unit.  */
285150397Sobrien  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
285250397Sobrien					 REG_NOTES (first));
285350397Sobrien  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
285418334Speter
285518334Speter  return last;
285618334Speter}
285718334Speter
285818334Speter/* Emit code to make a call to a constant function or a library call.
285918334Speter
286018334Speter   INSNS is a list containing all insns emitted in the call.
286118334Speter   These insns leave the result in RESULT.  Our block is to copy RESULT
286218334Speter   to TARGET, which is logically equivalent to EQUIV.
286318334Speter
286418334Speter   We first emit any insns that set a pseudo on the assumption that these are
286518334Speter   loading constants into registers; doing so allows them to be safely cse'ed
286618334Speter   between blocks.  Then we emit all the other insns in the block, followed by
286718334Speter   an insn to move RESULT to TARGET.  This last insn will have a REQ_EQUAL
286818334Speter   note with an operand of EQUIV.
286918334Speter
287018334Speter   Moving assignments to pseudos outside of the block is done to improve
287118334Speter   the generated code, but is not required to generate correct code,
287218334Speter   hence being unable to move an assignment is not grounds for not making
287318334Speter   a libcall block.  There are two reasons why it is safe to leave these
287418334Speter   insns inside the block: First, we know that these pseudos cannot be
287518334Speter   used in generated RTL outside the block since they are created for
287618334Speter   temporary purposes within the block.  Second, CSE will not record the
287718334Speter   values of anything set inside a libcall block, so we know they must
287818334Speter   be dead at the end of the block.
287918334Speter
288018334Speter   Except for the first group of insns (the ones setting pseudos), the
288118334Speter   block is delimited by REG_RETVAL and REG_LIBCALL notes.  */
288218334Speter
288318334Spetervoid
288418334Speteremit_libcall_block (insns, target, result, equiv)
288518334Speter     rtx insns;
288618334Speter     rtx target;
288718334Speter     rtx result;
288818334Speter     rtx equiv;
288918334Speter{
289018334Speter  rtx prev, next, first, last, insn;
289118334Speter
289252284Sobrien  /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION
289352284Sobrien     reg note to indicate that this call cannot throw. (Unless there is
289452284Sobrien     already a REG_EH_REGION note.) */
289552284Sobrien
289652284Sobrien  for (insn = insns; insn; insn = NEXT_INSN (insn))
289752284Sobrien    {
289852284Sobrien      if (GET_CODE (insn) == CALL_INSN)
289952284Sobrien        {
290052284Sobrien          rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
290152284Sobrien          if (note == NULL_RTX)
290252284Sobrien            REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1),
290352284Sobrien                                                  REG_NOTES (insn));
290452284Sobrien        }
290552284Sobrien    }
290652284Sobrien
290718334Speter  /* First emit all insns that set pseudos.  Remove them from the list as
290818334Speter     we go.  Avoid insns that set pseudos which were referenced in previous
290918334Speter     insns.  These can be generated by move_by_pieces, for example,
291018334Speter     to update an address.  Similarly, avoid insns that reference things
291118334Speter     set in previous insns.  */
291218334Speter
291318334Speter  for (insn = insns; insn; insn = next)
291418334Speter    {
291518334Speter      rtx set = single_set (insn);
291618334Speter
291718334Speter      next = NEXT_INSN (insn);
291818334Speter
291918334Speter      if (set != 0 && GET_CODE (SET_DEST (set)) == REG
292018334Speter	  && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
292118334Speter	  && (insn == insns
292218334Speter	      || (! reg_mentioned_p (SET_DEST (set), PATTERN (insns))
292318334Speter		  && ! reg_used_between_p (SET_DEST (set), insns, insn)
292418334Speter		  && ! modified_in_p (SET_SRC (set), insns)
292518334Speter		  && ! modified_between_p (SET_SRC (set), insns, insn))))
292618334Speter	{
292718334Speter	  if (PREV_INSN (insn))
292818334Speter	    NEXT_INSN (PREV_INSN (insn)) = next;
292918334Speter	  else
293018334Speter	    insns = next;
293118334Speter
293218334Speter	  if (next)
293318334Speter	    PREV_INSN (next) = PREV_INSN (insn);
293418334Speter
293518334Speter	  add_insn (insn);
293618334Speter	}
293718334Speter    }
293818334Speter
293918334Speter  prev = get_last_insn ();
294018334Speter
294118334Speter  /* Write the remaining insns followed by the final copy.  */
294218334Speter
294318334Speter  for (insn = insns; insn; insn = next)
294418334Speter    {
294518334Speter      next = NEXT_INSN (insn);
294618334Speter
294718334Speter      add_insn (insn);
294818334Speter    }
294918334Speter
295018334Speter  last = emit_move_insn (target, result);
295150397Sobrien  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
295250397Sobrien      != CODE_FOR_nothing)
295352284Sobrien    set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
295418334Speter
295518334Speter  if (prev == 0)
295618334Speter    first = get_insns ();
295718334Speter  else
295818334Speter    first = NEXT_INSN (prev);
295918334Speter
296018334Speter  /* Encapsulate the block so it gets manipulated as a unit.  */
296150397Sobrien  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
296250397Sobrien					 REG_NOTES (first));
296350397Sobrien  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
296418334Speter}
296518334Speter
296618334Speter/* Generate code to store zero in X.  */
296718334Speter
296818334Spetervoid
296918334Speteremit_clr_insn (x)
297018334Speter     rtx x;
297118334Speter{
297218334Speter  emit_move_insn (x, const0_rtx);
297318334Speter}
297418334Speter
297518334Speter/* Generate code to store 1 in X
297618334Speter   assuming it contains zero beforehand.  */
297718334Speter
297818334Spetervoid
297918334Speteremit_0_to_1_insn (x)
298018334Speter     rtx x;
298118334Speter{
298218334Speter  emit_move_insn (x, const1_rtx);
298318334Speter}
298418334Speter
298518334Speter/* Generate code to compare X with Y
298618334Speter   so that the condition codes are set.
298718334Speter
298818334Speter   MODE is the mode of the inputs (in case they are const_int).
298918334Speter   UNSIGNEDP nonzero says that X and Y are unsigned;
299018334Speter   this matters if they need to be widened.
299118334Speter
299218334Speter   If they have mode BLKmode, then SIZE specifies the size of both X and Y,
299318334Speter   and ALIGN specifies the known shared alignment of X and Y.
299418334Speter
299518334Speter   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
299618334Speter   It is ignored for fixed-point and block comparisons;
299718334Speter   it is used only for floating-point comparisons.  */
299818334Speter
299918334Spetervoid
300018334Speteremit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
300118334Speter     rtx x, y;
300218334Speter     enum rtx_code comparison;
300318334Speter     rtx size;
300418334Speter     enum machine_mode mode;
300518334Speter     int unsignedp;
300618334Speter     int align;
300718334Speter{
300818334Speter  enum mode_class class;
300918334Speter  enum machine_mode wider_mode;
301018334Speter
301118334Speter  class = GET_MODE_CLASS (mode);
301218334Speter
301318334Speter  /* They could both be VOIDmode if both args are immediate constants,
301418334Speter     but we should fold that at an earlier stage.
301518334Speter     With no special code here, this will call abort,
301618334Speter     reminding the programmer to implement such folding.  */
301718334Speter
301818334Speter  if (mode != BLKmode && flag_force_mem)
301918334Speter    {
302018334Speter      x = force_not_mem (x);
302118334Speter      y = force_not_mem (y);
302218334Speter    }
302318334Speter
302418334Speter  /* If we are inside an appropriately-short loop and one operand is an
302518334Speter     expensive constant, force it into a register.  */
302618334Speter  if (CONSTANT_P (x) && preserve_subexpressions_p () && rtx_cost (x, COMPARE) > 2)
302718334Speter    x = force_reg (mode, x);
302818334Speter
302918334Speter  if (CONSTANT_P (y) && preserve_subexpressions_p () && rtx_cost (y, COMPARE) > 2)
303018334Speter    y = force_reg (mode, y);
303118334Speter
303252284Sobrien#ifdef HAVE_cc0
303352284Sobrien  /* Abort if we have a non-canonical comparison.  The RTL documentation
303452284Sobrien     states that canonical comparisons are required only for targets which
303552284Sobrien     have cc0.  */
303652284Sobrien  if (CONSTANT_P (x) && ! CONSTANT_P (y))
303752284Sobrien    abort();
303852284Sobrien#endif
303952284Sobrien
304018334Speter  /* Don't let both operands fail to indicate the mode.  */
304118334Speter  if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode)
304218334Speter    x = force_reg (mode, x);
304318334Speter
304418334Speter  /* Handle all BLKmode compares.  */
304518334Speter
304618334Speter  if (mode == BLKmode)
304718334Speter    {
304818334Speter      emit_queue ();
304918334Speter      x = protect_from_queue (x, 0);
305018334Speter      y = protect_from_queue (y, 0);
305118334Speter
305218334Speter      if (size == 0)
305318334Speter	abort ();
305418334Speter#ifdef HAVE_cmpstrqi
305518334Speter      if (HAVE_cmpstrqi
305618334Speter	  && GET_CODE (size) == CONST_INT
305718334Speter	  && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
305818334Speter	{
305918334Speter	  enum machine_mode result_mode
306018334Speter	    = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
306118334Speter	  rtx result = gen_reg_rtx (result_mode);
306218334Speter	  emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align)));
306318334Speter	  emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
306418334Speter			 result_mode, 0, 0);
306518334Speter	}
306618334Speter      else
306718334Speter#endif
306818334Speter#ifdef HAVE_cmpstrhi
306918334Speter      if (HAVE_cmpstrhi
307018334Speter	  && GET_CODE (size) == CONST_INT
307118334Speter	  && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
307218334Speter	{
307318334Speter	  enum machine_mode result_mode
307418334Speter	    = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
307518334Speter	  rtx result = gen_reg_rtx (result_mode);
307618334Speter	  emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align)));
307718334Speter	  emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
307818334Speter			 result_mode, 0, 0);
307918334Speter	}
308018334Speter      else
308118334Speter#endif
308218334Speter#ifdef HAVE_cmpstrsi
308318334Speter      if (HAVE_cmpstrsi)
308418334Speter	{
308518334Speter	  enum machine_mode result_mode
308618334Speter	    = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
308718334Speter	  rtx result = gen_reg_rtx (result_mode);
308818334Speter	  size = protect_from_queue (size, 0);
308918334Speter	  emit_insn (gen_cmpstrsi (result, x, y,
309018334Speter				   convert_to_mode (SImode, size, 1),
309118334Speter				   GEN_INT (align)));
309218334Speter	  emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
309318334Speter			 result_mode, 0, 0);
309418334Speter	}
309518334Speter      else
309618334Speter#endif
309718334Speter	{
309850397Sobrien	  rtx result;
309950397Sobrien
310018334Speter#ifdef TARGET_MEM_FUNCTIONS
310118334Speter	  emit_library_call (memcmp_libfunc, 0,
310218334Speter			     TYPE_MODE (integer_type_node), 3,
310318334Speter			     XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
310450397Sobrien			     convert_to_mode (TYPE_MODE (sizetype), size,
310550397Sobrien					      TREE_UNSIGNED (sizetype)),
310650397Sobrien			     TYPE_MODE (sizetype));
310718334Speter#else
310818334Speter	  emit_library_call (bcmp_libfunc, 0,
310918334Speter			     TYPE_MODE (integer_type_node), 3,
311018334Speter			     XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
311150397Sobrien			     convert_to_mode (TYPE_MODE (integer_type_node),
311250397Sobrien					      size,
311350397Sobrien					      TREE_UNSIGNED (integer_type_node)),
311450397Sobrien			     TYPE_MODE (integer_type_node));
311518334Speter#endif
311650397Sobrien
311750397Sobrien	  /* Immediately move the result of the libcall into a pseudo
311850397Sobrien	     register so reload doesn't clobber the value if it needs
311950397Sobrien	     the return register for a spill reg.  */
312050397Sobrien	  result = gen_reg_rtx (TYPE_MODE (integer_type_node));
312150397Sobrien	  emit_move_insn (result,
312250397Sobrien			  hard_libcall_value (TYPE_MODE (integer_type_node)));
312350397Sobrien	  emit_cmp_insn (result,
312418334Speter			 const0_rtx, comparison, NULL_RTX,
312518334Speter			 TYPE_MODE (integer_type_node), 0, 0);
312618334Speter	}
312718334Speter      return;
312818334Speter    }
312918334Speter
313018334Speter  /* Handle some compares against zero.  */
313118334Speter
313218334Speter  if (y == CONST0_RTX (mode)
313318334Speter      && tst_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
313418334Speter    {
313518334Speter      int icode = (int) tst_optab->handlers[(int) mode].insn_code;
313618334Speter
313718334Speter      emit_queue ();
313818334Speter      x = protect_from_queue (x, 0);
313918334Speter      y = protect_from_queue (y, 0);
314018334Speter
314118334Speter      /* Now, if insn does accept these operands, put them into pseudos.  */
314218334Speter      if (! (*insn_operand_predicate[icode][0])
314318334Speter	  (x, insn_operand_mode[icode][0]))
314418334Speter	x = copy_to_mode_reg (insn_operand_mode[icode][0], x);
314518334Speter
314618334Speter      emit_insn (GEN_FCN (icode) (x));
314718334Speter      return;
314818334Speter    }
314918334Speter
315018334Speter  /* Handle compares for which there is a directly suitable insn.  */
315118334Speter
315218334Speter  if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
315318334Speter    {
315418334Speter      int icode = (int) cmp_optab->handlers[(int) mode].insn_code;
315518334Speter
315618334Speter      emit_queue ();
315718334Speter      x = protect_from_queue (x, 0);
315818334Speter      y = protect_from_queue (y, 0);
315918334Speter
316018334Speter      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
316118334Speter      if (! (*insn_operand_predicate[icode][0])
316218334Speter	  (x, insn_operand_mode[icode][0]))
316318334Speter	x = copy_to_mode_reg (insn_operand_mode[icode][0], x);
316418334Speter
316518334Speter      if (! (*insn_operand_predicate[icode][1])
316618334Speter	  (y, insn_operand_mode[icode][1]))
316718334Speter	y = copy_to_mode_reg (insn_operand_mode[icode][1], y);
316818334Speter
316918334Speter      emit_insn (GEN_FCN (icode) (x, y));
317018334Speter      return;
317118334Speter    }
317218334Speter
317318334Speter  /* Try widening if we can find a direct insn that way.  */
317418334Speter
317518334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
317618334Speter    {
317718334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
317818334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
317918334Speter	{
318018334Speter	  if (cmp_optab->handlers[(int) wider_mode].insn_code
318118334Speter	      != CODE_FOR_nothing)
318218334Speter	    {
318318334Speter	      x = protect_from_queue (x, 0);
318418334Speter	      y = protect_from_queue (y, 0);
318518334Speter	      x = convert_modes (wider_mode, mode, x, unsignedp);
318618334Speter	      y = convert_modes (wider_mode, mode, y, unsignedp);
318718334Speter	      emit_cmp_insn (x, y, comparison, NULL_RTX,
318818334Speter			     wider_mode, unsignedp, align);
318918334Speter	      return;
319018334Speter	    }
319118334Speter	}
319218334Speter    }
319318334Speter
319418334Speter  /* Handle a lib call just for the mode we are using.  */
319518334Speter
319618334Speter  if (cmp_optab->handlers[(int) mode].libfunc
319718334Speter      && class != MODE_FLOAT)
319818334Speter    {
319918334Speter      rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
320050397Sobrien      rtx result;
320150397Sobrien
320218334Speter      /* If we want unsigned, and this mode has a distinct unsigned
320318334Speter	 comparison routine, use that.  */
320418334Speter      if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
320518334Speter	libfunc = ucmp_optab->handlers[(int) mode].libfunc;
320618334Speter
320718334Speter      emit_library_call (libfunc, 1,
320818334Speter			 word_mode, 2, x, mode, y, mode);
320918334Speter
321050397Sobrien      /* Immediately move the result of the libcall into a pseudo
321150397Sobrien	 register so reload doesn't clobber the value if it needs
321250397Sobrien	 the return register for a spill reg.  */
321350397Sobrien      result = gen_reg_rtx (word_mode);
321450397Sobrien      emit_move_insn (result, hard_libcall_value (word_mode));
321550397Sobrien
321618334Speter      /* Integer comparison returns a result that must be compared against 1,
321718334Speter	 so that even if we do an unsigned compare afterward,
321818334Speter	 there is still a value that can represent the result "less than".  */
321950397Sobrien      emit_cmp_insn (result, const1_rtx,
322018334Speter		     comparison, NULL_RTX, word_mode, unsignedp, 0);
322118334Speter      return;
322218334Speter    }
322318334Speter
322418334Speter  if (class == MODE_FLOAT)
322518334Speter    emit_float_lib_cmp (x, y, comparison);
322618334Speter
322718334Speter  else
322818334Speter    abort ();
322918334Speter}
323018334Speter
323152284Sobrien/* Generate code to compare X with Y so that the condition codes are
323252284Sobrien   set and to jump to LABEL if the condition is true.  If X is a
323352284Sobrien   constant and Y is not a constant, then the comparison is swapped to
323452284Sobrien   ensure that the comparison RTL has the canonical form.
323552284Sobrien
323652284Sobrien   UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they
323752284Sobrien   need to be widened by emit_cmp_insn.  UNSIGNEDP is also used to select
323852284Sobrien   the proper branch condition code.
323952284Sobrien
324052284Sobrien   If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y,
324152284Sobrien   and ALIGN specifies the known shared alignment of X and Y.
324252284Sobrien
324352284Sobrien   MODE is the mode of the inputs (in case they are const_int).
324452284Sobrien
324552284Sobrien   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  It will
324652284Sobrien   be passed unchanged to emit_cmp_insn, then potentially converted into an
324752284Sobrien   unsigned variant based on UNSIGNEDP to select a proper jump instruction.  */
324852284Sobrien
324952284Sobrienvoid
325052284Sobrienemit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label)
325152284Sobrien     rtx x, y;
325252284Sobrien     enum rtx_code comparison;
325352284Sobrien     rtx size;
325452284Sobrien     enum machine_mode mode;
325552284Sobrien     int unsignedp;
325652284Sobrien     int align;
325752284Sobrien     rtx label;
325852284Sobrien{
325952284Sobrien  rtx op0;
326052284Sobrien  rtx op1;
326152284Sobrien
326252284Sobrien  if (CONSTANT_P (x))
326352284Sobrien    {
326452284Sobrien      /* Swap operands and condition to ensure canonical RTL.  */
326552284Sobrien      op0 = y;
326652284Sobrien      op1 = x;
326752284Sobrien      comparison = swap_condition (comparison);
326852284Sobrien    }
326952284Sobrien  else
327052284Sobrien    {
327152284Sobrien      op0 = x;
327252284Sobrien      op1 = y;
327352284Sobrien    }
327452284Sobrien
327552284Sobrien#ifdef HAVE_cc0
327652284Sobrien  /* If OP0 is still a constant, then both X and Y must be constants.  Force
327752284Sobrien     X into a register to avoid aborting in emit_cmp_insn due to non-canonical
327852284Sobrien     RTL.  */
327952284Sobrien  if (CONSTANT_P (op0))
328052284Sobrien    op0 = force_reg (mode, op0);
328152284Sobrien#endif
328252284Sobrien
328352284Sobrien  emit_cmp_insn (op0, op1, comparison, size, mode, unsignedp, align);
328452284Sobrien
328552284Sobrien  if (unsignedp)
328652284Sobrien    comparison = unsigned_condition (comparison);
328752284Sobrien  emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
328852284Sobrien}
328952284Sobrien
329052284Sobrien
329118334Speter/* Nonzero if a compare of mode MODE can be done straightforwardly
329218334Speter   (without splitting it into pieces).  */
329318334Speter
329418334Speterint
329518334Spetercan_compare_p (mode)
329618334Speter     enum machine_mode mode;
329718334Speter{
329818334Speter  do
329918334Speter    {
330018334Speter      if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
330118334Speter	return 1;
330218334Speter      mode = GET_MODE_WIDER_MODE (mode);
330318334Speter    } while (mode != VOIDmode);
330418334Speter
330518334Speter  return 0;
330618334Speter}
330718334Speter
330818334Speter/* Emit a library call comparison between floating point X and Y.
330918334Speter   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
331018334Speter
331118334Spetervoid
331218334Speteremit_float_lib_cmp (x, y, comparison)
331318334Speter     rtx x, y;
331418334Speter     enum rtx_code comparison;
331518334Speter{
331618334Speter  enum machine_mode mode = GET_MODE (x);
331718334Speter  rtx libfunc = 0;
331850397Sobrien  rtx result;
331918334Speter
332018334Speter  if (mode == HFmode)
332118334Speter    switch (comparison)
332218334Speter      {
332318334Speter      case EQ:
332418334Speter	libfunc = eqhf2_libfunc;
332518334Speter	break;
332618334Speter
332718334Speter      case NE:
332818334Speter	libfunc = nehf2_libfunc;
332918334Speter	break;
333018334Speter
333118334Speter      case GT:
333218334Speter	libfunc = gthf2_libfunc;
333318334Speter	break;
333418334Speter
333518334Speter      case GE:
333618334Speter	libfunc = gehf2_libfunc;
333718334Speter	break;
333818334Speter
333918334Speter      case LT:
334018334Speter	libfunc = lthf2_libfunc;
334118334Speter	break;
334218334Speter
334318334Speter      case LE:
334418334Speter	libfunc = lehf2_libfunc;
334518334Speter	break;
334650397Sobrien
334750397Sobrien      default:
334850397Sobrien	break;
334918334Speter      }
335018334Speter  else if (mode == SFmode)
335118334Speter    switch (comparison)
335218334Speter      {
335318334Speter      case EQ:
335418334Speter	libfunc = eqsf2_libfunc;
335518334Speter	break;
335618334Speter
335718334Speter      case NE:
335818334Speter	libfunc = nesf2_libfunc;
335918334Speter	break;
336018334Speter
336118334Speter      case GT:
336218334Speter	libfunc = gtsf2_libfunc;
336318334Speter	break;
336418334Speter
336518334Speter      case GE:
336618334Speter	libfunc = gesf2_libfunc;
336718334Speter	break;
336818334Speter
336918334Speter      case LT:
337018334Speter	libfunc = ltsf2_libfunc;
337118334Speter	break;
337218334Speter
337318334Speter      case LE:
337418334Speter	libfunc = lesf2_libfunc;
337518334Speter	break;
337650397Sobrien
337750397Sobrien      default:
337850397Sobrien	break;
337918334Speter      }
338018334Speter  else if (mode == DFmode)
338118334Speter    switch (comparison)
338218334Speter      {
338318334Speter      case EQ:
338418334Speter	libfunc = eqdf2_libfunc;
338518334Speter	break;
338618334Speter
338718334Speter      case NE:
338818334Speter	libfunc = nedf2_libfunc;
338918334Speter	break;
339018334Speter
339118334Speter      case GT:
339218334Speter	libfunc = gtdf2_libfunc;
339318334Speter	break;
339418334Speter
339518334Speter      case GE:
339618334Speter	libfunc = gedf2_libfunc;
339718334Speter	break;
339818334Speter
339918334Speter      case LT:
340018334Speter	libfunc = ltdf2_libfunc;
340118334Speter	break;
340218334Speter
340318334Speter      case LE:
340418334Speter	libfunc = ledf2_libfunc;
340518334Speter	break;
340650397Sobrien
340750397Sobrien      default:
340850397Sobrien	break;
340918334Speter      }
341018334Speter  else if (mode == XFmode)
341118334Speter    switch (comparison)
341218334Speter      {
341318334Speter      case EQ:
341418334Speter	libfunc = eqxf2_libfunc;
341518334Speter	break;
341618334Speter
341718334Speter      case NE:
341818334Speter	libfunc = nexf2_libfunc;
341918334Speter	break;
342018334Speter
342118334Speter      case GT:
342218334Speter	libfunc = gtxf2_libfunc;
342318334Speter	break;
342418334Speter
342518334Speter      case GE:
342618334Speter	libfunc = gexf2_libfunc;
342718334Speter	break;
342818334Speter
342918334Speter      case LT:
343018334Speter	libfunc = ltxf2_libfunc;
343118334Speter	break;
343218334Speter
343318334Speter      case LE:
343418334Speter	libfunc = lexf2_libfunc;
343518334Speter	break;
343650397Sobrien
343750397Sobrien      default:
343850397Sobrien	break;
343918334Speter      }
344018334Speter  else if (mode == TFmode)
344118334Speter    switch (comparison)
344218334Speter      {
344318334Speter      case EQ:
344418334Speter	libfunc = eqtf2_libfunc;
344518334Speter	break;
344618334Speter
344718334Speter      case NE:
344818334Speter	libfunc = netf2_libfunc;
344918334Speter	break;
345018334Speter
345118334Speter      case GT:
345218334Speter	libfunc = gttf2_libfunc;
345318334Speter	break;
345418334Speter
345518334Speter      case GE:
345618334Speter	libfunc = getf2_libfunc;
345718334Speter	break;
345818334Speter
345918334Speter      case LT:
346018334Speter	libfunc = lttf2_libfunc;
346118334Speter	break;
346218334Speter
346318334Speter      case LE:
346418334Speter	libfunc = letf2_libfunc;
346518334Speter	break;
346650397Sobrien
346750397Sobrien      default:
346850397Sobrien	break;
346918334Speter      }
347018334Speter  else
347118334Speter    {
347218334Speter      enum machine_mode wider_mode;
347318334Speter
347418334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
347518334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
347618334Speter	{
347718334Speter	  if ((cmp_optab->handlers[(int) wider_mode].insn_code
347818334Speter	       != CODE_FOR_nothing)
347918334Speter	      || (cmp_optab->handlers[(int) wider_mode].libfunc != 0))
348018334Speter	    {
348118334Speter	      x = protect_from_queue (x, 0);
348218334Speter	      y = protect_from_queue (y, 0);
348318334Speter	      x = convert_to_mode (wider_mode, x, 0);
348418334Speter	      y = convert_to_mode (wider_mode, y, 0);
348518334Speter	      emit_float_lib_cmp (x, y, comparison);
348618334Speter	      return;
348718334Speter	    }
348818334Speter	}
348918334Speter      abort ();
349018334Speter    }
349118334Speter
349218334Speter  if (libfunc == 0)
349318334Speter    abort ();
349418334Speter
349518334Speter  emit_library_call (libfunc, 1,
349618334Speter		     word_mode, 2, x, mode, y, mode);
349718334Speter
349850397Sobrien  /* Immediately move the result of the libcall into a pseudo
349950397Sobrien     register so reload doesn't clobber the value if it needs
350050397Sobrien     the return register for a spill reg.  */
350150397Sobrien  result = gen_reg_rtx (word_mode);
350250397Sobrien  emit_move_insn (result, hard_libcall_value (word_mode));
350350397Sobrien
350450397Sobrien  emit_cmp_insn (result, const0_rtx, comparison,
350518334Speter		 NULL_RTX, word_mode, 0, 0);
350618334Speter}
350718334Speter
350818334Speter/* Generate code to indirectly jump to a location given in the rtx LOC.  */
350918334Speter
351018334Spetervoid
351118334Speteremit_indirect_jump (loc)
351218334Speter     rtx loc;
351318334Speter{
351418334Speter  if (! ((*insn_operand_predicate[(int)CODE_FOR_indirect_jump][0])
351518334Speter	 (loc, Pmode)))
351618334Speter    loc = copy_to_mode_reg (Pmode, loc);
351718334Speter
351818334Speter  emit_jump_insn (gen_indirect_jump (loc));
351918334Speter  emit_barrier ();
352018334Speter}
352118334Speter
352218334Speter#ifdef HAVE_conditional_move
352318334Speter
352418334Speter/* Emit a conditional move instruction if the machine supports one for that
352518334Speter   condition and machine mode.
352618334Speter
352718334Speter   OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
352818334Speter   the mode to use should they be constants.  If it is VOIDmode, they cannot
352918334Speter   both be constants.
353018334Speter
353118334Speter   OP2 should be stored in TARGET if the comparison is true, otherwise OP3
353218334Speter   should be stored there.  MODE is the mode to use should they be constants.
353318334Speter   If it is VOIDmode, they cannot both be constants.
353418334Speter
353518334Speter   The result is either TARGET (perhaps modified) or NULL_RTX if the operation
353618334Speter   is not supported.  */
353718334Speter
353818334Speterrtx
353918334Speteremit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
354018334Speter		       unsignedp)
354118334Speter     rtx target;
354218334Speter     enum rtx_code code;
354318334Speter     rtx op0, op1;
354418334Speter     enum machine_mode cmode;
354518334Speter     rtx op2, op3;
354618334Speter     enum machine_mode mode;
354718334Speter     int unsignedp;
354818334Speter{
354918334Speter  rtx tem, subtarget, comparison, insn;
355018334Speter  enum insn_code icode;
355118334Speter
355218334Speter  /* If one operand is constant, make it the second one.  Only do this
355318334Speter     if the other operand is not constant as well.  */
355418334Speter
355518334Speter  if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
355618334Speter      || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
355718334Speter    {
355818334Speter      tem = op0;
355918334Speter      op0 = op1;
356018334Speter      op1 = tem;
356118334Speter      code = swap_condition (code);
356218334Speter    }
356318334Speter
356418334Speter  if (cmode == VOIDmode)
356518334Speter    cmode = GET_MODE (op0);
356618334Speter
356750397Sobrien  if (((CONSTANT_P (op2) && ! CONSTANT_P (op3))
356850397Sobrien       || (GET_CODE (op2) == CONST_INT && GET_CODE (op3) != CONST_INT))
356950397Sobrien      && (GET_MODE_CLASS (GET_MODE (op1)) != MODE_FLOAT
357050397Sobrien	  || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT || flag_fast_math))
357118334Speter    {
357218334Speter      tem = op2;
357318334Speter      op2 = op3;
357418334Speter      op3 = tem;
357518334Speter      code = reverse_condition (code);
357618334Speter    }
357718334Speter
357818334Speter  if (mode == VOIDmode)
357918334Speter    mode = GET_MODE (op2);
358018334Speter
358118334Speter  icode = movcc_gen_code[mode];
358218334Speter
358318334Speter  if (icode == CODE_FOR_nothing)
358418334Speter    return 0;
358518334Speter
358618334Speter  if (flag_force_mem)
358718334Speter    {
358818334Speter      op2 = force_not_mem (op2);
358918334Speter      op3 = force_not_mem (op3);
359018334Speter    }
359118334Speter
359218334Speter  if (target)
359318334Speter    target = protect_from_queue (target, 1);
359418334Speter  else
359518334Speter    target = gen_reg_rtx (mode);
359618334Speter
359718334Speter  subtarget = target;
359818334Speter
359918334Speter  emit_queue ();
360018334Speter
360118334Speter  op2 = protect_from_queue (op2, 0);
360218334Speter  op3 = protect_from_queue (op3, 0);
360318334Speter
360418334Speter  /* If the insn doesn't accept these operands, put them in pseudos.  */
360518334Speter
360618334Speter  if (! (*insn_operand_predicate[icode][0])
360718334Speter      (subtarget, insn_operand_mode[icode][0]))
360818334Speter    subtarget = gen_reg_rtx (insn_operand_mode[icode][0]);
360918334Speter
361018334Speter  if (! (*insn_operand_predicate[icode][2])
361118334Speter      (op2, insn_operand_mode[icode][2]))
361218334Speter    op2 = copy_to_mode_reg (insn_operand_mode[icode][2], op2);
361318334Speter
361418334Speter  if (! (*insn_operand_predicate[icode][3])
361518334Speter      (op3, insn_operand_mode[icode][3]))
361618334Speter    op3 = copy_to_mode_reg (insn_operand_mode[icode][3], op3);
361718334Speter
361818334Speter  /* Everything should now be in the suitable form, so emit the compare insn
361918334Speter     and then the conditional move.  */
362018334Speter
362118334Speter  comparison
362218334Speter    = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX, 0);
362318334Speter
362418334Speter  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
362518334Speter  if (GET_CODE (comparison) != code)
362618334Speter    /* This shouldn't happen.  */
362718334Speter    abort ();
362818334Speter
362918334Speter  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
363018334Speter
363118334Speter  /* If that failed, then give up.  */
363218334Speter  if (insn == 0)
363318334Speter    return 0;
363418334Speter
363518334Speter  emit_insn (insn);
363618334Speter
363718334Speter  if (subtarget != target)
363818334Speter    convert_move (target, subtarget, 0);
363918334Speter
364018334Speter  return target;
364118334Speter}
364218334Speter
364318334Speter/* Return non-zero if a conditional move of mode MODE is supported.
364418334Speter
364518334Speter   This function is for combine so it can tell whether an insn that looks
364618334Speter   like a conditional move is actually supported by the hardware.  If we
364718334Speter   guess wrong we lose a bit on optimization, but that's it.  */
364818334Speter/* ??? sparc64 supports conditionally moving integers values based on fp
364918334Speter   comparisons, and vice versa.  How do we handle them?  */
365018334Speter
365118334Speterint
365218334Spetercan_conditionally_move_p (mode)
365318334Speter     enum machine_mode mode;
365418334Speter{
365518334Speter  if (movcc_gen_code[mode] != CODE_FOR_nothing)
365618334Speter    return 1;
365718334Speter
365818334Speter  return 0;
365918334Speter}
366018334Speter
366118334Speter#endif /* HAVE_conditional_move */
366218334Speter
366318334Speter/* These three functions generate an insn body and return it
366418334Speter   rather than emitting the insn.
366518334Speter
366618334Speter   They do not protect from queued increments,
366718334Speter   because they may be used 1) in protect_from_queue itself
366818334Speter   and 2) in other passes where there is no queue.  */
366918334Speter
367018334Speter/* Generate and return an insn body to add Y to X.  */
367118334Speter
367218334Speterrtx
367318334Spetergen_add2_insn (x, y)
367418334Speter     rtx x, y;
367518334Speter{
367618334Speter  int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
367718334Speter
367818334Speter  if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0])
367918334Speter      || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1])
368018334Speter      || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2]))
368118334Speter    abort ();
368218334Speter
368318334Speter  return (GEN_FCN (icode) (x, x, y));
368418334Speter}
368518334Speter
368618334Speterint
368718334Speterhave_add2_insn (mode)
368818334Speter     enum machine_mode mode;
368918334Speter{
369018334Speter  return add_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing;
369118334Speter}
369218334Speter
369318334Speter/* Generate and return an insn body to subtract Y from X.  */
369418334Speter
369518334Speterrtx
369618334Spetergen_sub2_insn (x, y)
369718334Speter     rtx x, y;
369818334Speter{
369918334Speter  int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
370018334Speter
370118334Speter  if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0])
370218334Speter      || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1])
370318334Speter      || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2]))
370418334Speter    abort ();
370518334Speter
370618334Speter  return (GEN_FCN (icode) (x, x, y));
370718334Speter}
370818334Speter
370918334Speterint
371018334Speterhave_sub2_insn (mode)
371118334Speter     enum machine_mode mode;
371218334Speter{
371318334Speter  return sub_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing;
371418334Speter}
371518334Speter
371618334Speter/* Generate the body of an instruction to copy Y into X.
371718334Speter   It may be a SEQUENCE, if one insn isn't enough.  */
371818334Speter
371918334Speterrtx
372018334Spetergen_move_insn (x, y)
372118334Speter     rtx x, y;
372218334Speter{
372318334Speter  register enum machine_mode mode = GET_MODE (x);
372418334Speter  enum insn_code insn_code;
372518334Speter  rtx seq;
372618334Speter
372718334Speter  if (mode == VOIDmode)
372818334Speter    mode = GET_MODE (y);
372918334Speter
373018334Speter  insn_code = mov_optab->handlers[(int) mode].insn_code;
373118334Speter
373218334Speter  /* Handle MODE_CC modes:  If we don't have a special move insn for this mode,
373318334Speter     find a mode to do it in.  If we have a movcc, use it.  Otherwise,
373418334Speter     find the MODE_INT mode of the same width.  */
373518334Speter
373618334Speter  if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing)
373718334Speter    {
373818334Speter      enum machine_mode tmode = VOIDmode;
373918334Speter      rtx x1 = x, y1 = y;
374018334Speter
374118334Speter      if (mode != CCmode
374218334Speter	  && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
374318334Speter	tmode = CCmode;
374418334Speter      else
374518334Speter	for (tmode = QImode; tmode != VOIDmode;
374618334Speter	     tmode = GET_MODE_WIDER_MODE (tmode))
374718334Speter	  if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
374818334Speter	    break;
374918334Speter
375018334Speter      if (tmode == VOIDmode)
375118334Speter	abort ();
375218334Speter
375318334Speter      /* Get X and Y in TMODE.  We can't use gen_lowpart here because it
375418334Speter	 may call change_address which is not appropriate if we were
375518334Speter	 called when a reload was in progress.  We don't have to worry
375618334Speter	 about changing the address since the size in bytes is supposed to
375718334Speter	 be the same.  Copy the MEM to change the mode and move any
375818334Speter	 substitutions from the old MEM to the new one.  */
375918334Speter
376018334Speter      if (reload_in_progress)
376118334Speter	{
376218334Speter	  x = gen_lowpart_common (tmode, x1);
376318334Speter	  if (x == 0 && GET_CODE (x1) == MEM)
376418334Speter	    {
376550397Sobrien	      x = gen_rtx_MEM (tmode, XEXP (x1, 0));
376618334Speter	      RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (x1);
376752284Sobrien	      MEM_COPY_ATTRIBUTES (x, x1);
376818334Speter	      copy_replacements (x1, x);
376918334Speter	    }
377018334Speter
377118334Speter	  y = gen_lowpart_common (tmode, y1);
377218334Speter	  if (y == 0 && GET_CODE (y1) == MEM)
377318334Speter	    {
377450397Sobrien	      y = gen_rtx_MEM (tmode, XEXP (y1, 0));
377518334Speter	      RTX_UNCHANGING_P (y) = RTX_UNCHANGING_P (y1);
377652284Sobrien	      MEM_COPY_ATTRIBUTES (y, y1);
377718334Speter	      copy_replacements (y1, y);
377818334Speter	    }
377918334Speter	}
378018334Speter      else
378118334Speter	{
378218334Speter	  x = gen_lowpart (tmode, x);
378318334Speter	  y = gen_lowpart (tmode, y);
378418334Speter	}
378518334Speter
378618334Speter      insn_code = mov_optab->handlers[(int) tmode].insn_code;
378718334Speter      return (GEN_FCN (insn_code) (x, y));
378818334Speter    }
378918334Speter
379018334Speter  start_sequence ();
379118334Speter  emit_move_insn_1 (x, y);
379218334Speter  seq = gen_sequence ();
379318334Speter  end_sequence ();
379418334Speter  return seq;
379518334Speter}
379618334Speter
379718334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE.
379818334Speter   UNSIGNEDP specifies zero-extension instead of sign-extension.  If
379918334Speter   no such operation exists, CODE_FOR_nothing will be returned.  */
380018334Speter
380118334Speterenum insn_code
380218334Spetercan_extend_p (to_mode, from_mode, unsignedp)
380318334Speter     enum machine_mode to_mode, from_mode;
380418334Speter     int unsignedp;
380518334Speter{
380618334Speter  return extendtab[(int) to_mode][(int) from_mode][unsignedp];
380718334Speter}
380818334Speter
380918334Speter/* Generate the body of an insn to extend Y (with mode MFROM)
381018334Speter   into X (with mode MTO).  Do zero-extension if UNSIGNEDP is nonzero.  */
381118334Speter
381218334Speterrtx
381318334Spetergen_extend_insn (x, y, mto, mfrom, unsignedp)
381418334Speter     rtx x, y;
381518334Speter     enum machine_mode mto, mfrom;
381618334Speter     int unsignedp;
381718334Speter{
381818334Speter  return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp]) (x, y));
381918334Speter}
382018334Speter
382118334Speter/* can_fix_p and can_float_p say whether the target machine
382218334Speter   can directly convert a given fixed point type to
382318334Speter   a given floating point type, or vice versa.
382418334Speter   The returned value is the CODE_FOR_... value to use,
382518334Speter   or CODE_FOR_nothing if these modes cannot be directly converted.
382618334Speter
382718334Speter   *TRUNCP_PTR is set to 1 if it is necessary to output
382818334Speter   an explicit FTRUNC insn before the fix insn; otherwise 0.  */
382918334Speter
383018334Speterstatic enum insn_code
383118334Spetercan_fix_p (fixmode, fltmode, unsignedp, truncp_ptr)
383218334Speter     enum machine_mode fltmode, fixmode;
383318334Speter     int unsignedp;
383418334Speter     int *truncp_ptr;
383518334Speter{
383618334Speter  *truncp_ptr = 0;
383718334Speter  if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp] != CODE_FOR_nothing)
383818334Speter    return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp];
383918334Speter
384018334Speter  if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing)
384118334Speter    {
384218334Speter      *truncp_ptr = 1;
384318334Speter      return fixtab[(int) fltmode][(int) fixmode][unsignedp];
384418334Speter    }
384518334Speter  return CODE_FOR_nothing;
384618334Speter}
384718334Speter
384818334Speterstatic enum insn_code
384918334Spetercan_float_p (fltmode, fixmode, unsignedp)
385018334Speter     enum machine_mode fixmode, fltmode;
385118334Speter     int unsignedp;
385218334Speter{
385318334Speter  return floattab[(int) fltmode][(int) fixmode][unsignedp];
385418334Speter}
385518334Speter
385618334Speter/* Generate code to convert FROM to floating point
385718334Speter   and store in TO.  FROM must be fixed point and not VOIDmode.
385818334Speter   UNSIGNEDP nonzero means regard FROM as unsigned.
385918334Speter   Normally this is done by correcting the final value
386018334Speter   if it is negative.  */
386118334Speter
386218334Spetervoid
386318334Speterexpand_float (to, from, unsignedp)
386418334Speter     rtx to, from;
386518334Speter     int unsignedp;
386618334Speter{
386718334Speter  enum insn_code icode;
386818334Speter  register rtx target = to;
386918334Speter  enum machine_mode fmode, imode;
387018334Speter
387118334Speter  /* Crash now, because we won't be able to decide which mode to use.  */
387218334Speter  if (GET_MODE (from) == VOIDmode)
387318334Speter    abort ();
387418334Speter
387518334Speter  /* Look for an insn to do the conversion.  Do it in the specified
387618334Speter     modes if possible; otherwise convert either input, output or both to
387718334Speter     wider mode.  If the integer mode is wider than the mode of FROM,
387818334Speter     we can do the conversion signed even if the input is unsigned.  */
387918334Speter
388018334Speter  for (imode = GET_MODE (from); imode != VOIDmode;
388118334Speter       imode = GET_MODE_WIDER_MODE (imode))
388218334Speter    for (fmode = GET_MODE (to); fmode != VOIDmode;
388318334Speter	 fmode = GET_MODE_WIDER_MODE (fmode))
388418334Speter      {
388518334Speter	int doing_unsigned = unsignedp;
388618334Speter
388718334Speter	icode = can_float_p (fmode, imode, unsignedp);
388818334Speter	if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
388918334Speter	  icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
389018334Speter
389118334Speter	if (icode != CODE_FOR_nothing)
389218334Speter	  {
389318334Speter	    to = protect_from_queue (to, 1);
389418334Speter	    from = protect_from_queue (from, 0);
389518334Speter
389618334Speter	    if (imode != GET_MODE (from))
389718334Speter	      from = convert_to_mode (imode, from, unsignedp);
389818334Speter
389918334Speter	    if (fmode != GET_MODE (to))
390018334Speter	      target = gen_reg_rtx (fmode);
390118334Speter
390218334Speter	    emit_unop_insn (icode, target, from,
390318334Speter			    doing_unsigned ? UNSIGNED_FLOAT : FLOAT);
390418334Speter
390518334Speter	    if (target != to)
390618334Speter	      convert_move (to, target, 0);
390718334Speter	    return;
390818334Speter	  }
390918334Speter    }
391018334Speter
391118334Speter#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
391218334Speter
391318334Speter  /* Unsigned integer, and no way to convert directly.
391418334Speter     Convert as signed, then conditionally adjust the result.  */
391518334Speter  if (unsignedp)
391618334Speter    {
391718334Speter      rtx label = gen_label_rtx ();
391818334Speter      rtx temp;
391918334Speter      REAL_VALUE_TYPE offset;
392018334Speter
392118334Speter      emit_queue ();
392218334Speter
392318334Speter      to = protect_from_queue (to, 1);
392418334Speter      from = protect_from_queue (from, 0);
392518334Speter
392618334Speter      if (flag_force_mem)
392718334Speter	from = force_not_mem (from);
392818334Speter
392918334Speter      /* Look for a usable floating mode FMODE wider than the source and at
393018334Speter	 least as wide as the target.  Using FMODE will avoid rounding woes
393118334Speter	 with unsigned values greater than the signed maximum value.  */
393218334Speter
393318334Speter      for (fmode = GET_MODE (to);  fmode != VOIDmode;
393418334Speter	   fmode = GET_MODE_WIDER_MODE (fmode))
393518334Speter	if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
393618334Speter	    && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
393718334Speter	  break;
393818334Speter
393918334Speter      if (fmode == VOIDmode)
394018334Speter	{
394118334Speter	  /* There is no such mode.  Pretend the target is wide enough.  */
394218334Speter	  fmode = GET_MODE (to);
394318334Speter
394450397Sobrien	  /* Avoid double-rounding when TO is narrower than FROM.  */
394518334Speter	  if ((significand_size (fmode) + 1)
394618334Speter	      < GET_MODE_BITSIZE (GET_MODE (from)))
394718334Speter	    {
394818334Speter	      rtx temp1;
394918334Speter	      rtx neglabel = gen_label_rtx ();
395018334Speter
395118334Speter	      /* Don't use TARGET if it isn't a register, is a hard register,
395218334Speter		 or is the wrong mode.  */
395318334Speter	      if (GET_CODE (target) != REG
395418334Speter		  || REGNO (target) < FIRST_PSEUDO_REGISTER
395518334Speter		  || GET_MODE (target) != fmode)
395618334Speter		target = gen_reg_rtx (fmode);
395718334Speter
395818334Speter	      imode = GET_MODE (from);
395918334Speter	      do_pending_stack_adjust ();
396018334Speter
396118334Speter	      /* Test whether the sign bit is set.  */
396218334Speter	      emit_cmp_insn (from, const0_rtx, GE, NULL_RTX, imode, 0, 0);
396318334Speter	      emit_jump_insn (gen_blt (neglabel));
396418334Speter
396518334Speter	      /* The sign bit is not set.  Convert as signed.  */
396618334Speter	      expand_float (target, from, 0);
396718334Speter	      emit_jump_insn (gen_jump (label));
396818334Speter	      emit_barrier ();
396918334Speter
397018334Speter	      /* The sign bit is set.
397118334Speter		 Convert to a usable (positive signed) value by shifting right
397218334Speter		 one bit, while remembering if a nonzero bit was shifted
397318334Speter		 out; i.e., compute  (from & 1) | (from >> 1).  */
397418334Speter
397518334Speter	      emit_label (neglabel);
397618334Speter	      temp = expand_binop (imode, and_optab, from, const1_rtx,
397718334Speter				   NULL_RTX, 1, OPTAB_LIB_WIDEN);
397818334Speter	      temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
397918334Speter				    NULL_RTX, 1);
398018334Speter	      temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
398118334Speter				   OPTAB_LIB_WIDEN);
398218334Speter	      expand_float (target, temp, 0);
398318334Speter
398418334Speter	      /* Multiply by 2 to undo the shift above.  */
398518334Speter	      temp = expand_binop (fmode, add_optab, target, target,
398618334Speter				     target, 0, OPTAB_LIB_WIDEN);
398718334Speter	      if (temp != target)
398818334Speter		emit_move_insn (target, temp);
398918334Speter
399018334Speter	      do_pending_stack_adjust ();
399118334Speter	      emit_label (label);
399218334Speter	      goto done;
399318334Speter	    }
399418334Speter	}
399518334Speter
399618334Speter      /* If we are about to do some arithmetic to correct for an
399718334Speter	 unsigned operand, do it in a pseudo-register.  */
399818334Speter
399918334Speter      if (GET_MODE (to) != fmode
400018334Speter	  || GET_CODE (to) != REG || REGNO (to) < FIRST_PSEUDO_REGISTER)
400118334Speter	target = gen_reg_rtx (fmode);
400218334Speter
400318334Speter      /* Convert as signed integer to floating.  */
400418334Speter      expand_float (target, from, 0);
400518334Speter
400618334Speter      /* If FROM is negative (and therefore TO is negative),
400718334Speter	 correct its value by 2**bitwidth.  */
400818334Speter
400918334Speter      do_pending_stack_adjust ();
401052284Sobrien      emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
401152284Sobrien			        0, 0, label);
401218334Speter
401318334Speter      /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1).
401418334Speter	 Rather than setting up a dconst_dot_5, let's hope SCO
401518334Speter	 fixes the bug.  */
401618334Speter      offset = REAL_VALUE_LDEXP (dconst1, GET_MODE_BITSIZE (GET_MODE (from)));
401718334Speter      temp = expand_binop (fmode, add_optab, target,
401818334Speter			   CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
401918334Speter			   target, 0, OPTAB_LIB_WIDEN);
402018334Speter      if (temp != target)
402118334Speter	emit_move_insn (target, temp);
402218334Speter
402318334Speter      do_pending_stack_adjust ();
402418334Speter      emit_label (label);
402518334Speter      goto done;
402618334Speter    }
402718334Speter#endif
402818334Speter
402918334Speter  /* No hardware instruction available; call a library routine to convert from
403018334Speter     SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode.  */
403118334Speter    {
403218334Speter      rtx libfcn;
403318334Speter      rtx insns;
403418334Speter      rtx value;
403518334Speter
403618334Speter      to = protect_from_queue (to, 1);
403718334Speter      from = protect_from_queue (from, 0);
403818334Speter
403918334Speter      if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
404018334Speter	from = convert_to_mode (SImode, from, unsignedp);
404118334Speter
404218334Speter      if (flag_force_mem)
404318334Speter	from = force_not_mem (from);
404418334Speter
404518334Speter      if (GET_MODE (to) == SFmode)
404618334Speter	{
404718334Speter	  if (GET_MODE (from) == SImode)
404818334Speter	    libfcn = floatsisf_libfunc;
404918334Speter	  else if (GET_MODE (from) == DImode)
405018334Speter	    libfcn = floatdisf_libfunc;
405118334Speter	  else if (GET_MODE (from) == TImode)
405218334Speter	    libfcn = floattisf_libfunc;
405318334Speter	  else
405418334Speter	    abort ();
405518334Speter	}
405618334Speter      else if (GET_MODE (to) == DFmode)
405718334Speter	{
405818334Speter	  if (GET_MODE (from) == SImode)
405918334Speter	    libfcn = floatsidf_libfunc;
406018334Speter	  else if (GET_MODE (from) == DImode)
406118334Speter	    libfcn = floatdidf_libfunc;
406218334Speter	  else if (GET_MODE (from) == TImode)
406318334Speter	    libfcn = floattidf_libfunc;
406418334Speter	  else
406518334Speter	    abort ();
406618334Speter	}
406718334Speter      else if (GET_MODE (to) == XFmode)
406818334Speter	{
406918334Speter	  if (GET_MODE (from) == SImode)
407018334Speter	    libfcn = floatsixf_libfunc;
407118334Speter	  else if (GET_MODE (from) == DImode)
407218334Speter	    libfcn = floatdixf_libfunc;
407318334Speter	  else if (GET_MODE (from) == TImode)
407418334Speter	    libfcn = floattixf_libfunc;
407518334Speter	  else
407618334Speter	    abort ();
407718334Speter	}
407818334Speter      else if (GET_MODE (to) == TFmode)
407918334Speter	{
408018334Speter	  if (GET_MODE (from) == SImode)
408118334Speter	    libfcn = floatsitf_libfunc;
408218334Speter	  else if (GET_MODE (from) == DImode)
408318334Speter	    libfcn = floatditf_libfunc;
408418334Speter	  else if (GET_MODE (from) == TImode)
408518334Speter	    libfcn = floattitf_libfunc;
408618334Speter	  else
408718334Speter	    abort ();
408818334Speter	}
408918334Speter      else
409018334Speter	abort ();
409118334Speter
409218334Speter      start_sequence ();
409318334Speter
409418334Speter      value = emit_library_call_value (libfcn, NULL_RTX, 1,
409518334Speter				       GET_MODE (to),
409618334Speter				       1, from, GET_MODE (from));
409718334Speter      insns = get_insns ();
409818334Speter      end_sequence ();
409918334Speter
410018334Speter      emit_libcall_block (insns, target, value,
410150397Sobrien			  gen_rtx_FLOAT (GET_MODE (to), from));
410218334Speter    }
410318334Speter
410418334Speter done:
410518334Speter
410618334Speter  /* Copy result to requested destination
410718334Speter     if we have been computing in a temp location.  */
410818334Speter
410918334Speter  if (target != to)
411018334Speter    {
411118334Speter      if (GET_MODE (target) == GET_MODE (to))
411218334Speter	emit_move_insn (to, target);
411318334Speter      else
411418334Speter	convert_move (to, target, 0);
411518334Speter    }
411618334Speter}
411718334Speter
411818334Speter/* expand_fix: generate code to convert FROM to fixed point
411918334Speter   and store in TO.  FROM must be floating point.  */
412018334Speter
412118334Speterstatic rtx
412218334Speterftruncify (x)
412318334Speter     rtx x;
412418334Speter{
412518334Speter  rtx temp = gen_reg_rtx (GET_MODE (x));
412618334Speter  return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0);
412718334Speter}
412818334Speter
412918334Spetervoid
413018334Speterexpand_fix (to, from, unsignedp)
413118334Speter     register rtx to, from;
413218334Speter     int unsignedp;
413318334Speter{
413418334Speter  enum insn_code icode;
413518334Speter  register rtx target = to;
413618334Speter  enum machine_mode fmode, imode;
413718334Speter  int must_trunc = 0;
413818334Speter  rtx libfcn = 0;
413918334Speter
414018334Speter  /* We first try to find a pair of modes, one real and one integer, at
414118334Speter     least as wide as FROM and TO, respectively, in which we can open-code
414218334Speter     this conversion.  If the integer mode is wider than the mode of TO,
414318334Speter     we can do the conversion either signed or unsigned.  */
414418334Speter
414518334Speter  for (imode = GET_MODE (to); imode != VOIDmode;
414618334Speter       imode = GET_MODE_WIDER_MODE (imode))
414718334Speter    for (fmode = GET_MODE (from); fmode != VOIDmode;
414818334Speter	 fmode = GET_MODE_WIDER_MODE (fmode))
414918334Speter      {
415018334Speter	int doing_unsigned = unsignedp;
415118334Speter
415218334Speter	icode = can_fix_p (imode, fmode, unsignedp, &must_trunc);
415318334Speter	if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp)
415418334Speter	  icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0;
415518334Speter
415618334Speter	if (icode != CODE_FOR_nothing)
415718334Speter	  {
415818334Speter	    to = protect_from_queue (to, 1);
415918334Speter	    from = protect_from_queue (from, 0);
416018334Speter
416118334Speter	    if (fmode != GET_MODE (from))
416218334Speter	      from = convert_to_mode (fmode, from, 0);
416318334Speter
416418334Speter	    if (must_trunc)
416518334Speter	      from = ftruncify (from);
416618334Speter
416718334Speter	    if (imode != GET_MODE (to))
416818334Speter	      target = gen_reg_rtx (imode);
416918334Speter
417018334Speter	    emit_unop_insn (icode, target, from,
417118334Speter			    doing_unsigned ? UNSIGNED_FIX : FIX);
417218334Speter	    if (target != to)
417318334Speter	      convert_move (to, target, unsignedp);
417418334Speter	    return;
417518334Speter	  }
417618334Speter      }
417718334Speter
417818334Speter#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
417918334Speter  /* For an unsigned conversion, there is one more way to do it.
418018334Speter     If we have a signed conversion, we generate code that compares
418118334Speter     the real value to the largest representable positive number.  If if
418218334Speter     is smaller, the conversion is done normally.  Otherwise, subtract
418318334Speter     one plus the highest signed number, convert, and add it back.
418418334Speter
418518334Speter     We only need to check all real modes, since we know we didn't find
418618334Speter     anything with a wider integer mode.  */
418718334Speter
418818334Speter  if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
418918334Speter    for (fmode = GET_MODE (from); fmode != VOIDmode;
419018334Speter	 fmode = GET_MODE_WIDER_MODE (fmode))
419118334Speter      /* Make sure we won't lose significant bits doing this.  */
419218334Speter      if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to))
419318334Speter	  && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
419418334Speter					    &must_trunc))
419518334Speter	{
419618334Speter	  int bitsize;
419718334Speter	  REAL_VALUE_TYPE offset;
419818334Speter	  rtx limit, lab1, lab2, insn;
419918334Speter
420018334Speter	  bitsize = GET_MODE_BITSIZE (GET_MODE (to));
420118334Speter	  offset = REAL_VALUE_LDEXP (dconst1, bitsize - 1);
420218334Speter	  limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
420318334Speter	  lab1 = gen_label_rtx ();
420418334Speter	  lab2 = gen_label_rtx ();
420518334Speter
420618334Speter	  emit_queue ();
420718334Speter	  to = protect_from_queue (to, 1);
420818334Speter	  from = protect_from_queue (from, 0);
420918334Speter
421018334Speter	  if (flag_force_mem)
421118334Speter	    from = force_not_mem (from);
421218334Speter
421318334Speter	  if (fmode != GET_MODE (from))
421418334Speter	    from = convert_to_mode (fmode, from, 0);
421518334Speter
421618334Speter	  /* See if we need to do the subtraction.  */
421718334Speter	  do_pending_stack_adjust ();
421852284Sobrien	  emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
421952284Sobrien				   0, 0, lab1);
422018334Speter
422118334Speter	  /* If not, do the signed "fix" and branch around fixup code.  */
422218334Speter	  expand_fix (to, from, 0);
422318334Speter	  emit_jump_insn (gen_jump (lab2));
422418334Speter	  emit_barrier ();
422518334Speter
422618334Speter	  /* Otherwise, subtract 2**(N-1), convert to signed number,
422718334Speter	     then add 2**(N-1).  Do the addition using XOR since this
422818334Speter	     will often generate better code.  */
422918334Speter	  emit_label (lab1);
423018334Speter	  target = expand_binop (GET_MODE (from), sub_optab, from, limit,
423118334Speter				 NULL_RTX, 0, OPTAB_LIB_WIDEN);
423218334Speter	  expand_fix (to, target, 0);
423318334Speter	  target = expand_binop (GET_MODE (to), xor_optab, to,
423418334Speter				 GEN_INT ((HOST_WIDE_INT) 1 << (bitsize - 1)),
423518334Speter				 to, 1, OPTAB_LIB_WIDEN);
423618334Speter
423718334Speter	  if (target != to)
423818334Speter	    emit_move_insn (to, target);
423918334Speter
424018334Speter	  emit_label (lab2);
424118334Speter
424250397Sobrien	  if (mov_optab->handlers[(int) GET_MODE (to)].insn_code
424350397Sobrien	      != CODE_FOR_nothing)
424450397Sobrien	    {
424550397Sobrien	      /* Make a place for a REG_NOTE and add it.  */
424650397Sobrien	      insn = emit_move_insn (to, to);
424752284Sobrien	      set_unique_reg_note (insn,
424852284Sobrien	                           REG_EQUAL,
424952284Sobrien				   gen_rtx_fmt_e (UNSIGNED_FIX,
425052284Sobrien						  GET_MODE (to),
425152284Sobrien						  copy_rtx (from)));
425250397Sobrien	    }
425318334Speter	  return;
425418334Speter	}
425518334Speter#endif
425618334Speter
425718334Speter  /* We can't do it with an insn, so use a library call.  But first ensure
425818334Speter     that the mode of TO is at least as wide as SImode, since those are the
425918334Speter     only library calls we know about.  */
426018334Speter
426118334Speter  if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
426218334Speter    {
426318334Speter      target = gen_reg_rtx (SImode);
426418334Speter
426518334Speter      expand_fix (target, from, unsignedp);
426618334Speter    }
426718334Speter  else if (GET_MODE (from) == SFmode)
426818334Speter    {
426918334Speter      if (GET_MODE (to) == SImode)
427018334Speter	libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc;
427118334Speter      else if (GET_MODE (to) == DImode)
427218334Speter	libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc;
427318334Speter      else if (GET_MODE (to) == TImode)
427418334Speter	libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc;
427518334Speter      else
427618334Speter	abort ();
427718334Speter    }
427818334Speter  else if (GET_MODE (from) == DFmode)
427918334Speter    {
428018334Speter      if (GET_MODE (to) == SImode)
428118334Speter	libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc;
428218334Speter      else if (GET_MODE (to) == DImode)
428318334Speter	libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc;
428418334Speter      else if (GET_MODE (to) == TImode)
428518334Speter	libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc;
428618334Speter      else
428718334Speter	abort ();
428818334Speter    }
428918334Speter  else if (GET_MODE (from) == XFmode)
429018334Speter    {
429118334Speter      if (GET_MODE (to) == SImode)
429218334Speter	libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc;
429318334Speter      else if (GET_MODE (to) == DImode)
429418334Speter	libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc;
429518334Speter      else if (GET_MODE (to) == TImode)
429618334Speter	libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc;
429718334Speter      else
429818334Speter	abort ();
429918334Speter    }
430018334Speter  else if (GET_MODE (from) == TFmode)
430118334Speter    {
430218334Speter      if (GET_MODE (to) == SImode)
430318334Speter	libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc;
430418334Speter      else if (GET_MODE (to) == DImode)
430518334Speter	libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc;
430618334Speter      else if (GET_MODE (to) == TImode)
430718334Speter	libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc;
430818334Speter      else
430918334Speter	abort ();
431018334Speter    }
431118334Speter  else
431218334Speter    abort ();
431318334Speter
431418334Speter  if (libfcn)
431518334Speter    {
431618334Speter      rtx insns;
431718334Speter      rtx value;
431818334Speter
431918334Speter      to = protect_from_queue (to, 1);
432018334Speter      from = protect_from_queue (from, 0);
432118334Speter
432218334Speter      if (flag_force_mem)
432318334Speter	from = force_not_mem (from);
432418334Speter
432518334Speter      start_sequence ();
432618334Speter
432718334Speter      value = emit_library_call_value (libfcn, NULL_RTX, 1, GET_MODE (to),
432818334Speter
432918334Speter				       1, from, GET_MODE (from));
433018334Speter      insns = get_insns ();
433118334Speter      end_sequence ();
433218334Speter
433318334Speter      emit_libcall_block (insns, target, value,
433450397Sobrien			  gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
433550397Sobrien					 GET_MODE (to), from));
433618334Speter    }
433718334Speter
433850397Sobrien  if (target != to)
433950397Sobrien    {
434050397Sobrien      if (GET_MODE (to) == GET_MODE (target))
434150397Sobrien        emit_move_insn (to, target);
434250397Sobrien      else
434350397Sobrien        convert_move (to, target, 0);
434450397Sobrien    }
434518334Speter}
434618334Speter
434718334Speterstatic optab
434818334Speterinit_optab (code)
434918334Speter     enum rtx_code code;
435018334Speter{
435118334Speter  int i;
435218334Speter  optab op = (optab) xmalloc (sizeof (struct optab));
435318334Speter  op->code = code;
435418334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
435518334Speter    {
435618334Speter      op->handlers[i].insn_code = CODE_FOR_nothing;
435718334Speter      op->handlers[i].libfunc = 0;
435818334Speter    }
435918334Speter
436018334Speter  if (code != UNKNOWN)
436118334Speter    code_to_optab[(int) code] = op;
436218334Speter
436318334Speter  return op;
436418334Speter}
436518334Speter
436618334Speter/* Initialize the libfunc fields of an entire group of entries in some
436718334Speter   optab.  Each entry is set equal to a string consisting of a leading
436818334Speter   pair of underscores followed by a generic operation name followed by
436918334Speter   a mode name (downshifted to lower case) followed by a single character
437018334Speter   representing the number of operands for the given operation (which is
437118334Speter   usually one of the characters '2', '3', or '4').
437218334Speter
437318334Speter   OPTABLE is the table in which libfunc fields are to be initialized.
437418334Speter   FIRST_MODE is the first machine mode index in the given optab to
437518334Speter     initialize.
437618334Speter   LAST_MODE is the last machine mode index in the given optab to
437718334Speter     initialize.
437818334Speter   OPNAME is the generic (string) name of the operation.
437918334Speter   SUFFIX is the character which specifies the number of operands for
438018334Speter     the given generic operation.
438118334Speter*/
438218334Speter
438318334Speterstatic void
438418334Speterinit_libfuncs (optable, first_mode, last_mode, opname, suffix)
438518334Speter    register optab optable;
438618334Speter    register int first_mode;
438718334Speter    register int last_mode;
438852284Sobrien    register const char *opname;
438918334Speter    register int suffix;
439018334Speter{
439118334Speter  register int mode;
439218334Speter  register unsigned opname_len = strlen (opname);
439318334Speter
439418334Speter  for (mode = first_mode; (int) mode <= (int) last_mode;
439518334Speter       mode = (enum machine_mode) ((int) mode + 1))
439618334Speter    {
439718334Speter      register char *mname = mode_name[(int) mode];
439818334Speter      register unsigned mname_len = strlen (mname);
439918334Speter      register char *libfunc_name
440018334Speter	= (char *) xmalloc (2 + opname_len + mname_len + 1 + 1);
440118334Speter      register char *p;
440252284Sobrien      register const char *q;
440318334Speter
440418334Speter      p = libfunc_name;
440518334Speter      *p++ = '_';
440618334Speter      *p++ = '_';
440718334Speter      for (q = opname; *q; )
440818334Speter	*p++ = *q++;
440918334Speter      for (q = mname; *q; q++)
441052284Sobrien	*p++ = tolower ((unsigned char)*q);
441118334Speter      *p++ = suffix;
441218334Speter      *p++ = '\0';
441318334Speter      optable->handlers[(int) mode].libfunc
441450397Sobrien	= gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
441518334Speter    }
441618334Speter}
441718334Speter
441818334Speter/* Initialize the libfunc fields of an entire group of entries in some
441918334Speter   optab which correspond to all integer mode operations.  The parameters
442018334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
442118334Speter   routine.  (See above).  */
442218334Speter
442318334Speterstatic void
442418334Speterinit_integral_libfuncs (optable, opname, suffix)
442518334Speter    register optab optable;
442652284Sobrien    register const char *opname;
442718334Speter    register int suffix;
442818334Speter{
442918334Speter  init_libfuncs (optable, SImode, TImode, opname, suffix);
443018334Speter}
443118334Speter
443218334Speter/* Initialize the libfunc fields of an entire group of entries in some
443318334Speter   optab which correspond to all real mode operations.  The parameters
443418334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
443518334Speter   routine.  (See above).  */
443618334Speter
443718334Speterstatic void
443818334Speterinit_floating_libfuncs (optable, opname, suffix)
443918334Speter    register optab optable;
444052284Sobrien    register const char *opname;
444118334Speter    register int suffix;
444218334Speter{
444318334Speter  init_libfuncs (optable, SFmode, TFmode, opname, suffix);
444418334Speter}
444518334Speter
444618334Speter
444718334Speter/* Call this once to initialize the contents of the optabs
444818334Speter   appropriately for the current target machine.  */
444918334Speter
445018334Spetervoid
445118334Speterinit_optabs ()
445218334Speter{
445350397Sobrien  int i;
445450397Sobrien#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
445550397Sobrien  int j;
445650397Sobrien#endif
445750397Sobrien
445818334Speter  enum insn_code *p;
445918334Speter
446018334Speter  /* Start by initializing all tables to contain CODE_FOR_nothing.  */
446118334Speter
446218334Speter  for (p = fixtab[0][0];
446318334Speter       p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]);
446418334Speter       p++)
446518334Speter    *p = CODE_FOR_nothing;
446618334Speter
446718334Speter  for (p = fixtrunctab[0][0];
446818334Speter       p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]);
446918334Speter       p++)
447018334Speter    *p = CODE_FOR_nothing;
447118334Speter
447218334Speter  for (p = floattab[0][0];
447318334Speter       p < floattab[0][0] + sizeof floattab / sizeof (floattab[0][0][0]);
447418334Speter       p++)
447518334Speter    *p = CODE_FOR_nothing;
447618334Speter
447718334Speter  for (p = extendtab[0][0];
447818334Speter       p < extendtab[0][0] + sizeof extendtab / sizeof extendtab[0][0][0];
447918334Speter       p++)
448018334Speter    *p = CODE_FOR_nothing;
448118334Speter
448218334Speter  for (i = 0; i < NUM_RTX_CODE; i++)
448318334Speter    setcc_gen_code[i] = CODE_FOR_nothing;
448418334Speter
448518334Speter#ifdef HAVE_conditional_move
448618334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
448718334Speter    movcc_gen_code[i] = CODE_FOR_nothing;
448818334Speter#endif
448918334Speter
449018334Speter  add_optab = init_optab (PLUS);
449118334Speter  sub_optab = init_optab (MINUS);
449218334Speter  smul_optab = init_optab (MULT);
449318334Speter  smul_highpart_optab = init_optab (UNKNOWN);
449418334Speter  umul_highpart_optab = init_optab (UNKNOWN);
449518334Speter  smul_widen_optab = init_optab (UNKNOWN);
449618334Speter  umul_widen_optab = init_optab (UNKNOWN);
449718334Speter  sdiv_optab = init_optab (DIV);
449818334Speter  sdivmod_optab = init_optab (UNKNOWN);
449918334Speter  udiv_optab = init_optab (UDIV);
450018334Speter  udivmod_optab = init_optab (UNKNOWN);
450118334Speter  smod_optab = init_optab (MOD);
450218334Speter  umod_optab = init_optab (UMOD);
450318334Speter  flodiv_optab = init_optab (DIV);
450418334Speter  ftrunc_optab = init_optab (UNKNOWN);
450518334Speter  and_optab = init_optab (AND);
450618334Speter  ior_optab = init_optab (IOR);
450718334Speter  xor_optab = init_optab (XOR);
450818334Speter  ashl_optab = init_optab (ASHIFT);
450918334Speter  ashr_optab = init_optab (ASHIFTRT);
451018334Speter  lshr_optab = init_optab (LSHIFTRT);
451118334Speter  rotl_optab = init_optab (ROTATE);
451218334Speter  rotr_optab = init_optab (ROTATERT);
451318334Speter  smin_optab = init_optab (SMIN);
451418334Speter  smax_optab = init_optab (SMAX);
451518334Speter  umin_optab = init_optab (UMIN);
451618334Speter  umax_optab = init_optab (UMAX);
451718334Speter  mov_optab = init_optab (UNKNOWN);
451818334Speter  movstrict_optab = init_optab (UNKNOWN);
451918334Speter  cmp_optab = init_optab (UNKNOWN);
452018334Speter  ucmp_optab = init_optab (UNKNOWN);
452118334Speter  tst_optab = init_optab (UNKNOWN);
452218334Speter  neg_optab = init_optab (NEG);
452318334Speter  abs_optab = init_optab (ABS);
452418334Speter  one_cmpl_optab = init_optab (NOT);
452518334Speter  ffs_optab = init_optab (FFS);
452618334Speter  sqrt_optab = init_optab (SQRT);
452718334Speter  sin_optab = init_optab (UNKNOWN);
452818334Speter  cos_optab = init_optab (UNKNOWN);
452918334Speter  strlen_optab = init_optab (UNKNOWN);
453018334Speter
453118334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
453218334Speter    {
453318334Speter      movstr_optab[i] = CODE_FOR_nothing;
453450397Sobrien      clrstr_optab[i] = CODE_FOR_nothing;
453518334Speter
453618334Speter#ifdef HAVE_SECONDARY_RELOADS
453718334Speter      reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
453818334Speter#endif
453918334Speter    }
454018334Speter
454118334Speter  /* Fill in the optabs with the insns we support.  */
454218334Speter  init_all_optabs ();
454318334Speter
454418334Speter#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
454518334Speter  /* This flag says the same insns that convert to a signed fixnum
454618334Speter     also convert validly to an unsigned one.  */
454718334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
454818334Speter    for (j = 0; j < NUM_MACHINE_MODES; j++)
454918334Speter      fixtrunctab[i][j][1] = fixtrunctab[i][j][0];
455018334Speter#endif
455118334Speter
455218334Speter#ifdef EXTRA_CC_MODES
455318334Speter  init_mov_optab ();
455418334Speter#endif
455518334Speter
455618334Speter  /* Initialize the optabs with the names of the library functions.  */
455718334Speter  init_integral_libfuncs (add_optab, "add", '3');
455818334Speter  init_floating_libfuncs (add_optab, "add", '3');
455918334Speter  init_integral_libfuncs (sub_optab, "sub", '3');
456018334Speter  init_floating_libfuncs (sub_optab, "sub", '3');
456118334Speter  init_integral_libfuncs (smul_optab, "mul", '3');
456218334Speter  init_floating_libfuncs (smul_optab, "mul", '3');
456318334Speter  init_integral_libfuncs (sdiv_optab, "div", '3');
456418334Speter  init_integral_libfuncs (udiv_optab, "udiv", '3');
456518334Speter  init_integral_libfuncs (sdivmod_optab, "divmod", '4');
456618334Speter  init_integral_libfuncs (udivmod_optab, "udivmod", '4');
456718334Speter  init_integral_libfuncs (smod_optab, "mod", '3');
456818334Speter  init_integral_libfuncs (umod_optab, "umod", '3');
456918334Speter  init_floating_libfuncs (flodiv_optab, "div", '3');
457018334Speter  init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
457118334Speter  init_integral_libfuncs (and_optab, "and", '3');
457218334Speter  init_integral_libfuncs (ior_optab, "ior", '3');
457318334Speter  init_integral_libfuncs (xor_optab, "xor", '3');
457418334Speter  init_integral_libfuncs (ashl_optab, "ashl", '3');
457518334Speter  init_integral_libfuncs (ashr_optab, "ashr", '3');
457618334Speter  init_integral_libfuncs (lshr_optab, "lshr", '3');
457718334Speter  init_integral_libfuncs (smin_optab, "min", '3');
457818334Speter  init_floating_libfuncs (smin_optab, "min", '3');
457918334Speter  init_integral_libfuncs (smax_optab, "max", '3');
458018334Speter  init_floating_libfuncs (smax_optab, "max", '3');
458118334Speter  init_integral_libfuncs (umin_optab, "umin", '3');
458218334Speter  init_integral_libfuncs (umax_optab, "umax", '3');
458318334Speter  init_integral_libfuncs (neg_optab, "neg", '2');
458418334Speter  init_floating_libfuncs (neg_optab, "neg", '2');
458518334Speter  init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
458618334Speter  init_integral_libfuncs (ffs_optab, "ffs", '2');
458718334Speter
458818334Speter  /* Comparison libcalls for integers MUST come in pairs, signed/unsigned.  */
458918334Speter  init_integral_libfuncs (cmp_optab, "cmp", '2');
459018334Speter  init_integral_libfuncs (ucmp_optab, "ucmp", '2');
459118334Speter  init_floating_libfuncs (cmp_optab, "cmp", '2');
459218334Speter
459318334Speter#ifdef MULSI3_LIBCALL
459418334Speter  smul_optab->handlers[(int) SImode].libfunc
459550397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, MULSI3_LIBCALL);
459618334Speter#endif
459718334Speter#ifdef MULDI3_LIBCALL
459818334Speter  smul_optab->handlers[(int) DImode].libfunc
459950397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, MULDI3_LIBCALL);
460018334Speter#endif
460118334Speter
460218334Speter#ifdef DIVSI3_LIBCALL
460318334Speter  sdiv_optab->handlers[(int) SImode].libfunc
460450397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, DIVSI3_LIBCALL);
460518334Speter#endif
460618334Speter#ifdef DIVDI3_LIBCALL
460718334Speter  sdiv_optab->handlers[(int) DImode].libfunc
460850397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, DIVDI3_LIBCALL);
460918334Speter#endif
461018334Speter
461118334Speter#ifdef UDIVSI3_LIBCALL
461218334Speter  udiv_optab->handlers[(int) SImode].libfunc
461350397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, UDIVSI3_LIBCALL);
461418334Speter#endif
461518334Speter#ifdef UDIVDI3_LIBCALL
461618334Speter  udiv_optab->handlers[(int) DImode].libfunc
461750397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, UDIVDI3_LIBCALL);
461818334Speter#endif
461918334Speter
462018334Speter#ifdef MODSI3_LIBCALL
462118334Speter  smod_optab->handlers[(int) SImode].libfunc
462250397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, MODSI3_LIBCALL);
462318334Speter#endif
462418334Speter#ifdef MODDI3_LIBCALL
462518334Speter  smod_optab->handlers[(int) DImode].libfunc
462650397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, MODDI3_LIBCALL);
462718334Speter#endif
462818334Speter
462918334Speter#ifdef UMODSI3_LIBCALL
463018334Speter  umod_optab->handlers[(int) SImode].libfunc
463150397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, UMODSI3_LIBCALL);
463218334Speter#endif
463318334Speter#ifdef UMODDI3_LIBCALL
463418334Speter  umod_optab->handlers[(int) DImode].libfunc
463550397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, UMODDI3_LIBCALL);
463618334Speter#endif
463718334Speter
463818334Speter  /* Use cabs for DC complex abs, since systems generally have cabs.
463918334Speter     Don't define any libcall for SCmode, so that cabs will be used.  */
464018334Speter  abs_optab->handlers[(int) DCmode].libfunc
464150397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, "cabs");
464218334Speter
464318334Speter  /* The ffs function operates on `int'.  */
464418334Speter#ifndef INT_TYPE_SIZE
464518334Speter#define INT_TYPE_SIZE BITS_PER_WORD
464618334Speter#endif
464718334Speter  ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)] .libfunc
464850397Sobrien    = gen_rtx_SYMBOL_REF (Pmode, "ffs");
464918334Speter
465050397Sobrien  extendsfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsfdf2");
465150397Sobrien  extendsfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsfxf2");
465250397Sobrien  extendsftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsftf2");
465350397Sobrien  extenddfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddfxf2");
465450397Sobrien  extenddftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddftf2");
465518334Speter
465650397Sobrien  truncdfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncdfsf2");
465750397Sobrien  truncxfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfsf2");
465850397Sobrien  trunctfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfsf2");
465950397Sobrien  truncxfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfdf2");
466050397Sobrien  trunctfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfdf2");
466118334Speter
466250397Sobrien  memcpy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcpy");
466350397Sobrien  bcopy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bcopy");
466450397Sobrien  memcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcmp");
466550397Sobrien  bcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gcc_bcmp");
466650397Sobrien  memset_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memset");
466750397Sobrien  bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero");
466818334Speter
466950397Sobrien  throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw");
467052284Sobrien  rethrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__rethrow");
467150397Sobrien  sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow");
467250397Sobrien  sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow");
467350397Sobrien  terminate_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__terminate");
467452284Sobrien  eh_rtime_match_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eh_rtime_match");
467550397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
467650397Sobrien  setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__builtin_setjmp");
467750397Sobrien  longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__builtin_longjmp");
467850397Sobrien#else
467950397Sobrien  setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "setjmp");
468050397Sobrien  longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "longjmp");
468150397Sobrien#endif
468218334Speter
468350397Sobrien  eqhf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqhf2");
468450397Sobrien  nehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nehf2");
468550397Sobrien  gthf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gthf2");
468650397Sobrien  gehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gehf2");
468750397Sobrien  lthf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lthf2");
468850397Sobrien  lehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lehf2");
468918334Speter
469050397Sobrien  eqsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqsf2");
469150397Sobrien  nesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nesf2");
469250397Sobrien  gtsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtsf2");
469350397Sobrien  gesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gesf2");
469450397Sobrien  ltsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltsf2");
469550397Sobrien  lesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lesf2");
469618334Speter
469750397Sobrien  eqdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqdf2");
469850397Sobrien  nedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nedf2");
469950397Sobrien  gtdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtdf2");
470050397Sobrien  gedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gedf2");
470150397Sobrien  ltdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltdf2");
470250397Sobrien  ledf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ledf2");
470318334Speter
470450397Sobrien  eqxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqxf2");
470550397Sobrien  nexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nexf2");
470650397Sobrien  gtxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtxf2");
470750397Sobrien  gexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gexf2");
470850397Sobrien  ltxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltxf2");
470950397Sobrien  lexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lexf2");
471018334Speter
471150397Sobrien  eqtf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqtf2");
471250397Sobrien  netf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__netf2");
471350397Sobrien  gttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gttf2");
471450397Sobrien  getf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__getf2");
471550397Sobrien  lttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lttf2");
471650397Sobrien  letf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__letf2");
471718334Speter
471850397Sobrien  floatsisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsisf");
471950397Sobrien  floatdisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdisf");
472050397Sobrien  floattisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattisf");
472118334Speter
472250397Sobrien  floatsidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsidf");
472350397Sobrien  floatdidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdidf");
472450397Sobrien  floattidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattidf");
472518334Speter
472650397Sobrien  floatsixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsixf");
472750397Sobrien  floatdixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdixf");
472850397Sobrien  floattixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattixf");
472918334Speter
473050397Sobrien  floatsitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsitf");
473150397Sobrien  floatditf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatditf");
473250397Sobrien  floattitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattitf");
473318334Speter
473450397Sobrien  fixsfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfsi");
473550397Sobrien  fixsfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfdi");
473650397Sobrien  fixsfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfti");
473718334Speter
473850397Sobrien  fixdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfsi");
473950397Sobrien  fixdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfdi");
474050397Sobrien  fixdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfti");
474118334Speter
474250397Sobrien  fixxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfsi");
474350397Sobrien  fixxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfdi");
474450397Sobrien  fixxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfti");
474518334Speter
474650397Sobrien  fixtfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfsi");
474750397Sobrien  fixtfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfdi");
474850397Sobrien  fixtfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfti");
474918334Speter
475050397Sobrien  fixunssfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfsi");
475150397Sobrien  fixunssfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfdi");
475250397Sobrien  fixunssfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfti");
475318334Speter
475450397Sobrien  fixunsdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfsi");
475550397Sobrien  fixunsdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfdi");
475650397Sobrien  fixunsdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfti");
475718334Speter
475850397Sobrien  fixunsxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfsi");
475950397Sobrien  fixunsxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfdi");
476050397Sobrien  fixunsxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfti");
476118334Speter
476250397Sobrien  fixunstfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfsi");
476350397Sobrien  fixunstfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfdi");
476450397Sobrien  fixunstfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfti");
476550397Sobrien
476650397Sobrien  /* For check-memory-usage.  */
476752284Sobrien  chkr_check_addr_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_addr");
476852284Sobrien  chkr_set_right_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_set_right");
476952284Sobrien  chkr_copy_bitmap_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_copy_bitmap");
477052284Sobrien  chkr_check_exec_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_exec");
477152284Sobrien  chkr_check_str_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_str");
477250397Sobrien
477352284Sobrien  /* For function entry/exit instrumentation.  */
477452284Sobrien  profile_function_entry_libfunc
477552284Sobrien    = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_enter");
477652284Sobrien  profile_function_exit_libfunc
477752284Sobrien    = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_exit");
477852284Sobrien
477950397Sobrien#ifdef HAVE_conditional_trap
478050397Sobrien  init_traps ();
478150397Sobrien#endif
478250397Sobrien
478318334Speter#ifdef INIT_TARGET_OPTABS
478418334Speter  /* Allow the target to add more libcalls or rename some, etc.  */
478518334Speter  INIT_TARGET_OPTABS;
478618334Speter#endif
478718334Speter}
478818334Speter
478918334Speter#ifdef BROKEN_LDEXP
479018334Speter
479150397Sobrien/* SCO 3.2 apparently has a broken ldexp.  */
479218334Speter
479318334Speterdouble
479418334Speterldexp(x,n)
479518334Speter     double x;
479618334Speter     int n;
479718334Speter{
479818334Speter  if (n > 0)
479918334Speter    while (n--)
480018334Speter      x *= 2;
480118334Speter
480218334Speter  return x;
480318334Speter}
480418334Speter#endif /* BROKEN_LDEXP */
480550397Sobrien
480650397Sobrien#ifdef HAVE_conditional_trap
480750397Sobrien/* The insn generating function can not take an rtx_code argument.
480850397Sobrien   TRAP_RTX is used as an rtx argument.  Its code is replaced with
480950397Sobrien   the code to be used in the trap insn and all other fields are
481050397Sobrien   ignored.
481150397Sobrien
481250397Sobrien   ??? Will need to change to support garbage collection.  */
481350397Sobrienstatic rtx trap_rtx;
481450397Sobrien
481550397Sobrienstatic void
481650397Sobrieninit_traps ()
481750397Sobrien{
481850397Sobrien  if (HAVE_conditional_trap)
481950397Sobrien    trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
482050397Sobrien}
482150397Sobrien#endif
482250397Sobrien
482350397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
482450397Sobrien   CODE.  Return 0 on failure.  */
482550397Sobrien
482650397Sobrienrtx
482750397Sobriengen_cond_trap (code, op1, op2, tcode)
482852284Sobrien  enum rtx_code code ATTRIBUTE_UNUSED;
482952284Sobrien  rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED;
483050397Sobrien{
483150397Sobrien  enum machine_mode mode = GET_MODE (op1);
483250397Sobrien
483350397Sobrien  if (mode == VOIDmode)
483450397Sobrien    return 0;
483550397Sobrien
483650397Sobrien#ifdef HAVE_conditional_trap
483750397Sobrien  if (HAVE_conditional_trap
483850397Sobrien      && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
483950397Sobrien    {
484050397Sobrien      rtx insn;
484150397Sobrien      emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
484250397Sobrien      PUT_CODE (trap_rtx, code);
484350397Sobrien      insn = gen_conditional_trap (trap_rtx, tcode);
484450397Sobrien      if (insn)
484550397Sobrien	return insn;
484650397Sobrien    }
484750397Sobrien#endif
484850397Sobrien
484950397Sobrien  return 0;
485050397Sobrien}
4851