optabs.c revision 103445
118334Speter/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
290075Sobrien   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
390075Sobrien   1999, 2000, 2001 Free Software Foundation, Inc.
418334Speter
590075SobrienThis file is part of GCC.
618334Speter
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU General Public License as published by the Free
990075SobrienSoftware Foundation; either version 2, or (at your option) any later
1090075Sobrienversion.
1118334Speter
1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590075Sobrienfor more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090075Sobrien02111-1307, USA.  */
2118334Speter
2218334Speter
2318334Speter#include "config.h"
2450397Sobrien#include "system.h"
2552284Sobrien#include "toplev.h"
2652284Sobrien
2752284Sobrien/* Include insn-config.h before expr.h so that HAVE_conditional_move
2890075Sobrien   is properly defined.  */
2952284Sobrien#include "insn-config.h"
3018334Speter#include "rtl.h"
3118334Speter#include "tree.h"
3290075Sobrien#include "tm_p.h"
3318334Speter#include "flags.h"
3490075Sobrien#include "function.h"
3590075Sobrien#include "except.h"
3618334Speter#include "expr.h"
3790075Sobrien#include "optabs.h"
3890075Sobrien#include "libfuncs.h"
3918334Speter#include "recog.h"
4018334Speter#include "reload.h"
4190075Sobrien#include "ggc.h"
4290075Sobrien#include "real.h"
4318334Speter
4418334Speter/* Each optab contains info on how this target machine
4518334Speter   can perform a particular operation
4618334Speter   for all sizes and kinds of operands.
4718334Speter
4818334Speter   The operation to be performed is often specified
4918334Speter   by passing one of these optabs as an argument.
5018334Speter
5118334Speter   See expr.h for documentation of these optabs.  */
5218334Speter
5390075Sobrienoptab optab_table[OTI_MAX];
5418334Speter
5590075Sobrienrtx libfunc_table[LTI_MAX];
5618334Speter
5718334Speter/* Tables of patterns for extending one integer mode to another.  */
5818334Speterenum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
5918334Speter
6050397Sobrien/* Tables of patterns for converting between fixed and floating point.  */
6118334Speterenum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
6218334Speterenum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
6318334Speterenum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
6418334Speter
6518334Speter/* Contains the optab used for each rtx code.  */
6618334Speteroptab code_to_optab[NUM_RTX_CODE + 1];
6718334Speter
6818334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
6918334Speter   gives the gen_function to make a branch to test that condition.  */
7018334Speter
7118334Speterrtxfun bcc_gen_fctn[NUM_RTX_CODE];
7218334Speter
7318334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
7418334Speter   gives the insn code to make a store-condition insn
7518334Speter   to test that condition.  */
7618334Speter
7718334Speterenum insn_code setcc_gen_code[NUM_RTX_CODE];
7818334Speter
7918334Speter#ifdef HAVE_conditional_move
8018334Speter/* Indexed by the machine mode, gives the insn code to make a conditional
8118334Speter   move insn.  This is not indexed by the rtx-code like bcc_gen_fctn and
8218334Speter   setcc_gen_code to cut down on the number of named patterns.  Consider a day
8318334Speter   when a lot more rtx codes are conditional (eg: for the ARM).  */
8418334Speter
8518334Speterenum insn_code movcc_gen_code[NUM_MACHINE_MODES];
8618334Speter#endif
8718334Speter
8890075Sobrienstatic int add_equal_note	PARAMS ((rtx, rtx, enum rtx_code, rtx, rtx));
8990075Sobrienstatic rtx widen_operand	PARAMS ((rtx, enum machine_mode,
9018334Speter				       enum machine_mode, int, int));
9190075Sobrienstatic int expand_cmplxdiv_straight PARAMS ((rtx, rtx, rtx, rtx,
9252284Sobrien					   rtx, rtx, enum machine_mode,
9352284Sobrien					   int, enum optab_methods,
9452284Sobrien					   enum mode_class, optab));
9590075Sobrienstatic int expand_cmplxdiv_wide PARAMS ((rtx, rtx, rtx, rtx,
9652284Sobrien				       rtx, rtx, enum machine_mode,
9752284Sobrien				       int, enum optab_methods,
9852284Sobrien				       enum mode_class, optab));
9990075Sobrienstatic void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx,
10090075Sobrien				      enum machine_mode *, int *,
10190075Sobrien				      enum can_compare_purpose));
10290075Sobrienstatic enum insn_code can_fix_p	PARAMS ((enum machine_mode, enum machine_mode,
10318334Speter				       int, int *));
10490075Sobrienstatic enum insn_code can_float_p PARAMS ((enum machine_mode,
10590075Sobrien					   enum machine_mode,
10690075Sobrien					   int));
10790075Sobrienstatic rtx ftruncify	PARAMS ((rtx));
10890075Sobrienstatic optab new_optab	PARAMS ((void));
10990075Sobrienstatic inline optab init_optab	PARAMS ((enum rtx_code));
11090075Sobrienstatic inline optab init_optabv	PARAMS ((enum rtx_code));
11190075Sobrienstatic void init_libfuncs PARAMS ((optab, int, int, const char *, int));
11290075Sobrienstatic void init_integral_libfuncs PARAMS ((optab, const char *, int));
11390075Sobrienstatic void init_floating_libfuncs PARAMS ((optab, const char *, int));
11450397Sobrien#ifdef HAVE_conditional_trap
11590075Sobrienstatic void init_traps PARAMS ((void));
11650397Sobrien#endif
11790075Sobrienstatic void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode,
11890075Sobrien					    enum rtx_code, int, rtx));
11990075Sobrienstatic void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *,
12090075Sobrien					 enum machine_mode *, int *));
12118334Speter
12218334Speter/* Add a REG_EQUAL note to the last insn in SEQ.  TARGET is being set to
12318334Speter   the result of operation CODE applied to OP0 (and OP1 if it is a binary
12418334Speter   operation).
12518334Speter
12618334Speter   If the last insn does not set TARGET, don't do anything, but return 1.
12718334Speter
12818334Speter   If a previous insn sets TARGET and TARGET is one of OP0 or OP1,
12918334Speter   don't add the REG_EQUAL note but return 0.  Our caller can then try
13018334Speter   again, ensuring that TARGET is not one of the operands.  */
13118334Speter
13218334Speterstatic int
13318334Speteradd_equal_note (seq, target, code, op0, op1)
13418334Speter     rtx seq;
13518334Speter     rtx target;
13618334Speter     enum rtx_code code;
13718334Speter     rtx op0, op1;
13818334Speter{
13918334Speter  rtx set;
14018334Speter  int i;
14118334Speter  rtx note;
14218334Speter
14318334Speter  if ((GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2'
14418334Speter       && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<')
14518334Speter      || GET_CODE (seq) != SEQUENCE
14618334Speter      || (set = single_set (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))) == 0
14718334Speter      || GET_CODE (target) == ZERO_EXTRACT
14818334Speter      || (! rtx_equal_p (SET_DEST (set), target)
14918334Speter	  /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the
15018334Speter	     SUBREG.  */
15118334Speter	  && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
15218334Speter	      || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
15318334Speter				target))))
15418334Speter    return 1;
15518334Speter
15618334Speter  /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET
15718334Speter     besides the last insn.  */
15818334Speter  if (reg_overlap_mentioned_p (target, op0)
15918334Speter      || (op1 && reg_overlap_mentioned_p (target, op1)))
16018334Speter    for (i = XVECLEN (seq, 0) - 2; i >= 0; i--)
16118334Speter      if (reg_set_p (target, XVECEXP (seq, 0, i)))
16218334Speter	return 0;
16318334Speter
16418334Speter  if (GET_RTX_CLASS (code) == '1')
16550397Sobrien    note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0));
16618334Speter  else
16750397Sobrien    note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
16818334Speter
16952284Sobrien  set_unique_reg_note (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1), REG_EQUAL, note);
17018334Speter
17118334Speter  return 1;
17218334Speter}
17318334Speter
17418334Speter/* Widen OP to MODE and return the rtx for the widened operand.  UNSIGNEDP
17518334Speter   says whether OP is signed or unsigned.  NO_EXTEND is nonzero if we need
17618334Speter   not actually do a sign-extend or zero-extend, but can leave the
17718334Speter   higher-order bits of the result rtx undefined, for example, in the case
17818334Speter   of logical operations, but not right shifts.  */
17918334Speter
18018334Speterstatic rtx
18118334Speterwiden_operand (op, mode, oldmode, unsignedp, no_extend)
18218334Speter     rtx op;
18318334Speter     enum machine_mode mode, oldmode;
18418334Speter     int unsignedp;
18518334Speter     int no_extend;
18618334Speter{
18718334Speter  rtx result;
18818334Speter
18996263Sobrien  /* If we don't have to extend and this is a constant, return it.  */
19096263Sobrien  if (no_extend && GET_MODE (op) == VOIDmode)
19196263Sobrien    return op;
19296263Sobrien
19396263Sobrien  /* If we must extend do so.  If OP is a SUBREG for a promoted object, also
19496263Sobrien     extend since it will be more efficient to do so unless the signedness of
19596263Sobrien     a promoted object differs from our extension.  */
19618334Speter  if (! no_extend
19796263Sobrien      || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)
19896263Sobrien	  && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp))
19918334Speter    return convert_modes (mode, oldmode, op, unsignedp);
20018334Speter
20118334Speter  /* If MODE is no wider than a single word, we return a paradoxical
20218334Speter     SUBREG.  */
20318334Speter  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
20450397Sobrien    return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0);
20518334Speter
20618334Speter  /* Otherwise, get an object of MODE, clobber it, and set the low-order
20718334Speter     part to OP.  */
20818334Speter
20918334Speter  result = gen_reg_rtx (mode);
21050397Sobrien  emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
21118334Speter  emit_move_insn (gen_lowpart (GET_MODE (op), result), op);
21218334Speter  return result;
21318334Speter}
21418334Speter
21552284Sobrien/* Generate code to perform a straightforward complex divide.  */
21652284Sobrien
21752284Sobrienstatic int
21852284Sobrienexpand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
21952284Sobrien			  unsignedp, methods, class, binoptab)
22052284Sobrien  rtx real0, real1, imag0, imag1, realr, imagr;
22152284Sobrien  enum machine_mode submode;
22252284Sobrien  int unsignedp;
22352284Sobrien  enum optab_methods methods;
22452284Sobrien  enum mode_class class;
22552284Sobrien  optab binoptab;
22652284Sobrien{
22752284Sobrien  rtx divisor;
22852284Sobrien  rtx real_t, imag_t;
22952284Sobrien  rtx temp1, temp2;
23052284Sobrien  rtx res;
23190075Sobrien  optab this_add_optab = add_optab;
23290075Sobrien  optab this_sub_optab = sub_optab;
23390075Sobrien  optab this_neg_optab = neg_optab;
23490075Sobrien  optab this_mul_optab = smul_optab;
23552284Sobrien
23690075Sobrien  if (binoptab == sdivv_optab)
23790075Sobrien    {
23890075Sobrien      this_add_optab = addv_optab;
23990075Sobrien      this_sub_optab = subv_optab;
24090075Sobrien      this_neg_optab = negv_optab;
24190075Sobrien      this_mul_optab = smulv_optab;
24290075Sobrien    }
24390075Sobrien
24452284Sobrien  /* Don't fetch these from memory more than once.  */
24552284Sobrien  real0 = force_reg (submode, real0);
24652284Sobrien  real1 = force_reg (submode, real1);
24752284Sobrien
24852284Sobrien  if (imag0 != 0)
24952284Sobrien    imag0 = force_reg (submode, imag0);
25052284Sobrien
25152284Sobrien  imag1 = force_reg (submode, imag1);
25252284Sobrien
25352284Sobrien  /* Divisor: c*c + d*d.  */
25490075Sobrien  temp1 = expand_binop (submode, this_mul_optab, real1, real1,
25552284Sobrien			NULL_RTX, unsignedp, methods);
25652284Sobrien
25790075Sobrien  temp2 = expand_binop (submode, this_mul_optab, imag1, imag1,
25852284Sobrien			NULL_RTX, unsignedp, methods);
25952284Sobrien
26052284Sobrien  if (temp1 == 0 || temp2 == 0)
26152284Sobrien    return 0;
26252284Sobrien
26390075Sobrien  divisor = expand_binop (submode, this_add_optab, temp1, temp2,
26452284Sobrien			  NULL_RTX, unsignedp, methods);
26552284Sobrien  if (divisor == 0)
26652284Sobrien    return 0;
26752284Sobrien
26852284Sobrien  if (imag0 == 0)
26952284Sobrien    {
27052284Sobrien      /* Mathematically, ((a)(c-id))/divisor.  */
27152284Sobrien      /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
27252284Sobrien
27352284Sobrien      /* Calculate the dividend.  */
27490075Sobrien      real_t = expand_binop (submode, this_mul_optab, real0, real1,
27552284Sobrien			     NULL_RTX, unsignedp, methods);
27652284Sobrien
27790075Sobrien      imag_t = expand_binop (submode, this_mul_optab, real0, imag1,
27852284Sobrien			     NULL_RTX, unsignedp, methods);
27952284Sobrien
28052284Sobrien      if (real_t == 0 || imag_t == 0)
28152284Sobrien	return 0;
28252284Sobrien
28390075Sobrien      imag_t = expand_unop (submode, this_neg_optab, imag_t,
28452284Sobrien			    NULL_RTX, unsignedp);
28552284Sobrien    }
28652284Sobrien  else
28752284Sobrien    {
28852284Sobrien      /* Mathematically, ((a+ib)(c-id))/divider.  */
28952284Sobrien      /* Calculate the dividend.  */
29090075Sobrien      temp1 = expand_binop (submode, this_mul_optab, real0, real1,
29152284Sobrien			    NULL_RTX, unsignedp, methods);
29252284Sobrien
29390075Sobrien      temp2 = expand_binop (submode, this_mul_optab, imag0, imag1,
29452284Sobrien			    NULL_RTX, unsignedp, methods);
29552284Sobrien
29652284Sobrien      if (temp1 == 0 || temp2 == 0)
29752284Sobrien	return 0;
29852284Sobrien
29990075Sobrien      real_t = expand_binop (submode, this_add_optab, temp1, temp2,
30052284Sobrien			     NULL_RTX, unsignedp, methods);
30152284Sobrien
30290075Sobrien      temp1 = expand_binop (submode, this_mul_optab, imag0, real1,
30352284Sobrien			    NULL_RTX, unsignedp, methods);
30452284Sobrien
30590075Sobrien      temp2 = expand_binop (submode, this_mul_optab, real0, imag1,
30652284Sobrien			    NULL_RTX, unsignedp, methods);
30752284Sobrien
30852284Sobrien      if (temp1 == 0 || temp2 == 0)
30952284Sobrien	return 0;
31052284Sobrien
31190075Sobrien      imag_t = expand_binop (submode, this_sub_optab, temp1, temp2,
31252284Sobrien			     NULL_RTX, unsignedp, methods);
31352284Sobrien
31452284Sobrien      if (real_t == 0 || imag_t == 0)
31552284Sobrien	return 0;
31652284Sobrien    }
31752284Sobrien
31852284Sobrien  if (class == MODE_COMPLEX_FLOAT)
31952284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
32052284Sobrien			realr, unsignedp, methods);
32152284Sobrien  else
32252284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
32352284Sobrien			 real_t, divisor, realr, unsignedp);
32452284Sobrien
32552284Sobrien  if (res == 0)
32652284Sobrien    return 0;
32752284Sobrien
32852284Sobrien  if (res != realr)
32952284Sobrien    emit_move_insn (realr, res);
33052284Sobrien
33152284Sobrien  if (class == MODE_COMPLEX_FLOAT)
33252284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
33352284Sobrien			imagr, unsignedp, methods);
33452284Sobrien  else
33552284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
33652284Sobrien			 imag_t, divisor, imagr, unsignedp);
33752284Sobrien
33852284Sobrien  if (res == 0)
33952284Sobrien    return 0;
34052284Sobrien
34152284Sobrien  if (res != imagr)
34252284Sobrien    emit_move_insn (imagr, res);
34352284Sobrien
34452284Sobrien  return 1;
34552284Sobrien}
34652284Sobrien
34752284Sobrien/* Generate code to perform a wide-input-range-acceptable complex divide.  */
34852284Sobrien
34952284Sobrienstatic int
35052284Sobrienexpand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
35152284Sobrien		      unsignedp, methods, class, binoptab)
35252284Sobrien  rtx real0, real1, imag0, imag1, realr, imagr;
35352284Sobrien  enum machine_mode submode;
35452284Sobrien  int unsignedp;
35552284Sobrien  enum optab_methods methods;
35652284Sobrien  enum mode_class class;
35752284Sobrien  optab binoptab;
35852284Sobrien{
35952284Sobrien  rtx ratio, divisor;
36052284Sobrien  rtx real_t, imag_t;
36152284Sobrien  rtx temp1, temp2, lab1, lab2;
36252284Sobrien  enum machine_mode mode;
36352284Sobrien  rtx res;
36490075Sobrien  optab this_add_optab = add_optab;
36590075Sobrien  optab this_sub_optab = sub_optab;
36690075Sobrien  optab this_neg_optab = neg_optab;
36790075Sobrien  optab this_mul_optab = smul_optab;
36890075Sobrien
36990075Sobrien  if (binoptab == sdivv_optab)
37090075Sobrien    {
37190075Sobrien      this_add_optab = addv_optab;
37290075Sobrien      this_sub_optab = subv_optab;
37390075Sobrien      this_neg_optab = negv_optab;
37490075Sobrien      this_mul_optab = smulv_optab;
37590075Sobrien    }
37652284Sobrien
37752284Sobrien  /* Don't fetch these from memory more than once.  */
37852284Sobrien  real0 = force_reg (submode, real0);
37952284Sobrien  real1 = force_reg (submode, real1);
38052284Sobrien
38152284Sobrien  if (imag0 != 0)
38252284Sobrien    imag0 = force_reg (submode, imag0);
38352284Sobrien
38452284Sobrien  imag1 = force_reg (submode, imag1);
38552284Sobrien
38652284Sobrien  /* XXX What's an "unsigned" complex number?  */
38752284Sobrien  if (unsignedp)
38852284Sobrien    {
38952284Sobrien      temp1 = real1;
39052284Sobrien      temp2 = imag1;
39152284Sobrien    }
39252284Sobrien  else
39352284Sobrien    {
39490075Sobrien      temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1);
39590075Sobrien      temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1);
39652284Sobrien    }
39752284Sobrien
39852284Sobrien  if (temp1 == 0 || temp2 == 0)
39952284Sobrien    return 0;
40052284Sobrien
40152284Sobrien  mode = GET_MODE (temp1);
40252284Sobrien  lab1 = gen_label_rtx ();
40352284Sobrien  emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX,
40490075Sobrien			   mode, unsignedp, lab1);
40552284Sobrien
40652284Sobrien  /* |c| >= |d|; use ratio d/c to scale dividend and divisor.  */
40752284Sobrien
40852284Sobrien  if (class == MODE_COMPLEX_FLOAT)
40952284Sobrien    ratio = expand_binop (submode, binoptab, imag1, real1,
41052284Sobrien			  NULL_RTX, unsignedp, methods);
41152284Sobrien  else
41252284Sobrien    ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
41352284Sobrien			   imag1, real1, NULL_RTX, unsignedp);
41452284Sobrien
41552284Sobrien  if (ratio == 0)
41652284Sobrien    return 0;
41752284Sobrien
41852284Sobrien  /* Calculate divisor.  */
41952284Sobrien
42090075Sobrien  temp1 = expand_binop (submode, this_mul_optab, imag1, ratio,
42152284Sobrien			NULL_RTX, unsignedp, methods);
42252284Sobrien
42352284Sobrien  if (temp1 == 0)
42452284Sobrien    return 0;
42552284Sobrien
42690075Sobrien  divisor = expand_binop (submode, this_add_optab, temp1, real1,
42752284Sobrien			  NULL_RTX, unsignedp, methods);
42852284Sobrien
42952284Sobrien  if (divisor == 0)
43052284Sobrien    return 0;
43152284Sobrien
43252284Sobrien  /* Calculate dividend.  */
43352284Sobrien
43452284Sobrien  if (imag0 == 0)
43552284Sobrien    {
43652284Sobrien      real_t = real0;
43752284Sobrien
43852284Sobrien      /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)).  */
43952284Sobrien
44090075Sobrien      imag_t = expand_binop (submode, this_mul_optab, real0, ratio,
44152284Sobrien			     NULL_RTX, unsignedp, methods);
44252284Sobrien
44352284Sobrien      if (imag_t == 0)
44452284Sobrien	return 0;
44552284Sobrien
44690075Sobrien      imag_t = expand_unop (submode, this_neg_optab, imag_t,
44752284Sobrien			    NULL_RTX, unsignedp);
44852284Sobrien
44952284Sobrien      if (real_t == 0 || imag_t == 0)
45052284Sobrien	return 0;
45152284Sobrien    }
45252284Sobrien  else
45352284Sobrien    {
45452284Sobrien      /* Compute (a+ib)/(c+id) as
45552284Sobrien	 (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)).  */
45652284Sobrien
45790075Sobrien      temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
45852284Sobrien			    NULL_RTX, unsignedp, methods);
45952284Sobrien
46052284Sobrien      if (temp1 == 0)
46152284Sobrien	return 0;
46252284Sobrien
46390075Sobrien      real_t = expand_binop (submode, this_add_optab, temp1, real0,
46452284Sobrien			     NULL_RTX, unsignedp, methods);
46552284Sobrien
46690075Sobrien      temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
46752284Sobrien			    NULL_RTX, unsignedp, methods);
46852284Sobrien
46952284Sobrien      if (temp1 == 0)
47052284Sobrien	return 0;
47152284Sobrien
47290075Sobrien      imag_t = expand_binop (submode, this_sub_optab, imag0, temp1,
47352284Sobrien			     NULL_RTX, unsignedp, methods);
47452284Sobrien
47552284Sobrien      if (real_t == 0 || imag_t == 0)
47652284Sobrien	return 0;
47752284Sobrien    }
47852284Sobrien
47952284Sobrien  if (class == MODE_COMPLEX_FLOAT)
48052284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
48152284Sobrien			realr, unsignedp, methods);
48252284Sobrien  else
48352284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
48452284Sobrien			 real_t, divisor, realr, unsignedp);
48552284Sobrien
48652284Sobrien  if (res == 0)
48752284Sobrien    return 0;
48852284Sobrien
48952284Sobrien  if (res != realr)
49052284Sobrien    emit_move_insn (realr, res);
49152284Sobrien
49252284Sobrien  if (class == MODE_COMPLEX_FLOAT)
49352284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
49452284Sobrien			imagr, unsignedp, methods);
49552284Sobrien  else
49652284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
49752284Sobrien			 imag_t, divisor, imagr, unsignedp);
49852284Sobrien
49952284Sobrien  if (res == 0)
50052284Sobrien    return 0;
50152284Sobrien
50252284Sobrien  if (res != imagr)
50352284Sobrien    emit_move_insn (imagr, res);
50452284Sobrien
50552284Sobrien  lab2 = gen_label_rtx ();
50652284Sobrien  emit_jump_insn (gen_jump (lab2));
50752284Sobrien  emit_barrier ();
50852284Sobrien
50952284Sobrien  emit_label (lab1);
51052284Sobrien
51152284Sobrien  /* |d| > |c|; use ratio c/d to scale dividend and divisor.  */
51252284Sobrien
51352284Sobrien  if (class == MODE_COMPLEX_FLOAT)
51452284Sobrien    ratio = expand_binop (submode, binoptab, real1, imag1,
51552284Sobrien			  NULL_RTX, unsignedp, methods);
51652284Sobrien  else
51752284Sobrien    ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
51852284Sobrien			   real1, imag1, NULL_RTX, unsignedp);
51952284Sobrien
52052284Sobrien  if (ratio == 0)
52152284Sobrien    return 0;
52252284Sobrien
52352284Sobrien  /* Calculate divisor.  */
52452284Sobrien
52590075Sobrien  temp1 = expand_binop (submode, this_mul_optab, real1, ratio,
52652284Sobrien			NULL_RTX, unsignedp, methods);
52752284Sobrien
52852284Sobrien  if (temp1 == 0)
52952284Sobrien    return 0;
53052284Sobrien
53190075Sobrien  divisor = expand_binop (submode, this_add_optab, temp1, imag1,
53252284Sobrien			  NULL_RTX, unsignedp, methods);
53352284Sobrien
53452284Sobrien  if (divisor == 0)
53552284Sobrien    return 0;
53652284Sobrien
53752284Sobrien  /* Calculate dividend.  */
53852284Sobrien
53952284Sobrien  if (imag0 == 0)
54052284Sobrien    {
54152284Sobrien      /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
54252284Sobrien
54390075Sobrien      real_t = expand_binop (submode, this_mul_optab, real0, ratio,
54452284Sobrien			     NULL_RTX, unsignedp, methods);
54552284Sobrien
54690075Sobrien      imag_t = expand_unop (submode, this_neg_optab, real0,
54752284Sobrien			    NULL_RTX, unsignedp);
54852284Sobrien
54952284Sobrien      if (real_t == 0 || imag_t == 0)
55052284Sobrien	return 0;
55152284Sobrien    }
55252284Sobrien  else
55352284Sobrien    {
55452284Sobrien      /* Compute (a+ib)/(c+id) as
55552284Sobrien	 (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d).  */
55652284Sobrien
55790075Sobrien      temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
55852284Sobrien			    NULL_RTX, unsignedp, methods);
55952284Sobrien
56052284Sobrien      if (temp1 == 0)
56152284Sobrien	return 0;
56252284Sobrien
56390075Sobrien      real_t = expand_binop (submode, this_add_optab, temp1, imag0,
56452284Sobrien			     NULL_RTX, unsignedp, methods);
56552284Sobrien
56690075Sobrien      temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
56752284Sobrien			    NULL_RTX, unsignedp, methods);
56852284Sobrien
56952284Sobrien      if (temp1 == 0)
57052284Sobrien	return 0;
57152284Sobrien
57290075Sobrien      imag_t = expand_binop (submode, this_sub_optab, temp1, real0,
57352284Sobrien			     NULL_RTX, unsignedp, methods);
57452284Sobrien
57552284Sobrien      if (real_t == 0 || imag_t == 0)
57652284Sobrien	return 0;
57752284Sobrien    }
57852284Sobrien
57952284Sobrien  if (class == MODE_COMPLEX_FLOAT)
58052284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
58152284Sobrien			realr, unsignedp, methods);
58252284Sobrien  else
58352284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
58452284Sobrien			 real_t, divisor, realr, unsignedp);
58552284Sobrien
58652284Sobrien  if (res == 0)
58752284Sobrien    return 0;
58852284Sobrien
58952284Sobrien  if (res != realr)
59052284Sobrien    emit_move_insn (realr, res);
59152284Sobrien
59252284Sobrien  if (class == MODE_COMPLEX_FLOAT)
59352284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
59452284Sobrien			imagr, unsignedp, methods);
59552284Sobrien  else
59652284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
59752284Sobrien			 imag_t, divisor, imagr, unsignedp);
59852284Sobrien
59952284Sobrien  if (res == 0)
60052284Sobrien    return 0;
60152284Sobrien
60252284Sobrien  if (res != imagr)
60352284Sobrien    emit_move_insn (imagr, res);
60452284Sobrien
60552284Sobrien  emit_label (lab2);
60652284Sobrien
60752284Sobrien  return 1;
60852284Sobrien}
60952284Sobrien
61090075Sobrien/* Wrapper around expand_binop which takes an rtx code to specify
61190075Sobrien   the operation to perform, not an optab pointer.  All other
61290075Sobrien   arguments are the same.  */
61390075Sobrienrtx
61490075Sobrienexpand_simple_binop (mode, code, op0, op1, target, unsignedp, methods)
61590075Sobrien     enum machine_mode mode;
61690075Sobrien     enum rtx_code code;
61790075Sobrien     rtx op0, op1;
61890075Sobrien     rtx target;
61990075Sobrien     int unsignedp;
62090075Sobrien     enum optab_methods methods;
62190075Sobrien{
62290075Sobrien  optab binop = code_to_optab [(int) code];
62390075Sobrien  if (binop == 0)
62490075Sobrien    abort ();
62590075Sobrien
62690075Sobrien  return expand_binop (mode, binop, op0, op1, target, unsignedp, methods);
62790075Sobrien}
62890075Sobrien
62918334Speter/* Generate code to perform an operation specified by BINOPTAB
63018334Speter   on operands OP0 and OP1, with result having machine-mode MODE.
63118334Speter
63218334Speter   UNSIGNEDP is for the case where we have to widen the operands
63318334Speter   to perform the operation.  It says to use zero-extension.
63418334Speter
63518334Speter   If TARGET is nonzero, the value
63618334Speter   is generated there, if it is convenient to do so.
63718334Speter   In all cases an rtx is returned for the locus of the value;
63818334Speter   this may or may not be TARGET.  */
63918334Speter
64018334Speterrtx
64118334Speterexpand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
64218334Speter     enum machine_mode mode;
64318334Speter     optab binoptab;
64418334Speter     rtx op0, op1;
64518334Speter     rtx target;
64618334Speter     int unsignedp;
64718334Speter     enum optab_methods methods;
64818334Speter{
64918334Speter  enum optab_methods next_methods
65018334Speter    = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
65118334Speter       ? OPTAB_WIDEN : methods);
65218334Speter  enum mode_class class;
65318334Speter  enum machine_mode wider_mode;
65490075Sobrien  rtx temp;
65518334Speter  int commutative_op = 0;
65618334Speter  int shift_op = (binoptab->code ==  ASHIFT
65718334Speter		  || binoptab->code == ASHIFTRT
65818334Speter		  || binoptab->code == LSHIFTRT
65918334Speter		  || binoptab->code == ROTATE
66018334Speter		  || binoptab->code == ROTATERT);
66118334Speter  rtx entry_last = get_last_insn ();
66218334Speter  rtx last;
66318334Speter
66418334Speter  class = GET_MODE_CLASS (mode);
66518334Speter
66618334Speter  op0 = protect_from_queue (op0, 0);
66718334Speter  op1 = protect_from_queue (op1, 0);
66818334Speter  if (target)
66918334Speter    target = protect_from_queue (target, 1);
67018334Speter
67118334Speter  if (flag_force_mem)
67218334Speter    {
67318334Speter      op0 = force_not_mem (op0);
67418334Speter      op1 = force_not_mem (op1);
67518334Speter    }
67618334Speter
67718334Speter  /* If subtracting an integer constant, convert this into an addition of
67818334Speter     the negated constant.  */
67918334Speter
68018334Speter  if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT)
68118334Speter    {
68218334Speter      op1 = negate_rtx (mode, op1);
68318334Speter      binoptab = add_optab;
68418334Speter    }
68518334Speter
68618334Speter  /* If we are inside an appropriately-short loop and one operand is an
68718334Speter     expensive constant, force it into a register.  */
68818334Speter  if (CONSTANT_P (op0) && preserve_subexpressions_p ()
68990075Sobrien      && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
69018334Speter    op0 = force_reg (mode, op0);
69118334Speter
69218334Speter  if (CONSTANT_P (op1) && preserve_subexpressions_p ()
69390075Sobrien      && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
69418334Speter    op1 = force_reg (mode, op1);
69518334Speter
69618334Speter  /* Record where to delete back to if we backtrack.  */
69718334Speter  last = get_last_insn ();
69818334Speter
69918334Speter  /* If operation is commutative,
70018334Speter     try to make the first operand a register.
70118334Speter     Even better, try to make it the same as the target.
70218334Speter     Also try to make the last operand a constant.  */
70318334Speter  if (GET_RTX_CLASS (binoptab->code) == 'c'
70418334Speter      || binoptab == smul_widen_optab
70518334Speter      || binoptab == umul_widen_optab
70618334Speter      || binoptab == smul_highpart_optab
70718334Speter      || binoptab == umul_highpart_optab)
70818334Speter    {
70918334Speter      commutative_op = 1;
71018334Speter
71118334Speter      if (((target == 0 || GET_CODE (target) == REG)
71218334Speter	   ? ((GET_CODE (op1) == REG
71318334Speter	       && GET_CODE (op0) != REG)
71418334Speter	      || target == op1)
71518334Speter	   : rtx_equal_p (op1, target))
71618334Speter	  || GET_CODE (op0) == CONST_INT)
71718334Speter	{
71818334Speter	  temp = op1;
71918334Speter	  op1 = op0;
72018334Speter	  op0 = temp;
72118334Speter	}
72218334Speter    }
72318334Speter
72418334Speter  /* If we can do it with a three-operand insn, do so.  */
72518334Speter
72618334Speter  if (methods != OPTAB_MUST_WIDEN
72718334Speter      && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
72818334Speter    {
72918334Speter      int icode = (int) binoptab->handlers[(int) mode].insn_code;
73090075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
73190075Sobrien      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
73218334Speter      rtx pat;
73318334Speter      rtx xop0 = op0, xop1 = op1;
73418334Speter
73518334Speter      if (target)
73618334Speter	temp = target;
73718334Speter      else
73818334Speter	temp = gen_reg_rtx (mode);
73918334Speter
74018334Speter      /* If it is a commutative operator and the modes would match
74150397Sobrien	 if we would swap the operands, we can save the conversions.  */
74218334Speter      if (commutative_op)
74318334Speter	{
74418334Speter	  if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
74518334Speter	      && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
74618334Speter	    {
74790075Sobrien	      rtx tmp;
74818334Speter
74918334Speter	      tmp = op0; op0 = op1; op1 = tmp;
75018334Speter	      tmp = xop0; xop0 = xop1; xop1 = tmp;
75118334Speter	    }
75218334Speter	}
75318334Speter
75418334Speter      /* In case the insn wants input operands in modes different from
755103445Skan	 those of the actual operands, convert the operands.  It would
756103445Skan	 seem that we don't need to convert CONST_INTs, but we do, so
757103445Skan	 that they're properly zero-extended or sign-extended for their
758103445Skan	 modes; shift operations are an exception, because the second
759103445Skan	 operand needs not be extended to the mode of the result.  */
76018334Speter
76190075Sobrien      if (GET_MODE (op0) != mode0
76218334Speter	  && mode0 != VOIDmode)
76390075Sobrien	xop0 = convert_modes (mode0,
76490075Sobrien			      GET_MODE (op0) != VOIDmode
76590075Sobrien			      ? GET_MODE (op0)
766103445Skan			      : mode,
76790075Sobrien			      xop0, unsignedp);
76818334Speter
76990075Sobrien      if (GET_MODE (xop1) != mode1
77018334Speter	  && mode1 != VOIDmode)
77190075Sobrien	xop1 = convert_modes (mode1,
77290075Sobrien			      GET_MODE (op1) != VOIDmode
77390075Sobrien			      ? GET_MODE (op1)
774103445Skan			      : ! shift_op
77590075Sobrien			      ? mode
77690075Sobrien			      : mode1,
77790075Sobrien			      xop1, unsignedp);
77818334Speter
77918334Speter      /* Now, if insn's predicates don't allow our operands, put them into
78018334Speter	 pseudo regs.  */
78118334Speter
78290075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)
78318334Speter	  && mode0 != VOIDmode)
78418334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
78518334Speter
78690075Sobrien      if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
78718334Speter	  && mode1 != VOIDmode)
78818334Speter	xop1 = copy_to_mode_reg (mode1, xop1);
78918334Speter
79090075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
79118334Speter	temp = gen_reg_rtx (mode);
79218334Speter
79318334Speter      pat = GEN_FCN (icode) (temp, xop0, xop1);
79418334Speter      if (pat)
79518334Speter	{
79618334Speter	  /* If PAT is a multi-insn sequence, try to add an appropriate
79718334Speter	     REG_EQUAL note to it.  If we can't because TEMP conflicts with an
79818334Speter	     operand, call ourselves again, this time without a target.  */
79918334Speter	  if (GET_CODE (pat) == SEQUENCE
80018334Speter	      && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
80118334Speter	    {
80218334Speter	      delete_insns_since (last);
80318334Speter	      return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
80418334Speter				   unsignedp, methods);
80518334Speter	    }
80618334Speter
80718334Speter	  emit_insn (pat);
80818334Speter	  return temp;
80918334Speter	}
81018334Speter      else
81118334Speter	delete_insns_since (last);
81218334Speter    }
81318334Speter
81418334Speter  /* If this is a multiply, see if we can do a widening operation that
81518334Speter     takes operands of this mode and makes a wider mode.  */
81618334Speter
81718334Speter  if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode
81818334Speter      && (((unsignedp ? umul_widen_optab : smul_widen_optab)
81918334Speter	   ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code)
82018334Speter	  != CODE_FOR_nothing))
82118334Speter    {
82218334Speter      temp = expand_binop (GET_MODE_WIDER_MODE (mode),
82318334Speter			   unsignedp ? umul_widen_optab : smul_widen_optab,
82418334Speter			   op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);
82518334Speter
82618334Speter      if (temp != 0)
82718334Speter	{
82818334Speter	  if (GET_MODE_CLASS (mode) == MODE_INT)
82918334Speter	    return gen_lowpart (mode, temp);
83018334Speter	  else
83118334Speter	    return convert_to_mode (mode, temp, unsignedp);
83218334Speter	}
83318334Speter    }
83418334Speter
83518334Speter  /* Look for a wider mode of the same class for which we think we
83618334Speter     can open-code the operation.  Check for a widening multiply at the
83718334Speter     wider mode as well.  */
83818334Speter
83918334Speter  if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
84018334Speter      && methods != OPTAB_DIRECT && methods != OPTAB_LIB)
84118334Speter    for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
84218334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
84318334Speter      {
84418334Speter	if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
84518334Speter	    || (binoptab == smul_optab
84618334Speter		&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
84718334Speter		&& (((unsignedp ? umul_widen_optab : smul_widen_optab)
84818334Speter		     ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code)
84918334Speter		    != CODE_FOR_nothing)))
85018334Speter	  {
85118334Speter	    rtx xop0 = op0, xop1 = op1;
85218334Speter	    int no_extend = 0;
85318334Speter
85418334Speter	    /* For certain integer operations, we need not actually extend
85518334Speter	       the narrow operands, as long as we will truncate
85690075Sobrien	       the results to the same narrowness.  */
85718334Speter
85818334Speter	    if ((binoptab == ior_optab || binoptab == and_optab
85918334Speter		 || binoptab == xor_optab
86018334Speter		 || binoptab == add_optab || binoptab == sub_optab
86118334Speter		 || binoptab == smul_optab || binoptab == ashl_optab)
86218334Speter		&& class == MODE_INT)
86318334Speter	      no_extend = 1;
86418334Speter
86518334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend);
86618334Speter
86718334Speter	    /* The second operand of a shift must always be extended.  */
86818334Speter	    xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
86918334Speter				  no_extend && binoptab != ashl_optab);
87018334Speter
87118334Speter	    temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
87218334Speter				 unsignedp, OPTAB_DIRECT);
87318334Speter	    if (temp)
87418334Speter	      {
87518334Speter		if (class != MODE_INT)
87618334Speter		  {
87718334Speter		    if (target == 0)
87818334Speter		      target = gen_reg_rtx (mode);
87918334Speter		    convert_move (target, temp, 0);
88018334Speter		    return target;
88118334Speter		  }
88218334Speter		else
88318334Speter		  return gen_lowpart (mode, temp);
88418334Speter	      }
88518334Speter	    else
88618334Speter	      delete_insns_since (last);
88718334Speter	  }
88818334Speter      }
88918334Speter
89018334Speter  /* These can be done a word at a time.  */
89118334Speter  if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
89218334Speter      && class == MODE_INT
89318334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
89418334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
89518334Speter    {
89618334Speter      int i;
89718334Speter      rtx insns;
89818334Speter      rtx equiv_value;
89918334Speter
90018334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
90118334Speter	 won't be accurate, so use a new target.  */
90218334Speter      if (target == 0 || target == op0 || target == op1)
90318334Speter	target = gen_reg_rtx (mode);
90418334Speter
90518334Speter      start_sequence ();
90618334Speter
90718334Speter      /* Do the actual arithmetic.  */
90818334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
90918334Speter	{
91018334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
91118334Speter	  rtx x = expand_binop (word_mode, binoptab,
91218334Speter				operand_subword_force (op0, i, mode),
91318334Speter				operand_subword_force (op1, i, mode),
91418334Speter				target_piece, unsignedp, next_methods);
91518334Speter
91618334Speter	  if (x == 0)
91718334Speter	    break;
91818334Speter
91918334Speter	  if (target_piece != x)
92018334Speter	    emit_move_insn (target_piece, x);
92118334Speter	}
92218334Speter
92318334Speter      insns = get_insns ();
92418334Speter      end_sequence ();
92518334Speter
92618334Speter      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
92718334Speter	{
92818334Speter	  if (binoptab->code != UNKNOWN)
92918334Speter	    equiv_value
93050397Sobrien	      = gen_rtx_fmt_ee (binoptab->code, mode,
93150397Sobrien				copy_rtx (op0), copy_rtx (op1));
93218334Speter	  else
93318334Speter	    equiv_value = 0;
93418334Speter
93518334Speter	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);
93618334Speter	  return target;
93718334Speter	}
93818334Speter    }
93918334Speter
94018334Speter  /* Synthesize double word shifts from single word shifts.  */
94118334Speter  if ((binoptab == lshr_optab || binoptab == ashl_optab
94218334Speter       || binoptab == ashr_optab)
94318334Speter      && class == MODE_INT
94418334Speter      && GET_CODE (op1) == CONST_INT
94518334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
94618334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
94718334Speter      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
94818334Speter      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
94918334Speter    {
95018334Speter      rtx insns, inter, equiv_value;
95118334Speter      rtx into_target, outof_target;
95218334Speter      rtx into_input, outof_input;
95318334Speter      int shift_count, left_shift, outof_word;
95418334Speter
95518334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
95618334Speter	 won't be accurate, so use a new target.  */
95718334Speter      if (target == 0 || target == op0 || target == op1)
95818334Speter	target = gen_reg_rtx (mode);
95918334Speter
96018334Speter      start_sequence ();
96118334Speter
96218334Speter      shift_count = INTVAL (op1);
96318334Speter
96418334Speter      /* OUTOF_* is the word we are shifting bits away from, and
96518334Speter	 INTO_* is the word that we are shifting bits towards, thus
96618334Speter	 they differ depending on the direction of the shift and
96718334Speter	 WORDS_BIG_ENDIAN.  */
96818334Speter
96918334Speter      left_shift = binoptab == ashl_optab;
97018334Speter      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
97118334Speter
97218334Speter      outof_target = operand_subword (target, outof_word, 1, mode);
97318334Speter      into_target = operand_subword (target, 1 - outof_word, 1, mode);
97418334Speter
97518334Speter      outof_input = operand_subword_force (op0, outof_word, mode);
97618334Speter      into_input = operand_subword_force (op0, 1 - outof_word, mode);
97718334Speter
97818334Speter      if (shift_count >= BITS_PER_WORD)
97918334Speter	{
98018334Speter	  inter = expand_binop (word_mode, binoptab,
98118334Speter			       outof_input,
98218334Speter			       GEN_INT (shift_count - BITS_PER_WORD),
98318334Speter			       into_target, unsignedp, next_methods);
98418334Speter
98518334Speter	  if (inter != 0 && inter != into_target)
98618334Speter	    emit_move_insn (into_target, inter);
98718334Speter
98818334Speter	  /* For a signed right shift, we must fill the word we are shifting
98918334Speter	     out of with copies of the sign bit.  Otherwise it is zeroed.  */
99018334Speter	  if (inter != 0 && binoptab != ashr_optab)
99118334Speter	    inter = CONST0_RTX (word_mode);
99218334Speter	  else if (inter != 0)
99318334Speter	    inter = expand_binop (word_mode, binoptab,
99418334Speter				  outof_input,
99518334Speter				  GEN_INT (BITS_PER_WORD - 1),
99618334Speter				  outof_target, unsignedp, next_methods);
99718334Speter
99818334Speter	  if (inter != 0 && inter != outof_target)
99918334Speter	    emit_move_insn (outof_target, inter);
100018334Speter	}
100118334Speter      else
100218334Speter	{
100318334Speter	  rtx carries;
100418334Speter	  optab reverse_unsigned_shift, unsigned_shift;
100518334Speter
100618334Speter	  /* For a shift of less then BITS_PER_WORD, to compute the carry,
100718334Speter	     we must do a logical shift in the opposite direction of the
100818334Speter	     desired shift.  */
100918334Speter
101018334Speter	  reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab);
101118334Speter
101218334Speter	  /* For a shift of less than BITS_PER_WORD, to compute the word
101318334Speter	     shifted towards, we need to unsigned shift the orig value of
101418334Speter	     that word.  */
101518334Speter
101618334Speter	  unsigned_shift = (left_shift ? ashl_optab : lshr_optab);
101718334Speter
101818334Speter	  carries = expand_binop (word_mode, reverse_unsigned_shift,
101918334Speter				  outof_input,
102018334Speter				  GEN_INT (BITS_PER_WORD - shift_count),
102118334Speter				  0, unsignedp, next_methods);
102218334Speter
102318334Speter	  if (carries == 0)
102418334Speter	    inter = 0;
102518334Speter	  else
102618334Speter	    inter = expand_binop (word_mode, unsigned_shift, into_input,
102718334Speter				  op1, 0, unsignedp, next_methods);
102818334Speter
102918334Speter	  if (inter != 0)
103018334Speter	    inter = expand_binop (word_mode, ior_optab, carries, inter,
103118334Speter				  into_target, unsignedp, next_methods);
103218334Speter
103318334Speter	  if (inter != 0 && inter != into_target)
103418334Speter	    emit_move_insn (into_target, inter);
103518334Speter
103618334Speter	  if (inter != 0)
103718334Speter	    inter = expand_binop (word_mode, binoptab, outof_input,
103818334Speter				  op1, outof_target, unsignedp, next_methods);
103918334Speter
104018334Speter	  if (inter != 0 && inter != outof_target)
104118334Speter	    emit_move_insn (outof_target, inter);
104218334Speter	}
104318334Speter
104418334Speter      insns = get_insns ();
104518334Speter      end_sequence ();
104618334Speter
104718334Speter      if (inter != 0)
104818334Speter	{
104918334Speter	  if (binoptab->code != UNKNOWN)
105050397Sobrien	    equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
105118334Speter	  else
105218334Speter	    equiv_value = 0;
105318334Speter
105418334Speter	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);
105518334Speter	  return target;
105618334Speter	}
105718334Speter    }
105818334Speter
105918334Speter  /* Synthesize double word rotates from single word shifts.  */
106018334Speter  if ((binoptab == rotl_optab || binoptab == rotr_optab)
106118334Speter      && class == MODE_INT
106218334Speter      && GET_CODE (op1) == CONST_INT
106318334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
106418334Speter      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
106518334Speter      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
106618334Speter    {
106718334Speter      rtx insns, equiv_value;
106818334Speter      rtx into_target, outof_target;
106918334Speter      rtx into_input, outof_input;
107018334Speter      rtx inter;
107118334Speter      int shift_count, left_shift, outof_word;
107218334Speter
107318334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
107418334Speter	 won't be accurate, so use a new target.  */
107518334Speter      if (target == 0 || target == op0 || target == op1)
107618334Speter	target = gen_reg_rtx (mode);
107718334Speter
107818334Speter      start_sequence ();
107918334Speter
108018334Speter      shift_count = INTVAL (op1);
108118334Speter
108218334Speter      /* OUTOF_* is the word we are shifting bits away from, and
108318334Speter	 INTO_* is the word that we are shifting bits towards, thus
108418334Speter	 they differ depending on the direction of the shift and
108518334Speter	 WORDS_BIG_ENDIAN.  */
108618334Speter
108718334Speter      left_shift = (binoptab == rotl_optab);
108818334Speter      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
108918334Speter
109018334Speter      outof_target = operand_subword (target, outof_word, 1, mode);
109118334Speter      into_target = operand_subword (target, 1 - outof_word, 1, mode);
109218334Speter
109318334Speter      outof_input = operand_subword_force (op0, outof_word, mode);
109418334Speter      into_input = operand_subword_force (op0, 1 - outof_word, mode);
109518334Speter
109618334Speter      if (shift_count == BITS_PER_WORD)
109718334Speter	{
109818334Speter	  /* This is just a word swap.  */
109918334Speter	  emit_move_insn (outof_target, into_input);
110018334Speter	  emit_move_insn (into_target, outof_input);
110118334Speter	  inter = const0_rtx;
110218334Speter	}
110318334Speter      else
110418334Speter	{
110518334Speter	  rtx into_temp1, into_temp2, outof_temp1, outof_temp2;
110618334Speter	  rtx first_shift_count, second_shift_count;
110718334Speter	  optab reverse_unsigned_shift, unsigned_shift;
110818334Speter
110918334Speter	  reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
111018334Speter				    ? lshr_optab : ashl_optab);
111118334Speter
111218334Speter	  unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
111318334Speter			    ? ashl_optab : lshr_optab);
111418334Speter
111518334Speter	  if (shift_count > BITS_PER_WORD)
111618334Speter	    {
111718334Speter	      first_shift_count = GEN_INT (shift_count - BITS_PER_WORD);
111818334Speter	      second_shift_count = GEN_INT (2*BITS_PER_WORD - shift_count);
111918334Speter	    }
112018334Speter	  else
112118334Speter	    {
112218334Speter	      first_shift_count = GEN_INT (BITS_PER_WORD - shift_count);
112318334Speter	      second_shift_count = GEN_INT (shift_count);
112418334Speter	    }
112518334Speter
112618334Speter	  into_temp1 = expand_binop (word_mode, unsigned_shift,
112718334Speter				     outof_input, first_shift_count,
112818334Speter				     NULL_RTX, unsignedp, next_methods);
112918334Speter	  into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
113018334Speter				     into_input, second_shift_count,
113118334Speter				     into_target, unsignedp, next_methods);
113218334Speter
113318334Speter	  if (into_temp1 != 0 && into_temp2 != 0)
113418334Speter	    inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2,
113518334Speter				  into_target, unsignedp, next_methods);
113618334Speter	  else
113718334Speter	    inter = 0;
113818334Speter
113918334Speter	  if (inter != 0 && inter != into_target)
114018334Speter	    emit_move_insn (into_target, inter);
114118334Speter
114218334Speter	  outof_temp1 = expand_binop (word_mode, unsigned_shift,
114318334Speter				      into_input, first_shift_count,
114418334Speter				      NULL_RTX, unsignedp, next_methods);
114518334Speter	  outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
114618334Speter				      outof_input, second_shift_count,
114718334Speter				      outof_target, unsignedp, next_methods);
114818334Speter
114918334Speter	  if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)
115018334Speter	    inter = expand_binop (word_mode, ior_optab,
115118334Speter				  outof_temp1, outof_temp2,
115218334Speter				  outof_target, unsignedp, next_methods);
115318334Speter
115418334Speter	  if (inter != 0 && inter != outof_target)
115518334Speter	    emit_move_insn (outof_target, inter);
115618334Speter	}
115718334Speter
115818334Speter      insns = get_insns ();
115918334Speter      end_sequence ();
116018334Speter
116118334Speter      if (inter != 0)
116218334Speter	{
116318334Speter	  if (binoptab->code != UNKNOWN)
116450397Sobrien	    equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
116518334Speter	  else
116618334Speter	    equiv_value = 0;
116718334Speter
116818334Speter	  /* We can't make this a no conflict block if this is a word swap,
116918334Speter	     because the word swap case fails if the input and output values
117018334Speter	     are in the same register.  */
117118334Speter	  if (shift_count != BITS_PER_WORD)
117218334Speter	    emit_no_conflict_block (insns, target, op0, op1, equiv_value);
117318334Speter	  else
117418334Speter	    emit_insns (insns);
117518334Speter
117618334Speter
117718334Speter	  return target;
117818334Speter	}
117918334Speter    }
118018334Speter
118118334Speter  /* These can be done a word at a time by propagating carries.  */
118218334Speter  if ((binoptab == add_optab || binoptab == sub_optab)
118318334Speter      && class == MODE_INT
118418334Speter      && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD
118518334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
118618334Speter    {
118718334Speter      int i;
118818334Speter      optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
1189102780Skan      int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
119052284Sobrien      rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
1191102780Skan      rtx xop0, xop1, xtarget;
119218334Speter
119318334Speter      /* We can handle either a 1 or -1 value for the carry.  If STORE_FLAG
119418334Speter	 value is one of those, use it.  Otherwise, use 1 since it is the
119518334Speter	 one easiest to get.  */
119618334Speter#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
119718334Speter      int normalizep = STORE_FLAG_VALUE;
119818334Speter#else
119918334Speter      int normalizep = 1;
120018334Speter#endif
120118334Speter
120218334Speter      /* Prepare the operands.  */
120318334Speter      xop0 = force_reg (mode, op0);
120418334Speter      xop1 = force_reg (mode, op1);
120518334Speter
1206102780Skan      xtarget = gen_reg_rtx (mode);
120718334Speter
1208102780Skan      if (target == 0 || GET_CODE (target) != REG)
1209102780Skan	target = xtarget;
1210102780Skan
121118334Speter      /* Indicate for flow that the entire target reg is being set.  */
121218334Speter      if (GET_CODE (target) == REG)
1213102780Skan	emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget));
121418334Speter
121518334Speter      /* Do the actual arithmetic.  */
121618334Speter      for (i = 0; i < nwords; i++)
121718334Speter	{
121818334Speter	  int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
1219102780Skan	  rtx target_piece = operand_subword (xtarget, index, 1, mode);
122018334Speter	  rtx op0_piece = operand_subword_force (xop0, index, mode);
122118334Speter	  rtx op1_piece = operand_subword_force (xop1, index, mode);
122218334Speter	  rtx x;
122318334Speter
122418334Speter	  /* Main add/subtract of the input operands.  */
122518334Speter	  x = expand_binop (word_mode, binoptab,
122618334Speter			    op0_piece, op1_piece,
122718334Speter			    target_piece, unsignedp, next_methods);
122818334Speter	  if (x == 0)
122918334Speter	    break;
123018334Speter
123118334Speter	  if (i + 1 < nwords)
123218334Speter	    {
123318334Speter	      /* Store carry from main add/subtract.  */
123418334Speter	      carry_out = gen_reg_rtx (word_mode);
123550397Sobrien	      carry_out = emit_store_flag_force (carry_out,
123650397Sobrien						 (binoptab == add_optab
123790075Sobrien						  ? LT : GT),
123850397Sobrien						 x, op0_piece,
123950397Sobrien						 word_mode, 1, normalizep);
124018334Speter	    }
124118334Speter
124218334Speter	  if (i > 0)
124318334Speter	    {
124490075Sobrien	      rtx newx;
124590075Sobrien
124618334Speter	      /* Add/subtract previous carry to main result.  */
124790075Sobrien	      newx = expand_binop (word_mode,
124890075Sobrien				   normalizep == 1 ? binoptab : otheroptab,
124990075Sobrien				   x, carry_in,
125090075Sobrien				   NULL_RTX, 1, next_methods);
125118334Speter
125218334Speter	      if (i + 1 < nwords)
125318334Speter		{
125418334Speter		  /* Get out carry from adding/subtracting carry in.  */
125590075Sobrien		  rtx carry_tmp = gen_reg_rtx (word_mode);
125650397Sobrien		  carry_tmp = emit_store_flag_force (carry_tmp,
125790075Sobrien						     (binoptab == add_optab
125890075Sobrien						      ? LT : GT),
125990075Sobrien						     newx, x,
126050397Sobrien						     word_mode, 1, normalizep);
126118334Speter
126218334Speter		  /* Logical-ior the two poss. carry together.  */
126318334Speter		  carry_out = expand_binop (word_mode, ior_optab,
126418334Speter					    carry_out, carry_tmp,
126518334Speter					    carry_out, 0, next_methods);
126618334Speter		  if (carry_out == 0)
126718334Speter		    break;
126818334Speter		}
126990075Sobrien	      emit_move_insn (target_piece, newx);
127018334Speter	    }
127118334Speter
127218334Speter	  carry_in = carry_out;
127318334Speter	}
127418334Speter
127518334Speter      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
127618334Speter	{
127750397Sobrien	  if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
127850397Sobrien	    {
1279102780Skan	      rtx temp = emit_move_insn (target, xtarget);
128018334Speter
128152284Sobrien	      set_unique_reg_note (temp,
128252284Sobrien	      			   REG_EQUAL,
128352284Sobrien				   gen_rtx_fmt_ee (binoptab->code, mode,
128452284Sobrien						   copy_rtx (xop0),
128552284Sobrien						   copy_rtx (xop1)));
128650397Sobrien	    }
128790075Sobrien
128818334Speter	  return target;
128918334Speter	}
129090075Sobrien
129118334Speter      else
129218334Speter	delete_insns_since (last);
129318334Speter    }
129418334Speter
129518334Speter  /* If we want to multiply two two-word values and have normal and widening
129618334Speter     multiplies of single-word values, we can do this with three smaller
129718334Speter     multiplications.  Note that we do not make a REG_NO_CONFLICT block here
129818334Speter     because we are not operating on one word at a time.
129918334Speter
130018334Speter     The multiplication proceeds as follows:
130118334Speter			         _______________________
130218334Speter			        [__op0_high_|__op0_low__]
130318334Speter			         _______________________
130418334Speter        *			[__op1_high_|__op1_low__]
130518334Speter        _______________________________________________
130618334Speter			         _______________________
130718334Speter    (1)				[__op0_low__*__op1_low__]
130818334Speter		     _______________________
130918334Speter    (2a)	    [__op0_low__*__op1_high_]
131018334Speter		     _______________________
131118334Speter    (2b)	    [__op0_high_*__op1_low__]
131218334Speter         _______________________
131318334Speter    (3) [__op0_high_*__op1_high_]
131418334Speter
131518334Speter
131618334Speter    This gives a 4-word result.  Since we are only interested in the
131718334Speter    lower 2 words, partial result (3) and the upper words of (2a) and
131818334Speter    (2b) don't need to be calculated.  Hence (2a) and (2b) can be
131918334Speter    calculated using non-widening multiplication.
132018334Speter
132118334Speter    (1), however, needs to be calculated with an unsigned widening
132218334Speter    multiplication.  If this operation is not directly supported we
132318334Speter    try using a signed widening multiplication and adjust the result.
132418334Speter    This adjustment works as follows:
132518334Speter
132618334Speter      If both operands are positive then no adjustment is needed.
132718334Speter
132818334Speter      If the operands have different signs, for example op0_low < 0 and
132918334Speter      op1_low >= 0, the instruction treats the most significant bit of
133018334Speter      op0_low as a sign bit instead of a bit with significance
133118334Speter      2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low
133218334Speter      with 2**BITS_PER_WORD - op0_low, and two's complements the
133318334Speter      result.  Conclusion: We need to add op1_low * 2**BITS_PER_WORD to
133418334Speter      the result.
133518334Speter
133618334Speter      Similarly, if both operands are negative, we need to add
133718334Speter      (op0_low + op1_low) * 2**BITS_PER_WORD.
133818334Speter
133918334Speter      We use a trick to adjust quickly.  We logically shift op0_low right
134018334Speter      (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to
134118334Speter      op0_high (op1_high) before it is used to calculate 2b (2a).  If no
134218334Speter      logical shift exists, we do an arithmetic right shift and subtract
134318334Speter      the 0 or -1.  */
134418334Speter
134518334Speter  if (binoptab == smul_optab
134618334Speter      && class == MODE_INT
134718334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
134818334Speter      && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
134918334Speter      && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
135018334Speter      && ((umul_widen_optab->handlers[(int) mode].insn_code
135118334Speter	   != CODE_FOR_nothing)
135218334Speter	  || (smul_widen_optab->handlers[(int) mode].insn_code
135318334Speter	      != CODE_FOR_nothing)))
135418334Speter    {
135518334Speter      int low = (WORDS_BIG_ENDIAN ? 1 : 0);
135618334Speter      int high = (WORDS_BIG_ENDIAN ? 0 : 1);
135718334Speter      rtx op0_high = operand_subword_force (op0, high, mode);
135818334Speter      rtx op0_low = operand_subword_force (op0, low, mode);
135918334Speter      rtx op1_high = operand_subword_force (op1, high, mode);
136018334Speter      rtx op1_low = operand_subword_force (op1, low, mode);
136118334Speter      rtx product = 0;
136252284Sobrien      rtx op0_xhigh = NULL_RTX;
136352284Sobrien      rtx op1_xhigh = NULL_RTX;
136418334Speter
136518334Speter      /* If the target is the same as one of the inputs, don't use it.  This
136618334Speter	 prevents problems with the REG_EQUAL note.  */
136718334Speter      if (target == op0 || target == op1
136818334Speter	  || (target != 0 && GET_CODE (target) != REG))
136918334Speter	target = 0;
137018334Speter
137118334Speter      /* Multiply the two lower words to get a double-word product.
137218334Speter	 If unsigned widening multiplication is available, use that;
137318334Speter	 otherwise use the signed form and compensate.  */
137418334Speter
137518334Speter      if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
137618334Speter	{
137718334Speter	  product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,
137818334Speter				  target, 1, OPTAB_DIRECT);
137918334Speter
138018334Speter	  /* If we didn't succeed, delete everything we did so far.  */
138118334Speter	  if (product == 0)
138218334Speter	    delete_insns_since (last);
138318334Speter	  else
138418334Speter	    op0_xhigh = op0_high, op1_xhigh = op1_high;
138518334Speter	}
138618334Speter
138718334Speter      if (product == 0
138818334Speter	  && smul_widen_optab->handlers[(int) mode].insn_code
138918334Speter	       != CODE_FOR_nothing)
139018334Speter	{
139118334Speter	  rtx wordm1 = GEN_INT (BITS_PER_WORD - 1);
139218334Speter	  product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
139318334Speter				  target, 1, OPTAB_DIRECT);
139418334Speter	  op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
139518334Speter				    NULL_RTX, 1, next_methods);
139618334Speter	  if (op0_xhigh)
139718334Speter	    op0_xhigh = expand_binop (word_mode, add_optab, op0_high,
139818334Speter				      op0_xhigh, op0_xhigh, 0, next_methods);
139918334Speter	  else
140018334Speter	    {
140118334Speter	      op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
140218334Speter					NULL_RTX, 0, next_methods);
140318334Speter	      if (op0_xhigh)
140418334Speter		op0_xhigh = expand_binop (word_mode, sub_optab, op0_high,
140518334Speter					  op0_xhigh, op0_xhigh, 0,
140618334Speter					  next_methods);
140718334Speter	    }
140818334Speter
140918334Speter	  op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
141018334Speter				    NULL_RTX, 1, next_methods);
141118334Speter	  if (op1_xhigh)
141218334Speter	    op1_xhigh = expand_binop (word_mode, add_optab, op1_high,
141318334Speter				      op1_xhigh, op1_xhigh, 0, next_methods);
141418334Speter	  else
141518334Speter	    {
141618334Speter	      op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
141718334Speter					NULL_RTX, 0, next_methods);
141818334Speter	      if (op1_xhigh)
141918334Speter		op1_xhigh = expand_binop (word_mode, sub_optab, op1_high,
142018334Speter					  op1_xhigh, op1_xhigh, 0,
142118334Speter					  next_methods);
142218334Speter	    }
142318334Speter	}
142418334Speter
142518334Speter      /* If we have been able to directly compute the product of the
142618334Speter	 low-order words of the operands and perform any required adjustments
142718334Speter	 of the operands, we proceed by trying two more multiplications
142818334Speter	 and then computing the appropriate sum.
142918334Speter
143018334Speter	 We have checked above that the required addition is provided.
143118334Speter	 Full-word addition will normally always succeed, especially if
143218334Speter	 it is provided at all, so we don't worry about its failure.  The
143318334Speter	 multiplication may well fail, however, so we do handle that.  */
143418334Speter
143518334Speter      if (product && op0_xhigh && op1_xhigh)
143618334Speter	{
143718334Speter	  rtx product_high = operand_subword (product, high, 1, mode);
143818334Speter	  rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
143918334Speter				   NULL_RTX, 0, OPTAB_DIRECT);
144018334Speter
1441102780Skan	  if (!REG_P (product_high))
1442102780Skan	    product_high = force_reg (word_mode, product_high);
1443102780Skan
144418334Speter	  if (temp != 0)
144518334Speter	    temp = expand_binop (word_mode, add_optab, temp, product_high,
144618334Speter				 product_high, 0, next_methods);
144718334Speter
144818334Speter	  if (temp != 0 && temp != product_high)
144918334Speter	    emit_move_insn (product_high, temp);
145018334Speter
145118334Speter	  if (temp != 0)
145218334Speter	    temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
145318334Speter				 NULL_RTX, 0, OPTAB_DIRECT);
145418334Speter
145518334Speter	  if (temp != 0)
145618334Speter	    temp = expand_binop (word_mode, add_optab, temp,
145718334Speter				 product_high, product_high,
145818334Speter				 0, next_methods);
145918334Speter
146018334Speter	  if (temp != 0 && temp != product_high)
146118334Speter	    emit_move_insn (product_high, temp);
146218334Speter
1463102780Skan	  emit_move_insn (operand_subword (product, high, 1, mode), product_high);
1464102780Skan
146518334Speter	  if (temp != 0)
146618334Speter	    {
146750397Sobrien	      if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
146850397Sobrien		{
146950397Sobrien		  temp = emit_move_insn (product, product);
147052284Sobrien		  set_unique_reg_note (temp,
147152284Sobrien		  		       REG_EQUAL,
147252284Sobrien				       gen_rtx_fmt_ee (MULT, mode,
147352284Sobrien						       copy_rtx (op0),
147452284Sobrien						       copy_rtx (op1)));
147550397Sobrien		}
147690075Sobrien
147718334Speter	      return product;
147818334Speter	    }
147918334Speter	}
148018334Speter
148118334Speter      /* If we get here, we couldn't do it for some reason even though we
148218334Speter	 originally thought we could.  Delete anything we've emitted in
148318334Speter	 trying to do it.  */
148418334Speter
148518334Speter      delete_insns_since (last);
148618334Speter    }
148718334Speter
148818334Speter  /* We need to open-code the complex type operations: '+, -, * and /' */
148918334Speter
149018334Speter  /* At this point we allow operations between two similar complex
149118334Speter     numbers, and also if one of the operands is not a complex number
149218334Speter     but rather of MODE_FLOAT or MODE_INT. However, the caller
149318334Speter     must make sure that the MODE of the non-complex operand matches
149418334Speter     the SUBMODE of the complex operand.  */
149518334Speter
149618334Speter  if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
149718334Speter    {
149818334Speter      rtx real0 = 0, imag0 = 0;
149918334Speter      rtx real1 = 0, imag1 = 0;
150018334Speter      rtx realr, imagr, res;
150118334Speter      rtx seq;
150218334Speter      rtx equiv_value;
150318334Speter      int ok = 0;
150418334Speter
150518334Speter      /* Find the correct mode for the real and imaginary parts */
150618334Speter      enum machine_mode submode
150718334Speter	= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
150818334Speter			 class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
150918334Speter			 0);
151018334Speter
151118334Speter      if (submode == BLKmode)
151218334Speter	abort ();
151318334Speter
151418334Speter      if (! target)
151518334Speter	target = gen_reg_rtx (mode);
151618334Speter
151718334Speter      start_sequence ();
151818334Speter
151952284Sobrien      realr = gen_realpart (submode, target);
152018334Speter      imagr = gen_imagpart (submode, target);
152118334Speter
152218334Speter      if (GET_MODE (op0) == mode)
152318334Speter	{
152452284Sobrien	  real0 = gen_realpart (submode, op0);
152518334Speter	  imag0 = gen_imagpart (submode, op0);
152618334Speter	}
152718334Speter      else
152818334Speter	real0 = op0;
152918334Speter
153018334Speter      if (GET_MODE (op1) == mode)
153118334Speter	{
153252284Sobrien	  real1 = gen_realpart (submode, op1);
153318334Speter	  imag1 = gen_imagpart (submode, op1);
153418334Speter	}
153518334Speter      else
153618334Speter	real1 = op1;
153718334Speter
153818334Speter      if (real0 == 0 || real1 == 0 || ! (imag0 != 0|| imag1 != 0))
153918334Speter	abort ();
154018334Speter
154118334Speter      switch (binoptab->code)
154218334Speter	{
154318334Speter	case PLUS:
154418334Speter	  /* (a+ib) + (c+id) = (a+c) + i(b+d) */
154518334Speter	case MINUS:
154618334Speter	  /* (a+ib) - (c+id) = (a-c) + i(b-d) */
154718334Speter	  res = expand_binop (submode, binoptab, real0, real1,
154818334Speter			      realr, unsignedp, methods);
154918334Speter
155018334Speter	  if (res == 0)
155118334Speter	    break;
155218334Speter	  else if (res != realr)
155318334Speter	    emit_move_insn (realr, res);
155418334Speter
155518334Speter	  if (imag0 && imag1)
155618334Speter	    res = expand_binop (submode, binoptab, imag0, imag1,
155718334Speter				imagr, unsignedp, methods);
155818334Speter	  else if (imag0)
155918334Speter	    res = imag0;
156018334Speter	  else if (binoptab->code == MINUS)
156190075Sobrien            res = expand_unop (submode,
156290075Sobrien                                binoptab == subv_optab ? negv_optab : neg_optab,
156390075Sobrien                                imag1, imagr, unsignedp);
156418334Speter	  else
156518334Speter	    res = imag1;
156618334Speter
156718334Speter	  if (res == 0)
156818334Speter	    break;
156918334Speter	  else if (res != imagr)
157018334Speter	    emit_move_insn (imagr, res);
157118334Speter
157218334Speter	  ok = 1;
157318334Speter	  break;
157418334Speter
157518334Speter	case MULT:
157618334Speter	  /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
157718334Speter
157818334Speter	  if (imag0 && imag1)
157918334Speter	    {
158018334Speter	      rtx temp1, temp2;
158118334Speter
158218334Speter	      /* Don't fetch these from memory more than once.  */
158318334Speter	      real0 = force_reg (submode, real0);
158418334Speter	      real1 = force_reg (submode, real1);
158518334Speter	      imag0 = force_reg (submode, imag0);
158618334Speter	      imag1 = force_reg (submode, imag1);
158718334Speter
158818334Speter	      temp1 = expand_binop (submode, binoptab, real0, real1, NULL_RTX,
158918334Speter				    unsignedp, methods);
159018334Speter
159118334Speter	      temp2 = expand_binop (submode, binoptab, imag0, imag1, NULL_RTX,
159218334Speter				    unsignedp, methods);
159318334Speter
159418334Speter	      if (temp1 == 0 || temp2 == 0)
159518334Speter		break;
159618334Speter
159790075Sobrien	      res = (expand_binop
159890075Sobrien                     (submode,
159990075Sobrien                      binoptab == smulv_optab ? subv_optab : sub_optab,
160090075Sobrien                      temp1, temp2, realr, unsignedp, methods));
160118334Speter
160218334Speter	      if (res == 0)
160318334Speter		break;
160418334Speter	      else if (res != realr)
160518334Speter		emit_move_insn (realr, res);
160618334Speter
160718334Speter	      temp1 = expand_binop (submode, binoptab, real0, imag1,
160818334Speter				    NULL_RTX, unsignedp, methods);
160918334Speter
161018334Speter	      temp2 = expand_binop (submode, binoptab, real1, imag0,
161118334Speter				    NULL_RTX, unsignedp, methods);
161218334Speter
161318334Speter	      if (temp1 == 0 || temp2 == 0)
161418334Speter		  break;
161518334Speter
161690075Sobrien	      res = (expand_binop
161790075Sobrien                     (submode,
161890075Sobrien                      binoptab == smulv_optab ? addv_optab : add_optab,
161990075Sobrien                      temp1, temp2, imagr, unsignedp, methods));
162018334Speter
162118334Speter	      if (res == 0)
162218334Speter		break;
162318334Speter	      else if (res != imagr)
162418334Speter		emit_move_insn (imagr, res);
162518334Speter
162618334Speter	      ok = 1;
162718334Speter	    }
162818334Speter	  else
162918334Speter	    {
163018334Speter	      /* Don't fetch these from memory more than once.  */
163118334Speter	      real0 = force_reg (submode, real0);
163218334Speter	      real1 = force_reg (submode, real1);
163318334Speter
163418334Speter	      res = expand_binop (submode, binoptab, real0, real1,
163518334Speter				  realr, unsignedp, methods);
163618334Speter	      if (res == 0)
163718334Speter		break;
163818334Speter	      else if (res != realr)
163918334Speter		emit_move_insn (realr, res);
164018334Speter
164118334Speter	      if (imag0 != 0)
164218334Speter		res = expand_binop (submode, binoptab,
164318334Speter				    real1, imag0, imagr, unsignedp, methods);
164418334Speter	      else
164518334Speter		res = expand_binop (submode, binoptab,
164618334Speter				    real0, imag1, imagr, unsignedp, methods);
164718334Speter
164818334Speter	      if (res == 0)
164918334Speter		break;
165018334Speter	      else if (res != imagr)
165118334Speter		emit_move_insn (imagr, res);
165218334Speter
165318334Speter	      ok = 1;
165418334Speter	    }
165518334Speter	  break;
165618334Speter
165718334Speter	case DIV:
165818334Speter	  /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
165918334Speter
166018334Speter	  if (imag1 == 0)
166118334Speter	    {
166218334Speter	      /* (a+ib) / (c+i0) = (a/c) + i(b/c) */
166318334Speter
166418334Speter	      /* Don't fetch these from memory more than once.  */
166518334Speter	      real1 = force_reg (submode, real1);
166618334Speter
166718334Speter	      /* Simply divide the real and imaginary parts by `c' */
166818334Speter	      if (class == MODE_COMPLEX_FLOAT)
166918334Speter		res = expand_binop (submode, binoptab, real0, real1,
167018334Speter				    realr, unsignedp, methods);
167118334Speter	      else
167218334Speter		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
167318334Speter				     real0, real1, realr, unsignedp);
167418334Speter
167518334Speter	      if (res == 0)
167618334Speter		break;
167718334Speter	      else if (res != realr)
167818334Speter		emit_move_insn (realr, res);
167918334Speter
168018334Speter	      if (class == MODE_COMPLEX_FLOAT)
168118334Speter		res = expand_binop (submode, binoptab, imag0, real1,
168218334Speter				    imagr, unsignedp, methods);
168318334Speter	      else
168418334Speter		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
168518334Speter				     imag0, real1, imagr, unsignedp);
168618334Speter
168718334Speter	      if (res == 0)
168818334Speter		break;
168918334Speter	      else if (res != imagr)
169018334Speter		emit_move_insn (imagr, res);
169118334Speter
169218334Speter	      ok = 1;
169318334Speter	    }
169418334Speter	  else
169518334Speter	    {
169652284Sobrien	      switch (flag_complex_divide_method)
169718334Speter		{
169852284Sobrien		case 0:
169952284Sobrien		  ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1,
170052284Sobrien						 realr, imagr, submode,
170152284Sobrien						 unsignedp, methods,
170252284Sobrien						 class, binoptab);
170352284Sobrien		  break;
170418334Speter
170552284Sobrien		case 1:
170652284Sobrien		  ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1,
170752284Sobrien					     realr, imagr, submode,
170852284Sobrien					     unsignedp, methods,
170952284Sobrien					     class, binoptab);
171052284Sobrien		  break;
171118334Speter
171252284Sobrien		default:
171352284Sobrien		  abort ();
171418334Speter		}
171518334Speter	    }
171618334Speter	  break;
171718334Speter
171818334Speter	default:
171918334Speter	  abort ();
172018334Speter	}
172118334Speter
172218334Speter      seq = get_insns ();
172318334Speter      end_sequence ();
172418334Speter
172518334Speter      if (ok)
172618334Speter	{
172718334Speter	  if (binoptab->code != UNKNOWN)
172818334Speter	    equiv_value
172950397Sobrien	      = gen_rtx_fmt_ee (binoptab->code, mode,
173050397Sobrien				copy_rtx (op0), copy_rtx (op1));
173118334Speter	  else
173218334Speter	    equiv_value = 0;
173318334Speter
173418334Speter	  emit_no_conflict_block (seq, target, op0, op1, equiv_value);
173518334Speter
173618334Speter	  return target;
173718334Speter	}
173818334Speter    }
173918334Speter
174018334Speter  /* It can't be open-coded in this mode.
174118334Speter     Use a library call if one is available and caller says that's ok.  */
174218334Speter
174318334Speter  if (binoptab->handlers[(int) mode].libfunc
174418334Speter      && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
174518334Speter    {
174618334Speter      rtx insns;
174718334Speter      rtx op1x = op1;
174818334Speter      enum machine_mode op1_mode = mode;
174918334Speter      rtx value;
175018334Speter
175118334Speter      start_sequence ();
175218334Speter
175318334Speter      if (shift_op)
175418334Speter	{
175518334Speter	  op1_mode = word_mode;
175618334Speter	  /* Specify unsigned here,
175718334Speter	     since negative shift counts are meaningless.  */
175818334Speter	  op1x = convert_to_mode (word_mode, op1, 1);
175918334Speter	}
176018334Speter
176118334Speter      if (GET_MODE (op0) != VOIDmode
176218334Speter	  && GET_MODE (op0) != mode)
176318334Speter	op0 = convert_to_mode (mode, op0, unsignedp);
176418334Speter
176518334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
176618334Speter	 if the libcall is cse'd or moved.  */
176718334Speter      value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc,
176890075Sobrien				       NULL_RTX, LCT_CONST, mode, 2,
176918334Speter				       op0, mode, op1x, op1_mode);
177018334Speter
177118334Speter      insns = get_insns ();
177218334Speter      end_sequence ();
177318334Speter
177418334Speter      target = gen_reg_rtx (mode);
177518334Speter      emit_libcall_block (insns, target, value,
177650397Sobrien			  gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
177718334Speter
177818334Speter      return target;
177918334Speter    }
178018334Speter
178118334Speter  delete_insns_since (last);
178218334Speter
178318334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
178418334Speter
178518334Speter  if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN
178618334Speter	 || methods == OPTAB_MUST_WIDEN))
178718334Speter    {
178818334Speter      /* Caller says, don't even try.  */
178918334Speter      delete_insns_since (entry_last);
179018334Speter      return 0;
179118334Speter    }
179218334Speter
179318334Speter  /* Compute the value of METHODS to pass to recursive calls.
179418334Speter     Don't allow widening to be tried recursively.  */
179518334Speter
179618334Speter  methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT);
179718334Speter
179818334Speter  /* Look for a wider mode of the same class for which it appears we can do
179918334Speter     the operation.  */
180018334Speter
180118334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
180218334Speter    {
180318334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
180418334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
180518334Speter	{
180618334Speter	  if ((binoptab->handlers[(int) wider_mode].insn_code
180718334Speter	       != CODE_FOR_nothing)
180818334Speter	      || (methods == OPTAB_LIB
180918334Speter		  && binoptab->handlers[(int) wider_mode].libfunc))
181018334Speter	    {
181118334Speter	      rtx xop0 = op0, xop1 = op1;
181218334Speter	      int no_extend = 0;
181318334Speter
181418334Speter	      /* For certain integer operations, we need not actually extend
181518334Speter		 the narrow operands, as long as we will truncate
181618334Speter		 the results to the same narrowness.  */
181718334Speter
181818334Speter	      if ((binoptab == ior_optab || binoptab == and_optab
181918334Speter		   || binoptab == xor_optab
182018334Speter		   || binoptab == add_optab || binoptab == sub_optab
182118334Speter		   || binoptab == smul_optab || binoptab == ashl_optab)
182218334Speter		  && class == MODE_INT)
182318334Speter		no_extend = 1;
182418334Speter
182518334Speter	      xop0 = widen_operand (xop0, wider_mode, mode,
182618334Speter				    unsignedp, no_extend);
182718334Speter
182818334Speter	      /* The second operand of a shift must always be extended.  */
182918334Speter	      xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
183018334Speter				    no_extend && binoptab != ashl_optab);
183118334Speter
183218334Speter	      temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
183318334Speter				   unsignedp, methods);
183418334Speter	      if (temp)
183518334Speter		{
183618334Speter		  if (class != MODE_INT)
183718334Speter		    {
183818334Speter		      if (target == 0)
183918334Speter			target = gen_reg_rtx (mode);
184018334Speter		      convert_move (target, temp, 0);
184118334Speter		      return target;
184218334Speter		    }
184318334Speter		  else
184418334Speter		    return gen_lowpart (mode, temp);
184518334Speter		}
184618334Speter	      else
184718334Speter		delete_insns_since (last);
184818334Speter	    }
184918334Speter	}
185018334Speter    }
185118334Speter
185218334Speter  delete_insns_since (entry_last);
185318334Speter  return 0;
185418334Speter}
185518334Speter
185618334Speter/* Expand a binary operator which has both signed and unsigned forms.
185718334Speter   UOPTAB is the optab for unsigned operations, and SOPTAB is for
185818334Speter   signed operations.
185918334Speter
186018334Speter   If we widen unsigned operands, we may use a signed wider operation instead
186118334Speter   of an unsigned wider operation, since the result would be the same.  */
186218334Speter
186318334Speterrtx
186418334Spetersign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
186518334Speter    enum machine_mode mode;
186618334Speter    optab uoptab, soptab;
186718334Speter    rtx op0, op1, target;
186818334Speter    int unsignedp;
186918334Speter    enum optab_methods methods;
187018334Speter{
187190075Sobrien  rtx temp;
187218334Speter  optab direct_optab = unsignedp ? uoptab : soptab;
187318334Speter  struct optab wide_soptab;
187418334Speter
187518334Speter  /* Do it without widening, if possible.  */
187618334Speter  temp = expand_binop (mode, direct_optab, op0, op1, target,
187718334Speter		       unsignedp, OPTAB_DIRECT);
187818334Speter  if (temp || methods == OPTAB_DIRECT)
187918334Speter    return temp;
188018334Speter
188118334Speter  /* Try widening to a signed int.  Make a fake signed optab that
188218334Speter     hides any signed insn for direct use.  */
188318334Speter  wide_soptab = *soptab;
188418334Speter  wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing;
188518334Speter  wide_soptab.handlers[(int) mode].libfunc = 0;
188618334Speter
188718334Speter  temp = expand_binop (mode, &wide_soptab, op0, op1, target,
188818334Speter		       unsignedp, OPTAB_WIDEN);
188918334Speter
189018334Speter  /* For unsigned operands, try widening to an unsigned int.  */
189118334Speter  if (temp == 0 && unsignedp)
189218334Speter    temp = expand_binop (mode, uoptab, op0, op1, target,
189318334Speter			 unsignedp, OPTAB_WIDEN);
189418334Speter  if (temp || methods == OPTAB_WIDEN)
189518334Speter    return temp;
189618334Speter
189718334Speter  /* Use the right width lib call if that exists.  */
189818334Speter  temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB);
189918334Speter  if (temp || methods == OPTAB_LIB)
190018334Speter    return temp;
190118334Speter
190218334Speter  /* Must widen and use a lib call, use either signed or unsigned.  */
190318334Speter  temp = expand_binop (mode, &wide_soptab, op0, op1, target,
190418334Speter		       unsignedp, methods);
190518334Speter  if (temp != 0)
190618334Speter    return temp;
190718334Speter  if (unsignedp)
190818334Speter    return expand_binop (mode, uoptab, op0, op1, target,
190918334Speter			 unsignedp, methods);
191018334Speter  return 0;
191118334Speter}
191218334Speter
191318334Speter/* Generate code to perform an operation specified by BINOPTAB
191418334Speter   on operands OP0 and OP1, with two results to TARG1 and TARG2.
191518334Speter   We assume that the order of the operands for the instruction
191618334Speter   is TARG0, OP0, OP1, TARG1, which would fit a pattern like
191718334Speter   [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))].
191818334Speter
191918334Speter   Either TARG0 or TARG1 may be zero, but what that means is that
192050397Sobrien   the result is not actually wanted.  We will generate it into
192118334Speter   a dummy pseudo-reg and discard it.  They may not both be zero.
192218334Speter
192318334Speter   Returns 1 if this operation can be performed; 0 if not.  */
192418334Speter
192518334Speterint
192618334Speterexpand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
192718334Speter     optab binoptab;
192818334Speter     rtx op0, op1;
192918334Speter     rtx targ0, targ1;
193018334Speter     int unsignedp;
193118334Speter{
193218334Speter  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
193318334Speter  enum mode_class class;
193418334Speter  enum machine_mode wider_mode;
193518334Speter  rtx entry_last = get_last_insn ();
193618334Speter  rtx last;
193718334Speter
193818334Speter  class = GET_MODE_CLASS (mode);
193918334Speter
194018334Speter  op0 = protect_from_queue (op0, 0);
194118334Speter  op1 = protect_from_queue (op1, 0);
194218334Speter
194318334Speter  if (flag_force_mem)
194418334Speter    {
194518334Speter      op0 = force_not_mem (op0);
194618334Speter      op1 = force_not_mem (op1);
194718334Speter    }
194818334Speter
194918334Speter  /* If we are inside an appropriately-short loop and one operand is an
195018334Speter     expensive constant, force it into a register.  */
195118334Speter  if (CONSTANT_P (op0) && preserve_subexpressions_p ()
195290075Sobrien      && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
195318334Speter    op0 = force_reg (mode, op0);
195418334Speter
195518334Speter  if (CONSTANT_P (op1) && preserve_subexpressions_p ()
195690075Sobrien      && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
195718334Speter    op1 = force_reg (mode, op1);
195818334Speter
195918334Speter  if (targ0)
196018334Speter    targ0 = protect_from_queue (targ0, 1);
196118334Speter  else
196218334Speter    targ0 = gen_reg_rtx (mode);
196318334Speter  if (targ1)
196418334Speter    targ1 = protect_from_queue (targ1, 1);
196518334Speter  else
196618334Speter    targ1 = gen_reg_rtx (mode);
196718334Speter
196818334Speter  /* Record where to go back to if we fail.  */
196918334Speter  last = get_last_insn ();
197018334Speter
197118334Speter  if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
197218334Speter    {
197318334Speter      int icode = (int) binoptab->handlers[(int) mode].insn_code;
197490075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
197590075Sobrien      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
197618334Speter      rtx pat;
197718334Speter      rtx xop0 = op0, xop1 = op1;
197818334Speter
197918334Speter      /* In case this insn wants input operands in modes different from the
198018334Speter	 result, convert the operands.  */
198118334Speter      if (GET_MODE (op0) != VOIDmode && GET_MODE (op0) != mode0)
198218334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
198318334Speter
198418334Speter      if (GET_MODE (op1) != VOIDmode && GET_MODE (op1) != mode1)
198518334Speter	xop1 = convert_to_mode (mode1, xop1, unsignedp);
198618334Speter
198718334Speter      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
198890075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
198918334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
199018334Speter
199190075Sobrien      if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1))
199218334Speter	xop1 = copy_to_mode_reg (mode1, xop1);
199318334Speter
199418334Speter      /* We could handle this, but we should always be called with a pseudo
199518334Speter	 for our targets and all insns should take them as outputs.  */
199690075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
199790075Sobrien	  || ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
199818334Speter	abort ();
199918334Speter
200018334Speter      pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
200118334Speter      if (pat)
200218334Speter	{
200318334Speter	  emit_insn (pat);
200418334Speter	  return 1;
200518334Speter	}
200618334Speter      else
200718334Speter	delete_insns_since (last);
200818334Speter    }
200918334Speter
201018334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
201118334Speter
201218334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
201318334Speter    {
201418334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
201518334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
201618334Speter	{
201718334Speter	  if (binoptab->handlers[(int) wider_mode].insn_code
201818334Speter	      != CODE_FOR_nothing)
201918334Speter	    {
202090075Sobrien	      rtx t0 = gen_reg_rtx (wider_mode);
202190075Sobrien	      rtx t1 = gen_reg_rtx (wider_mode);
202290075Sobrien	      rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp);
202390075Sobrien	      rtx cop1 = convert_modes (wider_mode, mode, op1, unsignedp);
202418334Speter
202590075Sobrien	      if (expand_twoval_binop (binoptab, cop0, cop1,
202618334Speter				       t0, t1, unsignedp))
202718334Speter		{
202818334Speter		  convert_move (targ0, t0, unsignedp);
202918334Speter		  convert_move (targ1, t1, unsignedp);
203018334Speter		  return 1;
203118334Speter		}
203218334Speter	      else
203318334Speter		delete_insns_since (last);
203418334Speter	    }
203518334Speter	}
203618334Speter    }
203718334Speter
203818334Speter  delete_insns_since (entry_last);
203918334Speter  return 0;
204018334Speter}
204118334Speter
204290075Sobrien/* Wrapper around expand_unop which takes an rtx code to specify
204390075Sobrien   the operation to perform, not an optab pointer.  All other
204490075Sobrien   arguments are the same.  */
204590075Sobrienrtx
204690075Sobrienexpand_simple_unop (mode, code, op0, target, unsignedp)
204790075Sobrien     enum machine_mode mode;
204890075Sobrien     enum rtx_code code;
204990075Sobrien     rtx op0;
205090075Sobrien     rtx target;
205190075Sobrien     int unsignedp;
205290075Sobrien{
205390075Sobrien  optab unop = code_to_optab [(int) code];
205490075Sobrien  if (unop == 0)
205590075Sobrien    abort ();
205690075Sobrien
205790075Sobrien  return expand_unop (mode, unop, op0, target, unsignedp);
205890075Sobrien}
205990075Sobrien
206018334Speter/* Generate code to perform an operation specified by UNOPTAB
206118334Speter   on operand OP0, with result having machine-mode MODE.
206218334Speter
206318334Speter   UNSIGNEDP is for the case where we have to widen the operands
206418334Speter   to perform the operation.  It says to use zero-extension.
206518334Speter
206618334Speter   If TARGET is nonzero, the value
206718334Speter   is generated there, if it is convenient to do so.
206818334Speter   In all cases an rtx is returned for the locus of the value;
206918334Speter   this may or may not be TARGET.  */
207018334Speter
207118334Speterrtx
207218334Speterexpand_unop (mode, unoptab, op0, target, unsignedp)
207318334Speter     enum machine_mode mode;
207418334Speter     optab unoptab;
207518334Speter     rtx op0;
207618334Speter     rtx target;
207718334Speter     int unsignedp;
207818334Speter{
207918334Speter  enum mode_class class;
208018334Speter  enum machine_mode wider_mode;
208190075Sobrien  rtx temp;
208218334Speter  rtx last = get_last_insn ();
208318334Speter  rtx pat;
208418334Speter
208518334Speter  class = GET_MODE_CLASS (mode);
208618334Speter
208718334Speter  op0 = protect_from_queue (op0, 0);
208818334Speter
208918334Speter  if (flag_force_mem)
209018334Speter    {
209118334Speter      op0 = force_not_mem (op0);
209218334Speter    }
209318334Speter
209418334Speter  if (target)
209518334Speter    target = protect_from_queue (target, 1);
209618334Speter
209718334Speter  if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
209818334Speter    {
209918334Speter      int icode = (int) unoptab->handlers[(int) mode].insn_code;
210090075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
210118334Speter      rtx xop0 = op0;
210218334Speter
210318334Speter      if (target)
210418334Speter	temp = target;
210518334Speter      else
210618334Speter	temp = gen_reg_rtx (mode);
210718334Speter
210818334Speter      if (GET_MODE (xop0) != VOIDmode
210918334Speter	  && GET_MODE (xop0) != mode0)
211018334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
211118334Speter
211218334Speter      /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
211318334Speter
211490075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
211518334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
211618334Speter
211790075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
211818334Speter	temp = gen_reg_rtx (mode);
211918334Speter
212018334Speter      pat = GEN_FCN (icode) (temp, xop0);
212118334Speter      if (pat)
212218334Speter	{
212318334Speter	  if (GET_CODE (pat) == SEQUENCE
212418334Speter	      && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX))
212518334Speter	    {
212618334Speter	      delete_insns_since (last);
212718334Speter	      return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp);
212818334Speter	    }
212918334Speter
213018334Speter	  emit_insn (pat);
213118334Speter
213218334Speter	  return temp;
213318334Speter	}
213418334Speter      else
213518334Speter	delete_insns_since (last);
213618334Speter    }
213718334Speter
213818334Speter  /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
213918334Speter
214018334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
214118334Speter    for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
214218334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
214318334Speter      {
214418334Speter	if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
214518334Speter	  {
214618334Speter	    rtx xop0 = op0;
214718334Speter
214818334Speter	    /* For certain operations, we need not actually extend
214918334Speter	       the narrow operand, as long as we will truncate the
215018334Speter	       results to the same narrowness.  */
215118334Speter
215218334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
215318334Speter				  (unoptab == neg_optab
215418334Speter				   || unoptab == one_cmpl_optab)
215518334Speter				  && class == MODE_INT);
215618334Speter
215718334Speter	    temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
215818334Speter				unsignedp);
215918334Speter
216018334Speter	    if (temp)
216118334Speter	      {
216218334Speter		if (class != MODE_INT)
216318334Speter		  {
216418334Speter		    if (target == 0)
216518334Speter		      target = gen_reg_rtx (mode);
216618334Speter		    convert_move (target, temp, 0);
216718334Speter		    return target;
216818334Speter		  }
216918334Speter		else
217018334Speter		  return gen_lowpart (mode, temp);
217118334Speter	      }
217218334Speter	    else
217318334Speter	      delete_insns_since (last);
217418334Speter	  }
217518334Speter      }
217618334Speter
217718334Speter  /* These can be done a word at a time.  */
217818334Speter  if (unoptab == one_cmpl_optab
217918334Speter      && class == MODE_INT
218018334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
218118334Speter      && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
218218334Speter    {
218318334Speter      int i;
218418334Speter      rtx insns;
218518334Speter
218618334Speter      if (target == 0 || target == op0)
218718334Speter	target = gen_reg_rtx (mode);
218818334Speter
218918334Speter      start_sequence ();
219018334Speter
219118334Speter      /* Do the actual arithmetic.  */
219218334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
219318334Speter	{
219418334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
219518334Speter	  rtx x = expand_unop (word_mode, unoptab,
219618334Speter			       operand_subword_force (op0, i, mode),
219718334Speter			       target_piece, unsignedp);
219890075Sobrien
219918334Speter	  if (target_piece != x)
220018334Speter	    emit_move_insn (target_piece, x);
220118334Speter	}
220218334Speter
220318334Speter      insns = get_insns ();
220418334Speter      end_sequence ();
220518334Speter
220618334Speter      emit_no_conflict_block (insns, target, op0, NULL_RTX,
220750397Sobrien			      gen_rtx_fmt_e (unoptab->code, mode,
220850397Sobrien					     copy_rtx (op0)));
220918334Speter      return target;
221018334Speter    }
221118334Speter
221218334Speter  /* Open-code the complex negation operation.  */
221390075Sobrien  else if (unoptab->code == NEG
221418334Speter	   && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT))
221518334Speter    {
221618334Speter      rtx target_piece;
221718334Speter      rtx x;
221818334Speter      rtx seq;
221918334Speter
222018334Speter      /* Find the correct mode for the real and imaginary parts */
222118334Speter      enum machine_mode submode
222218334Speter	= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
222318334Speter			 class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
222418334Speter			 0);
222518334Speter
222618334Speter      if (submode == BLKmode)
222718334Speter	abort ();
222818334Speter
222918334Speter      if (target == 0)
223018334Speter	target = gen_reg_rtx (mode);
223118334Speter
223218334Speter      start_sequence ();
223318334Speter
223418334Speter      target_piece = gen_imagpart (submode, target);
223518334Speter      x = expand_unop (submode, unoptab,
223618334Speter		       gen_imagpart (submode, op0),
223718334Speter		       target_piece, unsignedp);
223818334Speter      if (target_piece != x)
223918334Speter	emit_move_insn (target_piece, x);
224018334Speter
224118334Speter      target_piece = gen_realpart (submode, target);
224218334Speter      x = expand_unop (submode, unoptab,
224318334Speter		       gen_realpart (submode, op0),
224418334Speter		       target_piece, unsignedp);
224518334Speter      if (target_piece != x)
224618334Speter	emit_move_insn (target_piece, x);
224718334Speter
224818334Speter      seq = get_insns ();
224918334Speter      end_sequence ();
225018334Speter
225118334Speter      emit_no_conflict_block (seq, target, op0, 0,
225250397Sobrien			      gen_rtx_fmt_e (unoptab->code, mode,
225350397Sobrien					     copy_rtx (op0)));
225418334Speter      return target;
225518334Speter    }
225618334Speter
225718334Speter  /* Now try a library call in this mode.  */
225818334Speter  if (unoptab->handlers[(int) mode].libfunc)
225918334Speter    {
226018334Speter      rtx insns;
226118334Speter      rtx value;
226218334Speter
226318334Speter      start_sequence ();
226418334Speter
226518334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
226618334Speter	 if the libcall is cse'd or moved.  */
226718334Speter      value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
226890075Sobrien				       NULL_RTX, LCT_CONST, mode, 1, op0, mode);
226918334Speter      insns = get_insns ();
227018334Speter      end_sequence ();
227118334Speter
227218334Speter      target = gen_reg_rtx (mode);
227318334Speter      emit_libcall_block (insns, target, value,
227450397Sobrien			  gen_rtx_fmt_e (unoptab->code, mode, op0));
227518334Speter
227618334Speter      return target;
227718334Speter    }
227818334Speter
227918334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
228018334Speter
228118334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
228218334Speter    {
228318334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
228418334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
228518334Speter	{
228618334Speter	  if ((unoptab->handlers[(int) wider_mode].insn_code
228718334Speter	       != CODE_FOR_nothing)
228818334Speter	      || unoptab->handlers[(int) wider_mode].libfunc)
228918334Speter	    {
229018334Speter	      rtx xop0 = op0;
229118334Speter
229218334Speter	      /* For certain operations, we need not actually extend
229318334Speter		 the narrow operand, as long as we will truncate the
229418334Speter		 results to the same narrowness.  */
229518334Speter
229618334Speter	      xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
229718334Speter				    (unoptab == neg_optab
229818334Speter				     || unoptab == one_cmpl_optab)
229918334Speter				    && class == MODE_INT);
230018334Speter
230118334Speter	      temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
230218334Speter				  unsignedp);
230318334Speter
230418334Speter	      if (temp)
230518334Speter		{
230618334Speter		  if (class != MODE_INT)
230718334Speter		    {
230818334Speter		      if (target == 0)
230918334Speter			target = gen_reg_rtx (mode);
231018334Speter		      convert_move (target, temp, 0);
231118334Speter		      return target;
231218334Speter		    }
231318334Speter		  else
231418334Speter		    return gen_lowpart (mode, temp);
231518334Speter		}
231618334Speter	      else
231718334Speter		delete_insns_since (last);
231818334Speter	    }
231918334Speter	}
232018334Speter    }
232118334Speter
232218334Speter  /* If there is no negate operation, try doing a subtract from zero.
232318334Speter     The US Software GOFAST library needs this.  */
232490075Sobrien  if (unoptab->code == NEG)
232518334Speter    {
232618334Speter      rtx temp;
232790075Sobrien      temp = expand_binop (mode,
232890075Sobrien                           unoptab == negv_optab ? subv_optab : sub_optab,
232990075Sobrien                           CONST0_RTX (mode), op0,
233090075Sobrien                           target, unsignedp, OPTAB_LIB_WIDEN);
233118334Speter      if (temp)
233218334Speter	return temp;
233318334Speter    }
233418334Speter
233518334Speter  return 0;
233618334Speter}
233718334Speter
233818334Speter/* Emit code to compute the absolute value of OP0, with result to
233918334Speter   TARGET if convenient.  (TARGET may be 0.)  The return value says
234018334Speter   where the result actually is to be found.
234118334Speter
234218334Speter   MODE is the mode of the operand; the mode of the result is
234318334Speter   different but can be deduced from MODE.
234418334Speter
234552284Sobrien */
234618334Speter
234718334Speterrtx
234890075Sobrienexpand_abs (mode, op0, target, result_unsignedp, safe)
234918334Speter     enum machine_mode mode;
235018334Speter     rtx op0;
235118334Speter     rtx target;
235290075Sobrien     int result_unsignedp;
235318334Speter     int safe;
235418334Speter{
235518334Speter  rtx temp, op1;
235618334Speter
235790075Sobrien  if (! flag_trapv)
235890075Sobrien    result_unsignedp = 1;
235990075Sobrien
236018334Speter  /* First try to do it with a special abs instruction.  */
236190075Sobrien  temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab,
236290075Sobrien                      op0, target, 0);
236318334Speter  if (temp != 0)
236418334Speter    return temp;
236518334Speter
236690075Sobrien  /* If we have a MAX insn, we can do this as MAX (x, -x).  */
236790075Sobrien  if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
236890075Sobrien    {
236990075Sobrien      rtx last = get_last_insn ();
237090075Sobrien
237190075Sobrien      temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0);
237290075Sobrien      if (temp != 0)
237390075Sobrien	temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
237490075Sobrien			     OPTAB_WIDEN);
237590075Sobrien
237690075Sobrien      if (temp != 0)
237790075Sobrien	return temp;
237890075Sobrien
237990075Sobrien      delete_insns_since (last);
238090075Sobrien    }
238190075Sobrien
238218334Speter  /* If this machine has expensive jumps, we can do integer absolute
238318334Speter     value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
238418334Speter     where W is the width of MODE.  */
238518334Speter
238618334Speter  if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
238718334Speter    {
238818334Speter      rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
238918334Speter				   size_int (GET_MODE_BITSIZE (mode) - 1),
239018334Speter				   NULL_RTX, 0);
239118334Speter
239218334Speter      temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
239318334Speter			   OPTAB_LIB_WIDEN);
239418334Speter      if (temp != 0)
239590075Sobrien	temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab,
239690075Sobrien                             temp, extended, target, 0, OPTAB_LIB_WIDEN);
239718334Speter
239818334Speter      if (temp != 0)
239918334Speter	return temp;
240018334Speter    }
240118334Speter
240218334Speter  /* If that does not win, use conditional jump and negate.  */
240350397Sobrien
240450397Sobrien  /* It is safe to use the target if it is the same
240550397Sobrien     as the source if this is also a pseudo register */
240650397Sobrien  if (op0 == target && GET_CODE (op0) == REG
240750397Sobrien      && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
240850397Sobrien    safe = 1;
240950397Sobrien
241018334Speter  op1 = gen_label_rtx ();
241118334Speter  if (target == 0 || ! safe
241218334Speter      || GET_MODE (target) != mode
241318334Speter      || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
241418334Speter      || (GET_CODE (target) == REG
241518334Speter	  && REGNO (target) < FIRST_PSEUDO_REGISTER))
241618334Speter    target = gen_reg_rtx (mode);
241718334Speter
241818334Speter  emit_move_insn (target, op0);
241918334Speter  NO_DEFER_POP;
242018334Speter
242118334Speter  /* If this mode is an integer too wide to compare properly,
242218334Speter     compare word by word.  Rely on CSE to optimize constant cases.  */
242390075Sobrien  if (GET_MODE_CLASS (mode) == MODE_INT
242490075Sobrien      && ! can_compare_p (GE, mode, ccp_jump))
242518334Speter    do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
242618334Speter				  NULL_RTX, op1);
242718334Speter  else
242890075Sobrien    do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
242990075Sobrien			     NULL_RTX, NULL_RTX, op1);
243018334Speter
243190075Sobrien  op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
243290075Sobrien                     target, target, 0);
243318334Speter  if (op0 != target)
243418334Speter    emit_move_insn (target, op0);
243518334Speter  emit_label (op1);
243618334Speter  OK_DEFER_POP;
243718334Speter  return target;
243818334Speter}
243918334Speter
244018334Speter/* Emit code to compute the absolute value of OP0, with result to
244118334Speter   TARGET if convenient.  (TARGET may be 0.)  The return value says
244218334Speter   where the result actually is to be found.
244318334Speter
244418334Speter   MODE is the mode of the operand; the mode of the result is
244518334Speter   different but can be deduced from MODE.
244618334Speter
244718334Speter   UNSIGNEDP is relevant for complex integer modes.  */
244818334Speter
244918334Speterrtx
245018334Speterexpand_complex_abs (mode, op0, target, unsignedp)
245118334Speter     enum machine_mode mode;
245218334Speter     rtx op0;
245318334Speter     rtx target;
245418334Speter     int unsignedp;
245518334Speter{
245618334Speter  enum mode_class class = GET_MODE_CLASS (mode);
245718334Speter  enum machine_mode wider_mode;
245890075Sobrien  rtx temp;
245918334Speter  rtx entry_last = get_last_insn ();
246018334Speter  rtx last;
246118334Speter  rtx pat;
246290075Sobrien  optab this_abs_optab;
246318334Speter
246418334Speter  /* Find the correct mode for the real and imaginary parts.  */
246518334Speter  enum machine_mode submode
246618334Speter    = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
246718334Speter		     class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
246818334Speter		     0);
246918334Speter
247018334Speter  if (submode == BLKmode)
247118334Speter    abort ();
247218334Speter
247318334Speter  op0 = protect_from_queue (op0, 0);
247418334Speter
247518334Speter  if (flag_force_mem)
247618334Speter    {
247718334Speter      op0 = force_not_mem (op0);
247818334Speter    }
247918334Speter
248018334Speter  last = get_last_insn ();
248118334Speter
248218334Speter  if (target)
248318334Speter    target = protect_from_queue (target, 1);
248418334Speter
248590075Sobrien  this_abs_optab = ! unsignedp && flag_trapv
248690075Sobrien                   && (GET_MODE_CLASS(mode) == MODE_INT)
248790075Sobrien                   ? absv_optab : abs_optab;
248890075Sobrien
248990075Sobrien  if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
249018334Speter    {
249190075Sobrien      int icode = (int) this_abs_optab->handlers[(int) mode].insn_code;
249290075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
249318334Speter      rtx xop0 = op0;
249418334Speter
249518334Speter      if (target)
249618334Speter	temp = target;
249718334Speter      else
249818334Speter	temp = gen_reg_rtx (submode);
249918334Speter
250018334Speter      if (GET_MODE (xop0) != VOIDmode
250118334Speter	  && GET_MODE (xop0) != mode0)
250218334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
250318334Speter
250418334Speter      /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
250518334Speter
250690075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
250718334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
250818334Speter
250990075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (temp, submode))
251018334Speter	temp = gen_reg_rtx (submode);
251118334Speter
251218334Speter      pat = GEN_FCN (icode) (temp, xop0);
251318334Speter      if (pat)
251418334Speter	{
251518334Speter	  if (GET_CODE (pat) == SEQUENCE
251690075Sobrien	      && ! add_equal_note (pat, temp, this_abs_optab->code, xop0,
251790075Sobrien				   NULL_RTX))
251818334Speter	    {
251918334Speter	      delete_insns_since (last);
252090075Sobrien	      return expand_unop (mode, this_abs_optab, op0, NULL_RTX,
252190075Sobrien				  unsignedp);
252218334Speter	    }
252318334Speter
252418334Speter	  emit_insn (pat);
252518334Speter
252618334Speter	  return temp;
252718334Speter	}
252818334Speter      else
252918334Speter	delete_insns_since (last);
253018334Speter    }
253118334Speter
253218334Speter  /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
253318334Speter
253418334Speter  for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
253518334Speter       wider_mode = GET_MODE_WIDER_MODE (wider_mode))
253618334Speter    {
253790075Sobrien      if (this_abs_optab->handlers[(int) wider_mode].insn_code
253890075Sobrien	  != CODE_FOR_nothing)
253918334Speter	{
254018334Speter	  rtx xop0 = op0;
254118334Speter
254218334Speter	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
254318334Speter	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
254418334Speter
254518334Speter	  if (temp)
254618334Speter	    {
254718334Speter	      if (class != MODE_COMPLEX_INT)
254818334Speter		{
254918334Speter		  if (target == 0)
255018334Speter		    target = gen_reg_rtx (submode);
255118334Speter		  convert_move (target, temp, 0);
255218334Speter		  return target;
255318334Speter		}
255418334Speter	      else
255518334Speter		return gen_lowpart (submode, temp);
255618334Speter	    }
255718334Speter	  else
255818334Speter	    delete_insns_since (last);
255918334Speter	}
256018334Speter    }
256118334Speter
256218334Speter  /* Open-code the complex absolute-value operation
256318334Speter     if we can open-code sqrt.  Otherwise it's not worth while.  */
256490075Sobrien  if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
256590075Sobrien      && ! flag_trapv)
256618334Speter    {
256718334Speter      rtx real, imag, total;
256818334Speter
256918334Speter      real = gen_realpart (submode, op0);
257018334Speter      imag = gen_imagpart (submode, op0);
257118334Speter
257218334Speter      /* Square both parts.  */
257318334Speter      real = expand_mult (submode, real, real, NULL_RTX, 0);
257418334Speter      imag = expand_mult (submode, imag, imag, NULL_RTX, 0);
257518334Speter
257618334Speter      /* Sum the parts.  */
257718334Speter      total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
257818334Speter			    0, OPTAB_LIB_WIDEN);
257918334Speter
258018334Speter      /* Get sqrt in TARGET.  Set TARGET to where the result is.  */
258118334Speter      target = expand_unop (submode, sqrt_optab, total, target, 0);
258218334Speter      if (target == 0)
258318334Speter	delete_insns_since (last);
258418334Speter      else
258518334Speter	return target;
258618334Speter    }
258718334Speter
258818334Speter  /* Now try a library call in this mode.  */
258990075Sobrien  if (this_abs_optab->handlers[(int) mode].libfunc)
259018334Speter    {
259118334Speter      rtx insns;
259218334Speter      rtx value;
259318334Speter
259418334Speter      start_sequence ();
259518334Speter
259618334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
259718334Speter	 if the libcall is cse'd or moved.  */
259818334Speter      value = emit_library_call_value (abs_optab->handlers[(int) mode].libfunc,
259990075Sobrien				       NULL_RTX, LCT_CONST, submode, 1, op0, mode);
260018334Speter      insns = get_insns ();
260118334Speter      end_sequence ();
260218334Speter
260318334Speter      target = gen_reg_rtx (submode);
260418334Speter      emit_libcall_block (insns, target, value,
260590075Sobrien			  gen_rtx_fmt_e (this_abs_optab->code, mode, op0));
260618334Speter
260718334Speter      return target;
260818334Speter    }
260918334Speter
261018334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
261118334Speter
261218334Speter  for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
261318334Speter       wider_mode = GET_MODE_WIDER_MODE (wider_mode))
261418334Speter    {
261590075Sobrien      if ((this_abs_optab->handlers[(int) wider_mode].insn_code
261618334Speter	   != CODE_FOR_nothing)
261790075Sobrien	  || this_abs_optab->handlers[(int) wider_mode].libfunc)
261818334Speter	{
261918334Speter	  rtx xop0 = op0;
262018334Speter
262118334Speter	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
262218334Speter
262318334Speter	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
262418334Speter
262518334Speter	  if (temp)
262618334Speter	    {
262718334Speter	      if (class != MODE_COMPLEX_INT)
262818334Speter		{
262918334Speter		  if (target == 0)
263018334Speter		    target = gen_reg_rtx (submode);
263118334Speter		  convert_move (target, temp, 0);
263218334Speter		  return target;
263318334Speter		}
263418334Speter	      else
263518334Speter		return gen_lowpart (submode, temp);
263618334Speter	    }
263718334Speter	  else
263818334Speter	    delete_insns_since (last);
263918334Speter	}
264018334Speter    }
264118334Speter
264218334Speter  delete_insns_since (entry_last);
264318334Speter  return 0;
264418334Speter}
264518334Speter
264618334Speter/* Generate an instruction whose insn-code is INSN_CODE,
264718334Speter   with two operands: an output TARGET and an input OP0.
264818334Speter   TARGET *must* be nonzero, and the output is always stored there.
264918334Speter   CODE is an rtx code such that (CODE OP0) is an rtx that describes
265018334Speter   the value that is stored into TARGET.  */
265118334Speter
265218334Spetervoid
265318334Speteremit_unop_insn (icode, target, op0, code)
265418334Speter     int icode;
265518334Speter     rtx target;
265618334Speter     rtx op0;
265718334Speter     enum rtx_code code;
265818334Speter{
265990075Sobrien  rtx temp;
266090075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
266118334Speter  rtx pat;
266218334Speter
266318334Speter  temp = target = protect_from_queue (target, 1);
266418334Speter
266518334Speter  op0 = protect_from_queue (op0, 0);
266618334Speter
266750397Sobrien  /* Sign and zero extension from memory is often done specially on
266850397Sobrien     RISC machines, so forcing into a register here can pessimize
266950397Sobrien     code.  */
267050397Sobrien  if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND)
267118334Speter    op0 = force_not_mem (op0);
267218334Speter
267318334Speter  /* Now, if insn does not accept our operands, put them into pseudos.  */
267418334Speter
267590075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
267618334Speter    op0 = copy_to_mode_reg (mode0, op0);
267718334Speter
267890075Sobrien  if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp))
267918334Speter      || (flag_force_mem && GET_CODE (temp) == MEM))
268018334Speter    temp = gen_reg_rtx (GET_MODE (temp));
268118334Speter
268218334Speter  pat = GEN_FCN (icode) (temp, op0);
268318334Speter
268418334Speter  if (GET_CODE (pat) == SEQUENCE && code != UNKNOWN)
268518334Speter    add_equal_note (pat, temp, code, op0, NULL_RTX);
268618334Speter
268718334Speter  emit_insn (pat);
268818334Speter
268918334Speter  if (temp != target)
269018334Speter    emit_move_insn (target, temp);
269118334Speter}
269218334Speter
269318334Speter/* Emit code to perform a series of operations on a multi-word quantity, one
269418334Speter   word at a time.
269518334Speter
269618334Speter   Such a block is preceded by a CLOBBER of the output, consists of multiple
269718334Speter   insns, each setting one word of the output, and followed by a SET copying
269818334Speter   the output to itself.
269918334Speter
270018334Speter   Each of the insns setting words of the output receives a REG_NO_CONFLICT
270118334Speter   note indicating that it doesn't conflict with the (also multi-word)
270218334Speter   inputs.  The entire block is surrounded by REG_LIBCALL and REG_RETVAL
270318334Speter   notes.
270418334Speter
270518334Speter   INSNS is a block of code generated to perform the operation, not including
270618334Speter   the CLOBBER and final copy.  All insns that compute intermediate values
270718334Speter   are first emitted, followed by the block as described above.
270818334Speter
270918334Speter   TARGET, OP0, and OP1 are the output and inputs of the operations,
271018334Speter   respectively.  OP1 may be zero for a unary operation.
271118334Speter
271218334Speter   EQUIV, if non-zero, is an expression to be placed into a REG_EQUAL note
271318334Speter   on the last insn.
271418334Speter
271518334Speter   If TARGET is not a register, INSNS is simply emitted with no special
271618334Speter   processing.  Likewise if anything in INSNS is not an INSN or if
271718334Speter   there is a libcall block inside INSNS.
271818334Speter
271918334Speter   The final insn emitted is returned.  */
272018334Speter
272118334Speterrtx
272218334Speteremit_no_conflict_block (insns, target, op0, op1, equiv)
272318334Speter     rtx insns;
272418334Speter     rtx target;
272518334Speter     rtx op0, op1;
272618334Speter     rtx equiv;
272718334Speter{
272818334Speter  rtx prev, next, first, last, insn;
272918334Speter
273018334Speter  if (GET_CODE (target) != REG || reload_in_progress)
273118334Speter    return emit_insns (insns);
273218334Speter  else
273318334Speter    for (insn = insns; insn; insn = NEXT_INSN (insn))
273418334Speter      if (GET_CODE (insn) != INSN
273518334Speter	  || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
273618334Speter	return emit_insns (insns);
273718334Speter
273818334Speter  /* First emit all insns that do not store into words of the output and remove
273918334Speter     these from the list.  */
274018334Speter  for (insn = insns; insn; insn = next)
274118334Speter    {
274296263Sobrien      rtx set = 0, note;
274318334Speter      int i;
274418334Speter
274518334Speter      next = NEXT_INSN (insn);
274618334Speter
274796263Sobrien      /* Some ports (cris) create an libcall regions at their own.  We must
274896263Sobrien	 avoid any potential nesting of LIBCALLs.  */
274996263Sobrien      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
275096263Sobrien	remove_note (insn, note);
275196263Sobrien      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
275296263Sobrien	remove_note (insn, note);
275396263Sobrien
275490075Sobrien      if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE
275590075Sobrien	  || GET_CODE (PATTERN (insn)) == CLOBBER)
275618334Speter	set = PATTERN (insn);
275718334Speter      else if (GET_CODE (PATTERN (insn)) == PARALLEL)
275818334Speter	{
275918334Speter	  for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
276018334Speter	    if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
276118334Speter	      {
276218334Speter		set = XVECEXP (PATTERN (insn), 0, i);
276318334Speter		break;
276418334Speter	      }
276518334Speter	}
276618334Speter
276718334Speter      if (set == 0)
276818334Speter	abort ();
276918334Speter
277018334Speter      if (! reg_overlap_mentioned_p (target, SET_DEST (set)))
277118334Speter	{
277218334Speter	  if (PREV_INSN (insn))
277318334Speter	    NEXT_INSN (PREV_INSN (insn)) = next;
277418334Speter	  else
277518334Speter	    insns = next;
277618334Speter
277718334Speter	  if (next)
277818334Speter	    PREV_INSN (next) = PREV_INSN (insn);
277918334Speter
278018334Speter	  add_insn (insn);
278118334Speter	}
278218334Speter    }
278318334Speter
278418334Speter  prev = get_last_insn ();
278518334Speter
278618334Speter  /* Now write the CLOBBER of the output, followed by the setting of each
278718334Speter     of the words, followed by the final copy.  */
278818334Speter  if (target != op0 && target != op1)
278950397Sobrien    emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
279018334Speter
279118334Speter  for (insn = insns; insn; insn = next)
279218334Speter    {
279318334Speter      next = NEXT_INSN (insn);
279418334Speter      add_insn (insn);
279518334Speter
279618334Speter      if (op1 && GET_CODE (op1) == REG)
279750397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
279850397Sobrien					      REG_NOTES (insn));
279918334Speter
280018334Speter      if (op0 && GET_CODE (op0) == REG)
280150397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
280250397Sobrien					      REG_NOTES (insn));
280318334Speter    }
280418334Speter
280518334Speter  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
280618334Speter      != CODE_FOR_nothing)
280718334Speter    {
280818334Speter      last = emit_move_insn (target, target);
280918334Speter      if (equiv)
281052284Sobrien	set_unique_reg_note (last, REG_EQUAL, equiv);
281118334Speter    }
281218334Speter  else
281390075Sobrien    {
281490075Sobrien      last = get_last_insn ();
281518334Speter
281690075Sobrien      /* Remove any existing REG_EQUAL note from "last", or else it will
281790075Sobrien	 be mistaken for a note referring to the full contents of the
281890075Sobrien	 alleged libcall value when found together with the REG_RETVAL
281990075Sobrien	 note added below.  An existing note can come from an insn
282090075Sobrien	 expansion at "last".  */
282190075Sobrien      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
282290075Sobrien    }
282390075Sobrien
282418334Speter  if (prev == 0)
282518334Speter    first = get_insns ();
282618334Speter  else
282718334Speter    first = NEXT_INSN (prev);
282818334Speter
282918334Speter  /* Encapsulate the block so it gets manipulated as a unit.  */
283050397Sobrien  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
283150397Sobrien					 REG_NOTES (first));
283250397Sobrien  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
283318334Speter
283418334Speter  return last;
283518334Speter}
283618334Speter
283718334Speter/* Emit code to make a call to a constant function or a library call.
283818334Speter
283918334Speter   INSNS is a list containing all insns emitted in the call.
284018334Speter   These insns leave the result in RESULT.  Our block is to copy RESULT
284118334Speter   to TARGET, which is logically equivalent to EQUIV.
284218334Speter
284318334Speter   We first emit any insns that set a pseudo on the assumption that these are
284418334Speter   loading constants into registers; doing so allows them to be safely cse'ed
284518334Speter   between blocks.  Then we emit all the other insns in the block, followed by
284618334Speter   an insn to move RESULT to TARGET.  This last insn will have a REQ_EQUAL
284718334Speter   note with an operand of EQUIV.
284818334Speter
284918334Speter   Moving assignments to pseudos outside of the block is done to improve
285018334Speter   the generated code, but is not required to generate correct code,
285118334Speter   hence being unable to move an assignment is not grounds for not making
285218334Speter   a libcall block.  There are two reasons why it is safe to leave these
285318334Speter   insns inside the block: First, we know that these pseudos cannot be
285418334Speter   used in generated RTL outside the block since they are created for
285518334Speter   temporary purposes within the block.  Second, CSE will not record the
285618334Speter   values of anything set inside a libcall block, so we know they must
285718334Speter   be dead at the end of the block.
285818334Speter
285918334Speter   Except for the first group of insns (the ones setting pseudos), the
286018334Speter   block is delimited by REG_RETVAL and REG_LIBCALL notes.  */
286118334Speter
286218334Spetervoid
286318334Speteremit_libcall_block (insns, target, result, equiv)
286418334Speter     rtx insns;
286518334Speter     rtx target;
286618334Speter     rtx result;
286718334Speter     rtx equiv;
286818334Speter{
286970635Sobrien  rtx final_dest = target;
287018334Speter  rtx prev, next, first, last, insn;
287118334Speter
287270635Sobrien  /* If this is a reg with REG_USERVAR_P set, then it could possibly turn
287370635Sobrien     into a MEM later.  Protect the libcall block from this change.  */
287470635Sobrien  if (! REG_P (target) || REG_USERVAR_P (target))
287570635Sobrien    target = gen_reg_rtx (GET_MODE (target));
287690075Sobrien
287790075Sobrien  /* If we're using non-call exceptions, a libcall corresponding to an
287890075Sobrien     operation that may trap may also trap.  */
287990075Sobrien  if (flag_non_call_exceptions && may_trap_p (equiv))
288090075Sobrien    {
288190075Sobrien      for (insn = insns; insn; insn = NEXT_INSN (insn))
288290075Sobrien	if (GET_CODE (insn) == CALL_INSN)
288390075Sobrien	  {
288490075Sobrien	    rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
288590075Sobrien
288690075Sobrien	    if (note != 0 && INTVAL (XEXP (note, 0)) <= 0)
288790075Sobrien	      remove_note (insn, note);
288890075Sobrien	  }
288990075Sobrien    }
289090075Sobrien  else
289152284Sobrien  /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION
289290075Sobrien     reg note to indicate that this call cannot throw or execute a nonlocal
289390075Sobrien     goto (unless there is already a REG_EH_REGION note, in which case
289490075Sobrien     we update it).  */
289590075Sobrien    for (insn = insns; insn; insn = NEXT_INSN (insn))
289652284Sobrien      if (GET_CODE (insn) == CALL_INSN)
289790075Sobrien	{
289890075Sobrien	  rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
289990075Sobrien
290090075Sobrien	  if (note != 0)
290190075Sobrien	    XEXP (note, 0) = GEN_INT (-1);
290290075Sobrien	  else
290390075Sobrien	    REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1),
290490075Sobrien						  REG_NOTES (insn));
290590075Sobrien	}
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);
291696263Sobrien      rtx note;
291718334Speter
291896263Sobrien      /* Some ports (cris) create an libcall regions at their own.  We must
291996263Sobrien	 avoid any potential nesting of LIBCALLs.  */
292096263Sobrien      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
292196263Sobrien	remove_note (insn, note);
292296263Sobrien      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
292396263Sobrien	remove_note (insn, note);
292496263Sobrien
292518334Speter      next = NEXT_INSN (insn);
292618334Speter
292718334Speter      if (set != 0 && GET_CODE (SET_DEST (set)) == REG
292818334Speter	  && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
292918334Speter	  && (insn == insns
293090075Sobrien	      || ((! INSN_P(insns)
293190075Sobrien		   || ! reg_mentioned_p (SET_DEST (set), PATTERN (insns)))
293218334Speter		  && ! reg_used_between_p (SET_DEST (set), insns, insn)
293318334Speter		  && ! modified_in_p (SET_SRC (set), insns)
293418334Speter		  && ! modified_between_p (SET_SRC (set), insns, insn))))
293518334Speter	{
293618334Speter	  if (PREV_INSN (insn))
293718334Speter	    NEXT_INSN (PREV_INSN (insn)) = next;
293818334Speter	  else
293918334Speter	    insns = next;
294018334Speter
294118334Speter	  if (next)
294218334Speter	    PREV_INSN (next) = PREV_INSN (insn);
294318334Speter
294418334Speter	  add_insn (insn);
294518334Speter	}
294618334Speter    }
294718334Speter
294818334Speter  prev = get_last_insn ();
294918334Speter
295018334Speter  /* Write the remaining insns followed by the final copy.  */
295118334Speter
295218334Speter  for (insn = insns; insn; insn = next)
295318334Speter    {
295418334Speter      next = NEXT_INSN (insn);
295518334Speter
295618334Speter      add_insn (insn);
295718334Speter    }
295818334Speter
295918334Speter  last = emit_move_insn (target, result);
296050397Sobrien  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
296150397Sobrien      != CODE_FOR_nothing)
296252284Sobrien    set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
296390075Sobrien  else
296490075Sobrien    {
296590075Sobrien      /* Remove any existing REG_EQUAL note from "last", or else it will
296690075Sobrien	 be mistaken for a note referring to the full contents of the
296790075Sobrien	 libcall value when found together with the REG_RETVAL note added
296890075Sobrien	 below.  An existing note can come from an insn expansion at
296990075Sobrien	 "last".  */
297090075Sobrien      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
297190075Sobrien    }
297218334Speter
297370635Sobrien  if (final_dest != target)
297470635Sobrien    emit_move_insn (final_dest, target);
297570635Sobrien
297618334Speter  if (prev == 0)
297718334Speter    first = get_insns ();
297818334Speter  else
297918334Speter    first = NEXT_INSN (prev);
298018334Speter
298118334Speter  /* Encapsulate the block so it gets manipulated as a unit.  */
298290075Sobrien  if (!flag_non_call_exceptions || !may_trap_p (equiv))
298390075Sobrien    {
298490075Sobrien      REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
298590075Sobrien		      			     REG_NOTES (first));
298690075Sobrien      REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
298790075Sobrien		      			    REG_NOTES (last));
298890075Sobrien    }
298918334Speter}
299018334Speter
299118334Speter/* Generate code to store zero in X.  */
299218334Speter
299318334Spetervoid
299418334Speteremit_clr_insn (x)
299518334Speter     rtx x;
299618334Speter{
299718334Speter  emit_move_insn (x, const0_rtx);
299818334Speter}
299918334Speter
300018334Speter/* Generate code to store 1 in X
300118334Speter   assuming it contains zero beforehand.  */
300218334Speter
300318334Spetervoid
300418334Speteremit_0_to_1_insn (x)
300518334Speter     rtx x;
300618334Speter{
300718334Speter  emit_move_insn (x, const1_rtx);
300818334Speter}
300918334Speter
301090075Sobrien/* Nonzero if we can perform a comparison of mode MODE straightforwardly.
301190075Sobrien   PURPOSE describes how this comparison will be used.  CODE is the rtx
301290075Sobrien   comparison code we will be using.
301318334Speter
301490075Sobrien   ??? Actually, CODE is slightly weaker than that.  A target is still
301590075Sobrien   required to implement all of the normal bcc operations, but not
301690075Sobrien   required to implement all (or any) of the unordered bcc operations.  */
301790075Sobrien
301890075Sobrienint
301990075Sobriencan_compare_p (code, mode, purpose)
302090075Sobrien     enum rtx_code code;
302190075Sobrien     enum machine_mode mode;
302290075Sobrien     enum can_compare_purpose purpose;
302390075Sobrien{
302490075Sobrien  do
302590075Sobrien    {
302690075Sobrien      if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
302790075Sobrien	{
302890075Sobrien	  if (purpose == ccp_jump)
302990075Sobrien	    return bcc_gen_fctn[(int)code] != NULL;
303090075Sobrien	  else if (purpose == ccp_store_flag)
303190075Sobrien	    return setcc_gen_code[(int)code] != CODE_FOR_nothing;
303290075Sobrien	  else
303390075Sobrien	    /* There's only one cmov entry point, and it's allowed to fail.  */
303490075Sobrien	    return 1;
303590075Sobrien	}
303690075Sobrien      if (purpose == ccp_jump
303790075Sobrien	  && cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
303890075Sobrien	return 1;
303990075Sobrien      if (purpose == ccp_cmov
304090075Sobrien	  && cmov_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
304190075Sobrien	return 1;
304290075Sobrien      if (purpose == ccp_store_flag
304390075Sobrien	  && cstore_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
304490075Sobrien	return 1;
304590075Sobrien
304690075Sobrien      mode = GET_MODE_WIDER_MODE (mode);
304790075Sobrien    }
304890075Sobrien  while (mode != VOIDmode);
304990075Sobrien
305090075Sobrien  return 0;
305190075Sobrien}
305290075Sobrien
305390075Sobrien/* This function is called when we are going to emit a compare instruction that
305490075Sobrien   compares the values found in *PX and *PY, using the rtl operator COMPARISON.
305590075Sobrien
305690075Sobrien   *PMODE is the mode of the inputs (in case they are const_int).
305790075Sobrien   *PUNSIGNEDP nonzero says that the operands are unsigned;
305818334Speter   this matters if they need to be widened.
305918334Speter
306090075Sobrien   If they have mode BLKmode, then SIZE specifies the size of both operands.
306118334Speter
306290075Sobrien   This function performs all the setup necessary so that the caller only has
306390075Sobrien   to emit a single comparison insn.  This setup can involve doing a BLKmode
306490075Sobrien   comparison or emitting a library call to perform the comparison if no insn
306590075Sobrien   is available to handle it.
306690075Sobrien   The values which are passed in through pointers can be modified; the caller
306790075Sobrien   should perform the comparison on the modified values.  */
306818334Speter
306990075Sobrienstatic void
307090075Sobrienprepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
307190075Sobrien     rtx *px, *py;
307290075Sobrien     enum rtx_code *pcomparison;
307318334Speter     rtx size;
307490075Sobrien     enum machine_mode *pmode;
307590075Sobrien     int *punsignedp;
307690075Sobrien     enum can_compare_purpose purpose;
307718334Speter{
307890075Sobrien  enum machine_mode mode = *pmode;
307990075Sobrien  rtx x = *px, y = *py;
308090075Sobrien  int unsignedp = *punsignedp;
308118334Speter  enum mode_class class;
308218334Speter
308318334Speter  class = GET_MODE_CLASS (mode);
308418334Speter
308518334Speter  /* They could both be VOIDmode if both args are immediate constants,
308618334Speter     but we should fold that at an earlier stage.
308718334Speter     With no special code here, this will call abort,
308818334Speter     reminding the programmer to implement such folding.  */
308918334Speter
309018334Speter  if (mode != BLKmode && flag_force_mem)
309118334Speter    {
309218334Speter      x = force_not_mem (x);
309318334Speter      y = force_not_mem (y);
309418334Speter    }
309518334Speter
309618334Speter  /* If we are inside an appropriately-short loop and one operand is an
309718334Speter     expensive constant, force it into a register.  */
309890075Sobrien  if (CONSTANT_P (x) && preserve_subexpressions_p ()
309990075Sobrien      && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1))
310018334Speter    x = force_reg (mode, x);
310118334Speter
310290075Sobrien  if (CONSTANT_P (y) && preserve_subexpressions_p ()
310390075Sobrien      && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1))
310418334Speter    y = force_reg (mode, y);
310518334Speter
310652284Sobrien#ifdef HAVE_cc0
310752284Sobrien  /* Abort if we have a non-canonical comparison.  The RTL documentation
310852284Sobrien     states that canonical comparisons are required only for targets which
310952284Sobrien     have cc0.  */
311052284Sobrien  if (CONSTANT_P (x) && ! CONSTANT_P (y))
311152284Sobrien    abort();
311252284Sobrien#endif
311352284Sobrien
311418334Speter  /* Don't let both operands fail to indicate the mode.  */
311518334Speter  if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode)
311618334Speter    x = force_reg (mode, x);
311718334Speter
311818334Speter  /* Handle all BLKmode compares.  */
311918334Speter
312018334Speter  if (mode == BLKmode)
312118334Speter    {
312290075Sobrien      rtx result;
312390075Sobrien      enum machine_mode result_mode;
312490075Sobrien      rtx opalign ATTRIBUTE_UNUSED
312590075Sobrien	= GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
312690075Sobrien
312718334Speter      emit_queue ();
312818334Speter      x = protect_from_queue (x, 0);
312918334Speter      y = protect_from_queue (y, 0);
313018334Speter
313118334Speter      if (size == 0)
313218334Speter	abort ();
313318334Speter#ifdef HAVE_cmpstrqi
313418334Speter      if (HAVE_cmpstrqi
313518334Speter	  && GET_CODE (size) == CONST_INT
313618334Speter	  && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
313718334Speter	{
313890075Sobrien	  result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode;
313990075Sobrien	  result = gen_reg_rtx (result_mode);
314090075Sobrien	  emit_insn (gen_cmpstrqi (result, x, y, size, opalign));
314118334Speter	}
314218334Speter      else
314318334Speter#endif
314418334Speter#ifdef HAVE_cmpstrhi
314518334Speter      if (HAVE_cmpstrhi
314618334Speter	  && GET_CODE (size) == CONST_INT
314718334Speter	  && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
314818334Speter	{
314990075Sobrien	  result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode;
315090075Sobrien	  result = gen_reg_rtx (result_mode);
315190075Sobrien	  emit_insn (gen_cmpstrhi (result, x, y, size, opalign));
315218334Speter	}
315318334Speter      else
315418334Speter#endif
315518334Speter#ifdef HAVE_cmpstrsi
315618334Speter      if (HAVE_cmpstrsi)
315718334Speter	{
315890075Sobrien	  result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
315990075Sobrien	  result = gen_reg_rtx (result_mode);
316018334Speter	  size = protect_from_queue (size, 0);
316118334Speter	  emit_insn (gen_cmpstrsi (result, x, y,
316218334Speter				   convert_to_mode (SImode, size, 1),
316390075Sobrien				   opalign));
316418334Speter	}
316518334Speter      else
316618334Speter#endif
316718334Speter	{
316818334Speter#ifdef TARGET_MEM_FUNCTIONS
316990075Sobrien	  emit_library_call (memcmp_libfunc, LCT_PURE_MAKE_BLOCK,
317018334Speter			     TYPE_MODE (integer_type_node), 3,
317118334Speter			     XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
317250397Sobrien			     convert_to_mode (TYPE_MODE (sizetype), size,
317350397Sobrien					      TREE_UNSIGNED (sizetype)),
317450397Sobrien			     TYPE_MODE (sizetype));
317518334Speter#else
317690075Sobrien	  emit_library_call (bcmp_libfunc, LCT_PURE_MAKE_BLOCK,
317718334Speter			     TYPE_MODE (integer_type_node), 3,
317818334Speter			     XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
317950397Sobrien			     convert_to_mode (TYPE_MODE (integer_type_node),
318050397Sobrien					      size,
318150397Sobrien					      TREE_UNSIGNED (integer_type_node)),
318250397Sobrien			     TYPE_MODE (integer_type_node));
318318334Speter#endif
318450397Sobrien
318550397Sobrien	  /* Immediately move the result of the libcall into a pseudo
318650397Sobrien	     register so reload doesn't clobber the value if it needs
318750397Sobrien	     the return register for a spill reg.  */
318850397Sobrien	  result = gen_reg_rtx (TYPE_MODE (integer_type_node));
318990075Sobrien	  result_mode = TYPE_MODE (integer_type_node);
319050397Sobrien	  emit_move_insn (result,
319190075Sobrien			  hard_libcall_value (result_mode));
319218334Speter	}
319390075Sobrien      *px = result;
319490075Sobrien      *py = const0_rtx;
319590075Sobrien      *pmode = result_mode;
319618334Speter      return;
319718334Speter    }
319818334Speter
319990075Sobrien  *px = x;
320090075Sobrien  *py = y;
320190075Sobrien  if (can_compare_p (*pcomparison, mode, purpose))
320290075Sobrien    return;
320318334Speter
320418334Speter  /* Handle a lib call just for the mode we are using.  */
320518334Speter
320690075Sobrien  if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
320718334Speter    {
320818334Speter      rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
320950397Sobrien      rtx result;
321050397Sobrien
321118334Speter      /* If we want unsigned, and this mode has a distinct unsigned
321218334Speter	 comparison routine, use that.  */
321318334Speter      if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
321418334Speter	libfunc = ucmp_optab->handlers[(int) mode].libfunc;
321518334Speter
321690075Sobrien      emit_library_call (libfunc, LCT_CONST_MAKE_BLOCK, word_mode, 2, x, mode,
321790075Sobrien			 y, mode);
321818334Speter
321950397Sobrien      /* Immediately move the result of the libcall into a pseudo
322050397Sobrien	 register so reload doesn't clobber the value if it needs
322150397Sobrien	 the return register for a spill reg.  */
322250397Sobrien      result = gen_reg_rtx (word_mode);
322350397Sobrien      emit_move_insn (result, hard_libcall_value (word_mode));
322450397Sobrien
322518334Speter      /* Integer comparison returns a result that must be compared against 1,
322618334Speter	 so that even if we do an unsigned compare afterward,
322718334Speter	 there is still a value that can represent the result "less than".  */
322890075Sobrien      *px = result;
322990075Sobrien      *py = const1_rtx;
323090075Sobrien      *pmode = word_mode;
323118334Speter      return;
323218334Speter    }
323318334Speter
323418334Speter  if (class == MODE_FLOAT)
323590075Sobrien    prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
323618334Speter
323718334Speter  else
323818334Speter    abort ();
323918334Speter}
324018334Speter
324190075Sobrien/* Before emitting an insn with code ICODE, make sure that X, which is going
324290075Sobrien   to be used for operand OPNUM of the insn, is converted from mode MODE to
324390075Sobrien   WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and
324490075Sobrien   that it is accepted by the operand predicate.  Return the new value.  */
324590075Sobrien
324690075Sobrienrtx
324790075Sobrienprepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
324890075Sobrien     int icode;
324990075Sobrien     rtx x;
325090075Sobrien     int opnum;
325190075Sobrien     enum machine_mode mode, wider_mode;
325290075Sobrien     int unsignedp;
325390075Sobrien{
325490075Sobrien  x = protect_from_queue (x, 0);
325590075Sobrien
325690075Sobrien  if (mode != wider_mode)
325790075Sobrien    x = convert_modes (wider_mode, mode, x, unsignedp);
325890075Sobrien
325990075Sobrien  if (! (*insn_data[icode].operand[opnum].predicate)
326090075Sobrien      (x, insn_data[icode].operand[opnum].mode))
326190075Sobrien    x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
326290075Sobrien  return x;
326390075Sobrien}
326490075Sobrien
326590075Sobrien/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
326690075Sobrien   we can do the comparison.
326790075Sobrien   The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
326890075Sobrien   be NULL_RTX which indicates that only a comparison is to be generated.  */
326990075Sobrien
327090075Sobrienstatic void
327190075Sobrienemit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
327290075Sobrien     rtx x, y;
327390075Sobrien     enum machine_mode mode;
327490075Sobrien     enum rtx_code comparison;
327590075Sobrien     int unsignedp;
327690075Sobrien     rtx label;
327790075Sobrien{
327890075Sobrien  rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
327990075Sobrien  enum mode_class class = GET_MODE_CLASS (mode);
328090075Sobrien  enum machine_mode wider_mode = mode;
328190075Sobrien
328290075Sobrien  /* Try combined insns first.  */
328390075Sobrien  do
328490075Sobrien    {
328590075Sobrien      enum insn_code icode;
328690075Sobrien      PUT_MODE (test, wider_mode);
328790075Sobrien
328890075Sobrien      if (label)
328990075Sobrien	{
329090075Sobrien	  icode = cbranch_optab->handlers[(int)wider_mode].insn_code;
329190075Sobrien
329290075Sobrien	  if (icode != CODE_FOR_nothing
329390075Sobrien	      && (*insn_data[icode].operand[0].predicate) (test, wider_mode))
329490075Sobrien	    {
329590075Sobrien	      x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
329690075Sobrien	      y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
329790075Sobrien	      emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
329890075Sobrien	      return;
329990075Sobrien	    }
330090075Sobrien	}
330190075Sobrien
330290075Sobrien      /* Handle some compares against zero.  */
330390075Sobrien      icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
330490075Sobrien      if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
330590075Sobrien	{
330690075Sobrien	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
330790075Sobrien	  emit_insn (GEN_FCN (icode) (x));
330890075Sobrien	  if (label)
330990075Sobrien	    emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
331090075Sobrien	  return;
331190075Sobrien	}
331290075Sobrien
331390075Sobrien      /* Handle compares for which there is a directly suitable insn.  */
331490075Sobrien
331590075Sobrien      icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code;
331690075Sobrien      if (icode != CODE_FOR_nothing)
331790075Sobrien	{
331890075Sobrien	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
331990075Sobrien	  y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp);
332090075Sobrien	  emit_insn (GEN_FCN (icode) (x, y));
332190075Sobrien	  if (label)
332290075Sobrien	    emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
332390075Sobrien	  return;
332490075Sobrien	}
332590075Sobrien
332690075Sobrien      if (class != MODE_INT && class != MODE_FLOAT
332790075Sobrien	  && class != MODE_COMPLEX_FLOAT)
332890075Sobrien	break;
332990075Sobrien
333090075Sobrien      wider_mode = GET_MODE_WIDER_MODE (wider_mode);
333190075Sobrien    } while (wider_mode != VOIDmode);
333290075Sobrien
333390075Sobrien  abort ();
333490075Sobrien}
333590075Sobrien
333652284Sobrien/* Generate code to compare X with Y so that the condition codes are
333752284Sobrien   set and to jump to LABEL if the condition is true.  If X is a
333852284Sobrien   constant and Y is not a constant, then the comparison is swapped to
333952284Sobrien   ensure that the comparison RTL has the canonical form.
334052284Sobrien
334152284Sobrien   UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they
334252284Sobrien   need to be widened by emit_cmp_insn.  UNSIGNEDP is also used to select
334352284Sobrien   the proper branch condition code.
334452284Sobrien
334590075Sobrien   If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y.
334652284Sobrien
334752284Sobrien   MODE is the mode of the inputs (in case they are const_int).
334852284Sobrien
334952284Sobrien   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  It will
335052284Sobrien   be passed unchanged to emit_cmp_insn, then potentially converted into an
335152284Sobrien   unsigned variant based on UNSIGNEDP to select a proper jump instruction.  */
335252284Sobrien
335352284Sobrienvoid
335490075Sobrienemit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label)
335552284Sobrien     rtx x, y;
335652284Sobrien     enum rtx_code comparison;
335752284Sobrien     rtx size;
335852284Sobrien     enum machine_mode mode;
335952284Sobrien     int unsignedp;
336052284Sobrien     rtx label;
336152284Sobrien{
336290075Sobrien  rtx op0 = x, op1 = y;
336390075Sobrien
336490075Sobrien  /* Swap operands and condition to ensure canonical RTL.  */
336590075Sobrien  if (swap_commutative_operands_p (x, y))
336652284Sobrien    {
336790075Sobrien      /* If we're not emitting a branch, this means some caller
336890075Sobrien         is out of sync.  */
336990075Sobrien      if (! label)
337090075Sobrien	abort ();
337190075Sobrien
337290075Sobrien      op0 = y, op1 = x;
337352284Sobrien      comparison = swap_condition (comparison);
337452284Sobrien    }
337552284Sobrien
337652284Sobrien#ifdef HAVE_cc0
337752284Sobrien  /* If OP0 is still a constant, then both X and Y must be constants.  Force
337852284Sobrien     X into a register to avoid aborting in emit_cmp_insn due to non-canonical
337952284Sobrien     RTL.  */
338052284Sobrien  if (CONSTANT_P (op0))
338152284Sobrien    op0 = force_reg (mode, op0);
338252284Sobrien#endif
338352284Sobrien
338490075Sobrien  emit_queue ();
338552284Sobrien  if (unsignedp)
338652284Sobrien    comparison = unsigned_condition (comparison);
338790075Sobrien
338890075Sobrien  prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp,
338990075Sobrien		    ccp_jump);
339090075Sobrien  emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
339152284Sobrien}
339252284Sobrien
339390075Sobrien/* Like emit_cmp_and_jump_insns, but generate only the comparison.  */
339452284Sobrien
339590075Sobrienvoid
339690075Sobrienemit_cmp_insn (x, y, comparison, size, mode, unsignedp)
339790075Sobrien     rtx x, y;
339890075Sobrien     enum rtx_code comparison;
339990075Sobrien     rtx size;
340018334Speter     enum machine_mode mode;
340190075Sobrien     int unsignedp;
340218334Speter{
340390075Sobrien  emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0);
340418334Speter}
340518334Speter
340618334Speter/* Emit a library call comparison between floating point X and Y.
340718334Speter   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
340818334Speter
340990075Sobrienstatic void
341090075Sobrienprepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
341190075Sobrien     rtx *px, *py;
341290075Sobrien     enum rtx_code *pcomparison;
341390075Sobrien     enum machine_mode *pmode;
341490075Sobrien     int *punsignedp;
341518334Speter{
341690075Sobrien  enum rtx_code comparison = *pcomparison;
341790075Sobrien  rtx x = *px = protect_from_queue (*px, 0);
341890075Sobrien  rtx y = *py = protect_from_queue (*py, 0);
341918334Speter  enum machine_mode mode = GET_MODE (x);
342018334Speter  rtx libfunc = 0;
342150397Sobrien  rtx result;
342218334Speter
342318334Speter  if (mode == HFmode)
342418334Speter    switch (comparison)
342518334Speter      {
342618334Speter      case EQ:
342718334Speter	libfunc = eqhf2_libfunc;
342818334Speter	break;
342918334Speter
343018334Speter      case NE:
343118334Speter	libfunc = nehf2_libfunc;
343218334Speter	break;
343318334Speter
343418334Speter      case GT:
343518334Speter	libfunc = gthf2_libfunc;
343618334Speter	break;
343718334Speter
343818334Speter      case GE:
343918334Speter	libfunc = gehf2_libfunc;
344018334Speter	break;
344118334Speter
344218334Speter      case LT:
344318334Speter	libfunc = lthf2_libfunc;
344418334Speter	break;
344518334Speter
344618334Speter      case LE:
344718334Speter	libfunc = lehf2_libfunc;
344818334Speter	break;
344950397Sobrien
345090075Sobrien      case UNORDERED:
345190075Sobrien	libfunc = unordhf2_libfunc;
345290075Sobrien	break;
345390075Sobrien
345450397Sobrien      default:
345550397Sobrien	break;
345618334Speter      }
345718334Speter  else if (mode == SFmode)
345818334Speter    switch (comparison)
345918334Speter      {
346018334Speter      case EQ:
346118334Speter	libfunc = eqsf2_libfunc;
346218334Speter	break;
346318334Speter
346418334Speter      case NE:
346518334Speter	libfunc = nesf2_libfunc;
346618334Speter	break;
346718334Speter
346818334Speter      case GT:
346918334Speter	libfunc = gtsf2_libfunc;
347018334Speter	break;
347118334Speter
347218334Speter      case GE:
347318334Speter	libfunc = gesf2_libfunc;
347418334Speter	break;
347518334Speter
347618334Speter      case LT:
347718334Speter	libfunc = ltsf2_libfunc;
347818334Speter	break;
347918334Speter
348018334Speter      case LE:
348118334Speter	libfunc = lesf2_libfunc;
348218334Speter	break;
348350397Sobrien
348490075Sobrien      case UNORDERED:
348590075Sobrien	libfunc = unordsf2_libfunc;
348690075Sobrien	break;
348790075Sobrien
348850397Sobrien      default:
348950397Sobrien	break;
349018334Speter      }
349118334Speter  else if (mode == DFmode)
349218334Speter    switch (comparison)
349318334Speter      {
349418334Speter      case EQ:
349518334Speter	libfunc = eqdf2_libfunc;
349618334Speter	break;
349718334Speter
349818334Speter      case NE:
349918334Speter	libfunc = nedf2_libfunc;
350018334Speter	break;
350118334Speter
350218334Speter      case GT:
350318334Speter	libfunc = gtdf2_libfunc;
350418334Speter	break;
350518334Speter
350618334Speter      case GE:
350718334Speter	libfunc = gedf2_libfunc;
350818334Speter	break;
350918334Speter
351018334Speter      case LT:
351118334Speter	libfunc = ltdf2_libfunc;
351218334Speter	break;
351318334Speter
351418334Speter      case LE:
351518334Speter	libfunc = ledf2_libfunc;
351618334Speter	break;
351750397Sobrien
351890075Sobrien      case UNORDERED:
351990075Sobrien	libfunc = unorddf2_libfunc;
352090075Sobrien	break;
352190075Sobrien
352250397Sobrien      default:
352350397Sobrien	break;
352418334Speter      }
352518334Speter  else if (mode == XFmode)
352618334Speter    switch (comparison)
352718334Speter      {
352818334Speter      case EQ:
352918334Speter	libfunc = eqxf2_libfunc;
353018334Speter	break;
353118334Speter
353218334Speter      case NE:
353318334Speter	libfunc = nexf2_libfunc;
353418334Speter	break;
353518334Speter
353618334Speter      case GT:
353718334Speter	libfunc = gtxf2_libfunc;
353818334Speter	break;
353918334Speter
354018334Speter      case GE:
354118334Speter	libfunc = gexf2_libfunc;
354218334Speter	break;
354318334Speter
354418334Speter      case LT:
354518334Speter	libfunc = ltxf2_libfunc;
354618334Speter	break;
354718334Speter
354818334Speter      case LE:
354918334Speter	libfunc = lexf2_libfunc;
355018334Speter	break;
355150397Sobrien
355290075Sobrien      case UNORDERED:
355390075Sobrien	libfunc = unordxf2_libfunc;
355490075Sobrien	break;
355590075Sobrien
355650397Sobrien      default:
355750397Sobrien	break;
355818334Speter      }
355918334Speter  else if (mode == TFmode)
356018334Speter    switch (comparison)
356118334Speter      {
356218334Speter      case EQ:
356318334Speter	libfunc = eqtf2_libfunc;
356418334Speter	break;
356518334Speter
356618334Speter      case NE:
356718334Speter	libfunc = netf2_libfunc;
356818334Speter	break;
356918334Speter
357018334Speter      case GT:
357118334Speter	libfunc = gttf2_libfunc;
357218334Speter	break;
357318334Speter
357418334Speter      case GE:
357518334Speter	libfunc = getf2_libfunc;
357618334Speter	break;
357718334Speter
357818334Speter      case LT:
357918334Speter	libfunc = lttf2_libfunc;
358018334Speter	break;
358118334Speter
358218334Speter      case LE:
358318334Speter	libfunc = letf2_libfunc;
358418334Speter	break;
358550397Sobrien
358690075Sobrien      case UNORDERED:
358790075Sobrien	libfunc = unordtf2_libfunc;
358890075Sobrien	break;
358990075Sobrien
359050397Sobrien      default:
359150397Sobrien	break;
359218334Speter      }
359318334Speter  else
359418334Speter    {
359518334Speter      enum machine_mode wider_mode;
359618334Speter
359718334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
359818334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
359918334Speter	{
360018334Speter	  if ((cmp_optab->handlers[(int) wider_mode].insn_code
360118334Speter	       != CODE_FOR_nothing)
360218334Speter	      || (cmp_optab->handlers[(int) wider_mode].libfunc != 0))
360318334Speter	    {
360418334Speter	      x = protect_from_queue (x, 0);
360518334Speter	      y = protect_from_queue (y, 0);
360690075Sobrien	      *px = convert_to_mode (wider_mode, x, 0);
360790075Sobrien	      *py = convert_to_mode (wider_mode, y, 0);
360890075Sobrien	      prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
360918334Speter	      return;
361018334Speter	    }
361118334Speter	}
361218334Speter      abort ();
361318334Speter    }
361418334Speter
361518334Speter  if (libfunc == 0)
361618334Speter    abort ();
361718334Speter
361890075Sobrien  emit_library_call (libfunc, LCT_CONST_MAKE_BLOCK, word_mode, 2, x, mode, y,
361990075Sobrien		     mode);
362018334Speter
362150397Sobrien  /* Immediately move the result of the libcall into a pseudo
362250397Sobrien     register so reload doesn't clobber the value if it needs
362350397Sobrien     the return register for a spill reg.  */
362450397Sobrien  result = gen_reg_rtx (word_mode);
362550397Sobrien  emit_move_insn (result, hard_libcall_value (word_mode));
362690075Sobrien  *px = result;
362790075Sobrien  *py = const0_rtx;
362890075Sobrien  *pmode = word_mode;
362990075Sobrien  if (comparison == UNORDERED)
363090075Sobrien    *pcomparison = NE;
363190075Sobrien#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL
363290075Sobrien  else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
363390075Sobrien    *pcomparison = NE;
363490075Sobrien#endif
363590075Sobrien  *punsignedp = 0;
363618334Speter}
363718334Speter
363818334Speter/* Generate code to indirectly jump to a location given in the rtx LOC.  */
363918334Speter
364018334Spetervoid
364118334Speteremit_indirect_jump (loc)
364218334Speter     rtx loc;
364318334Speter{
364490075Sobrien  if (! ((*insn_data[(int)CODE_FOR_indirect_jump].operand[0].predicate)
364518334Speter	 (loc, Pmode)))
364618334Speter    loc = copy_to_mode_reg (Pmode, loc);
364718334Speter
364818334Speter  emit_jump_insn (gen_indirect_jump (loc));
364918334Speter  emit_barrier ();
365018334Speter}
365118334Speter
365218334Speter#ifdef HAVE_conditional_move
365318334Speter
365418334Speter/* Emit a conditional move instruction if the machine supports one for that
365518334Speter   condition and machine mode.
365618334Speter
365718334Speter   OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
365818334Speter   the mode to use should they be constants.  If it is VOIDmode, they cannot
365918334Speter   both be constants.
366018334Speter
366118334Speter   OP2 should be stored in TARGET if the comparison is true, otherwise OP3
366218334Speter   should be stored there.  MODE is the mode to use should they be constants.
366318334Speter   If it is VOIDmode, they cannot both be constants.
366418334Speter
366518334Speter   The result is either TARGET (perhaps modified) or NULL_RTX if the operation
366618334Speter   is not supported.  */
366718334Speter
366818334Speterrtx
366918334Speteremit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
367018334Speter		       unsignedp)
367118334Speter     rtx target;
367218334Speter     enum rtx_code code;
367318334Speter     rtx op0, op1;
367418334Speter     enum machine_mode cmode;
367518334Speter     rtx op2, op3;
367618334Speter     enum machine_mode mode;
367718334Speter     int unsignedp;
367818334Speter{
367918334Speter  rtx tem, subtarget, comparison, insn;
368018334Speter  enum insn_code icode;
368190075Sobrien  enum rtx_code reversed;
368218334Speter
368318334Speter  /* If one operand is constant, make it the second one.  Only do this
368418334Speter     if the other operand is not constant as well.  */
368518334Speter
368690075Sobrien  if (swap_commutative_operands_p (op0, op1))
368718334Speter    {
368818334Speter      tem = op0;
368918334Speter      op0 = op1;
369018334Speter      op1 = tem;
369118334Speter      code = swap_condition (code);
369218334Speter    }
369318334Speter
369490075Sobrien  /* get_condition will prefer to generate LT and GT even if the old
369590075Sobrien     comparison was against zero, so undo that canonicalization here since
369690075Sobrien     comparisons against zero are cheaper.  */
369790075Sobrien  if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
369890075Sobrien    code = LE, op1 = const0_rtx;
369990075Sobrien  else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
370090075Sobrien    code = GE, op1 = const0_rtx;
370190075Sobrien
370218334Speter  if (cmode == VOIDmode)
370318334Speter    cmode = GET_MODE (op0);
370418334Speter
370590075Sobrien  if (swap_commutative_operands_p (op2, op3)
370690075Sobrien      && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
370790075Sobrien          != UNKNOWN))
370818334Speter    {
370918334Speter      tem = op2;
371018334Speter      op2 = op3;
371118334Speter      op3 = tem;
371290075Sobrien      code = reversed;
371318334Speter    }
371418334Speter
371518334Speter  if (mode == VOIDmode)
371618334Speter    mode = GET_MODE (op2);
371718334Speter
371818334Speter  icode = movcc_gen_code[mode];
371918334Speter
372018334Speter  if (icode == CODE_FOR_nothing)
372118334Speter    return 0;
372218334Speter
372318334Speter  if (flag_force_mem)
372418334Speter    {
372518334Speter      op2 = force_not_mem (op2);
372618334Speter      op3 = force_not_mem (op3);
372718334Speter    }
372818334Speter
372918334Speter  if (target)
373018334Speter    target = protect_from_queue (target, 1);
373118334Speter  else
373218334Speter    target = gen_reg_rtx (mode);
373318334Speter
373418334Speter  subtarget = target;
373518334Speter
373618334Speter  emit_queue ();
373718334Speter
373818334Speter  op2 = protect_from_queue (op2, 0);
373918334Speter  op3 = protect_from_queue (op3, 0);
374018334Speter
374118334Speter  /* If the insn doesn't accept these operands, put them in pseudos.  */
374218334Speter
374390075Sobrien  if (! (*insn_data[icode].operand[0].predicate)
374490075Sobrien      (subtarget, insn_data[icode].operand[0].mode))
374590075Sobrien    subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
374618334Speter
374790075Sobrien  if (! (*insn_data[icode].operand[2].predicate)
374890075Sobrien      (op2, insn_data[icode].operand[2].mode))
374990075Sobrien    op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
375018334Speter
375190075Sobrien  if (! (*insn_data[icode].operand[3].predicate)
375290075Sobrien      (op3, insn_data[icode].operand[3].mode))
375390075Sobrien    op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
375418334Speter
375518334Speter  /* Everything should now be in the suitable form, so emit the compare insn
375618334Speter     and then the conditional move.  */
375718334Speter
375818334Speter  comparison
375990075Sobrien    = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
376018334Speter
376118334Speter  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
376290075Sobrien  /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
376390075Sobrien     return NULL and let the caller figure out how best to deal with this
376490075Sobrien     situation.  */
376518334Speter  if (GET_CODE (comparison) != code)
376690075Sobrien    return NULL_RTX;
376718334Speter
376818334Speter  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
376918334Speter
377018334Speter  /* If that failed, then give up.  */
377118334Speter  if (insn == 0)
377218334Speter    return 0;
377318334Speter
377418334Speter  emit_insn (insn);
377518334Speter
377618334Speter  if (subtarget != target)
377718334Speter    convert_move (target, subtarget, 0);
377818334Speter
377918334Speter  return target;
378018334Speter}
378118334Speter
378218334Speter/* Return non-zero if a conditional move of mode MODE is supported.
378318334Speter
378418334Speter   This function is for combine so it can tell whether an insn that looks
378518334Speter   like a conditional move is actually supported by the hardware.  If we
378618334Speter   guess wrong we lose a bit on optimization, but that's it.  */
378718334Speter/* ??? sparc64 supports conditionally moving integers values based on fp
378818334Speter   comparisons, and vice versa.  How do we handle them?  */
378918334Speter
379018334Speterint
379118334Spetercan_conditionally_move_p (mode)
379218334Speter     enum machine_mode mode;
379318334Speter{
379418334Speter  if (movcc_gen_code[mode] != CODE_FOR_nothing)
379518334Speter    return 1;
379618334Speter
379718334Speter  return 0;
379818334Speter}
379918334Speter
380018334Speter#endif /* HAVE_conditional_move */
380118334Speter
380290075Sobrien/* These functions generate an insn body and return it
380318334Speter   rather than emitting the insn.
380418334Speter
380518334Speter   They do not protect from queued increments,
380618334Speter   because they may be used 1) in protect_from_queue itself
380718334Speter   and 2) in other passes where there is no queue.  */
380818334Speter
380918334Speter/* Generate and return an insn body to add Y to X.  */
381018334Speter
381118334Speterrtx
381218334Spetergen_add2_insn (x, y)
381318334Speter     rtx x, y;
381418334Speter{
381518334Speter  int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
381618334Speter
381790075Sobrien  if (! ((*insn_data[icode].operand[0].predicate)
381890075Sobrien	 (x, insn_data[icode].operand[0].mode))
381990075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
382090075Sobrien	    (x, insn_data[icode].operand[1].mode))
382190075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
382290075Sobrien	    (y, insn_data[icode].operand[2].mode)))
382318334Speter    abort ();
382418334Speter
382518334Speter  return (GEN_FCN (icode) (x, x, y));
382618334Speter}
382718334Speter
382890075Sobrien/* Generate and return an insn body to add r1 and c,
382990075Sobrien   storing the result in r0.  */
383090075Sobrienrtx
383190075Sobriengen_add3_insn (r0, r1, c)
383290075Sobrien     rtx r0, r1, c;
383390075Sobrien{
383490075Sobrien  int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
383590075Sobrien
383690075Sobrien    if (icode == CODE_FOR_nothing
383790075Sobrien      || ! ((*insn_data[icode].operand[0].predicate)
383890075Sobrien	    (r0, insn_data[icode].operand[0].mode))
383990075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
384090075Sobrien	    (r1, insn_data[icode].operand[1].mode))
384190075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
384290075Sobrien	    (c, insn_data[icode].operand[2].mode)))
384390075Sobrien    return NULL_RTX;
384490075Sobrien
384590075Sobrien  return (GEN_FCN (icode) (r0, r1, c));
384690075Sobrien}
384790075Sobrien
384818334Speterint
384990075Sobrienhave_add2_insn (x, y)
385090075Sobrien     rtx x, y;
385118334Speter{
385290075Sobrien  int icode;
385390075Sobrien
385490075Sobrien  if (GET_MODE (x) == VOIDmode)
385590075Sobrien    abort ();
385690075Sobrien
385790075Sobrien  icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
385890075Sobrien
385990075Sobrien  if (icode == CODE_FOR_nothing)
386090075Sobrien    return 0;
386190075Sobrien
386290075Sobrien  if (! ((*insn_data[icode].operand[0].predicate)
386390075Sobrien	 (x, insn_data[icode].operand[0].mode))
386490075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
386590075Sobrien	    (x, insn_data[icode].operand[1].mode))
386690075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
386790075Sobrien	    (y, insn_data[icode].operand[2].mode)))
386890075Sobrien    return 0;
386990075Sobrien
387090075Sobrien  return 1;
387118334Speter}
387218334Speter
387318334Speter/* Generate and return an insn body to subtract Y from X.  */
387418334Speter
387518334Speterrtx
387618334Spetergen_sub2_insn (x, y)
387718334Speter     rtx x, y;
387818334Speter{
387918334Speter  int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
388018334Speter
388190075Sobrien  if (! ((*insn_data[icode].operand[0].predicate)
388290075Sobrien	 (x, insn_data[icode].operand[0].mode))
388390075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
388490075Sobrien	    (x, insn_data[icode].operand[1].mode))
388590075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
388690075Sobrien	    (y, insn_data[icode].operand[2].mode)))
388718334Speter    abort ();
388818334Speter
388918334Speter  return (GEN_FCN (icode) (x, x, y));
389018334Speter}
389118334Speter
389290075Sobrien/* Generate and return an insn body to subtract r1 and c,
389390075Sobrien   storing the result in r0.  */
389490075Sobrienrtx
389590075Sobriengen_sub3_insn (r0, r1, c)
389690075Sobrien     rtx r0, r1, c;
389790075Sobrien{
389890075Sobrien  int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code;
389990075Sobrien
390090075Sobrien    if (icode == CODE_FOR_nothing
390190075Sobrien      || ! ((*insn_data[icode].operand[0].predicate)
390290075Sobrien	    (r0, insn_data[icode].operand[0].mode))
390390075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
390490075Sobrien	    (r1, insn_data[icode].operand[1].mode))
390590075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
390690075Sobrien	    (c, insn_data[icode].operand[2].mode)))
390790075Sobrien    return NULL_RTX;
390890075Sobrien
390990075Sobrien  return (GEN_FCN (icode) (r0, r1, c));
391090075Sobrien}
391190075Sobrien
391218334Speterint
391390075Sobrienhave_sub2_insn (x, y)
391490075Sobrien     rtx x, y;
391518334Speter{
391690075Sobrien  int icode;
391790075Sobrien
391890075Sobrien  if (GET_MODE (x) == VOIDmode)
391990075Sobrien    abort ();
392090075Sobrien
392190075Sobrien  icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
392290075Sobrien
392390075Sobrien  if (icode == CODE_FOR_nothing)
392490075Sobrien    return 0;
392590075Sobrien
392690075Sobrien  if (! ((*insn_data[icode].operand[0].predicate)
392790075Sobrien	 (x, insn_data[icode].operand[0].mode))
392890075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
392990075Sobrien	    (x, insn_data[icode].operand[1].mode))
393090075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
393190075Sobrien	    (y, insn_data[icode].operand[2].mode)))
393290075Sobrien    return 0;
393390075Sobrien
393490075Sobrien  return 1;
393518334Speter}
393618334Speter
393718334Speter/* Generate the body of an instruction to copy Y into X.
393818334Speter   It may be a SEQUENCE, if one insn isn't enough.  */
393918334Speter
394018334Speterrtx
394118334Spetergen_move_insn (x, y)
394218334Speter     rtx x, y;
394318334Speter{
394490075Sobrien  enum machine_mode mode = GET_MODE (x);
394518334Speter  enum insn_code insn_code;
394618334Speter  rtx seq;
394718334Speter
394818334Speter  if (mode == VOIDmode)
394918334Speter    mode = GET_MODE (y);
395018334Speter
395118334Speter  insn_code = mov_optab->handlers[(int) mode].insn_code;
395218334Speter
395318334Speter  /* Handle MODE_CC modes:  If we don't have a special move insn for this mode,
395418334Speter     find a mode to do it in.  If we have a movcc, use it.  Otherwise,
395518334Speter     find the MODE_INT mode of the same width.  */
395618334Speter
395718334Speter  if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing)
395818334Speter    {
395918334Speter      enum machine_mode tmode = VOIDmode;
396018334Speter      rtx x1 = x, y1 = y;
396118334Speter
396218334Speter      if (mode != CCmode
396318334Speter	  && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
396418334Speter	tmode = CCmode;
396518334Speter      else
396618334Speter	for (tmode = QImode; tmode != VOIDmode;
396718334Speter	     tmode = GET_MODE_WIDER_MODE (tmode))
396818334Speter	  if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
396918334Speter	    break;
397018334Speter
397118334Speter      if (tmode == VOIDmode)
397218334Speter	abort ();
397318334Speter
397418334Speter      /* Get X and Y in TMODE.  We can't use gen_lowpart here because it
397518334Speter	 may call change_address which is not appropriate if we were
397618334Speter	 called when a reload was in progress.  We don't have to worry
397718334Speter	 about changing the address since the size in bytes is supposed to
397818334Speter	 be the same.  Copy the MEM to change the mode and move any
397918334Speter	 substitutions from the old MEM to the new one.  */
398018334Speter
398118334Speter      if (reload_in_progress)
398218334Speter	{
398318334Speter	  x = gen_lowpart_common (tmode, x1);
398418334Speter	  if (x == 0 && GET_CODE (x1) == MEM)
398518334Speter	    {
398690075Sobrien	      x = adjust_address_nv (x1, tmode, 0);
398718334Speter	      copy_replacements (x1, x);
398818334Speter	    }
398918334Speter
399018334Speter	  y = gen_lowpart_common (tmode, y1);
399118334Speter	  if (y == 0 && GET_CODE (y1) == MEM)
399218334Speter	    {
399390075Sobrien	      y = adjust_address_nv (y1, tmode, 0);
399418334Speter	      copy_replacements (y1, y);
399518334Speter	    }
399618334Speter	}
399718334Speter      else
399818334Speter	{
399918334Speter	  x = gen_lowpart (tmode, x);
400018334Speter	  y = gen_lowpart (tmode, y);
400118334Speter	}
400218334Speter
400318334Speter      insn_code = mov_optab->handlers[(int) tmode].insn_code;
400418334Speter      return (GEN_FCN (insn_code) (x, y));
400518334Speter    }
400618334Speter
400718334Speter  start_sequence ();
400818334Speter  emit_move_insn_1 (x, y);
400918334Speter  seq = gen_sequence ();
401018334Speter  end_sequence ();
401118334Speter  return seq;
401218334Speter}
401318334Speter
401418334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE.
401518334Speter   UNSIGNEDP specifies zero-extension instead of sign-extension.  If
401618334Speter   no such operation exists, CODE_FOR_nothing will be returned.  */
401718334Speter
401818334Speterenum insn_code
401918334Spetercan_extend_p (to_mode, from_mode, unsignedp)
402018334Speter     enum machine_mode to_mode, from_mode;
402118334Speter     int unsignedp;
402218334Speter{
402390075Sobrien#ifdef HAVE_ptr_extend
402490075Sobrien  if (unsignedp < 0)
402590075Sobrien    return CODE_FOR_ptr_extend;
402690075Sobrien  else
402790075Sobrien#endif
402890075Sobrien    return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0];
402918334Speter}
403018334Speter
403118334Speter/* Generate the body of an insn to extend Y (with mode MFROM)
403218334Speter   into X (with mode MTO).  Do zero-extension if UNSIGNEDP is nonzero.  */
403318334Speter
403418334Speterrtx
403518334Spetergen_extend_insn (x, y, mto, mfrom, unsignedp)
403618334Speter     rtx x, y;
403718334Speter     enum machine_mode mto, mfrom;
403818334Speter     int unsignedp;
403918334Speter{
404090075Sobrien  return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp != 0]) (x, y));
404118334Speter}
404218334Speter
404318334Speter/* can_fix_p and can_float_p say whether the target machine
404418334Speter   can directly convert a given fixed point type to
404518334Speter   a given floating point type, or vice versa.
404618334Speter   The returned value is the CODE_FOR_... value to use,
404718334Speter   or CODE_FOR_nothing if these modes cannot be directly converted.
404818334Speter
404918334Speter   *TRUNCP_PTR is set to 1 if it is necessary to output
405018334Speter   an explicit FTRUNC insn before the fix insn; otherwise 0.  */
405118334Speter
405218334Speterstatic enum insn_code
405318334Spetercan_fix_p (fixmode, fltmode, unsignedp, truncp_ptr)
405418334Speter     enum machine_mode fltmode, fixmode;
405518334Speter     int unsignedp;
405618334Speter     int *truncp_ptr;
405718334Speter{
405818334Speter  *truncp_ptr = 0;
405990075Sobrien  if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0]
406090075Sobrien      != CODE_FOR_nothing)
406190075Sobrien    return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0];
406218334Speter
406318334Speter  if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing)
406418334Speter    {
406518334Speter      *truncp_ptr = 1;
406690075Sobrien      return fixtab[(int) fltmode][(int) fixmode][unsignedp != 0];
406718334Speter    }
406818334Speter  return CODE_FOR_nothing;
406918334Speter}
407018334Speter
407118334Speterstatic enum insn_code
407218334Spetercan_float_p (fltmode, fixmode, unsignedp)
407318334Speter     enum machine_mode fixmode, fltmode;
407418334Speter     int unsignedp;
407518334Speter{
407690075Sobrien  return floattab[(int) fltmode][(int) fixmode][unsignedp != 0];
407718334Speter}
407818334Speter
407918334Speter/* Generate code to convert FROM to floating point
408018334Speter   and store in TO.  FROM must be fixed point and not VOIDmode.
408118334Speter   UNSIGNEDP nonzero means regard FROM as unsigned.
408218334Speter   Normally this is done by correcting the final value
408318334Speter   if it is negative.  */
408418334Speter
408518334Spetervoid
408618334Speterexpand_float (to, from, unsignedp)
408718334Speter     rtx to, from;
408818334Speter     int unsignedp;
408918334Speter{
409018334Speter  enum insn_code icode;
409190075Sobrien  rtx target = to;
409218334Speter  enum machine_mode fmode, imode;
409318334Speter
409418334Speter  /* Crash now, because we won't be able to decide which mode to use.  */
409518334Speter  if (GET_MODE (from) == VOIDmode)
409618334Speter    abort ();
409718334Speter
409818334Speter  /* Look for an insn to do the conversion.  Do it in the specified
409918334Speter     modes if possible; otherwise convert either input, output or both to
410018334Speter     wider mode.  If the integer mode is wider than the mode of FROM,
410118334Speter     we can do the conversion signed even if the input is unsigned.  */
410218334Speter
410318334Speter  for (imode = GET_MODE (from); imode != VOIDmode;
410418334Speter       imode = GET_MODE_WIDER_MODE (imode))
410518334Speter    for (fmode = GET_MODE (to); fmode != VOIDmode;
410618334Speter	 fmode = GET_MODE_WIDER_MODE (fmode))
410718334Speter      {
410818334Speter	int doing_unsigned = unsignedp;
410918334Speter
411090075Sobrien	if (fmode != GET_MODE (to)
411190075Sobrien	    && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from)))
411290075Sobrien	  continue;
411390075Sobrien
411418334Speter	icode = can_float_p (fmode, imode, unsignedp);
411518334Speter	if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
411618334Speter	  icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
411718334Speter
411818334Speter	if (icode != CODE_FOR_nothing)
411918334Speter	  {
412018334Speter	    to = protect_from_queue (to, 1);
412118334Speter	    from = protect_from_queue (from, 0);
412218334Speter
412318334Speter	    if (imode != GET_MODE (from))
412418334Speter	      from = convert_to_mode (imode, from, unsignedp);
412518334Speter
412618334Speter	    if (fmode != GET_MODE (to))
412718334Speter	      target = gen_reg_rtx (fmode);
412818334Speter
412918334Speter	    emit_unop_insn (icode, target, from,
413018334Speter			    doing_unsigned ? UNSIGNED_FLOAT : FLOAT);
413118334Speter
413218334Speter	    if (target != to)
413318334Speter	      convert_move (to, target, 0);
413418334Speter	    return;
413518334Speter	  }
413618334Speter    }
413718334Speter
413818334Speter#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
413918334Speter
414018334Speter  /* Unsigned integer, and no way to convert directly.
414118334Speter     Convert as signed, then conditionally adjust the result.  */
414218334Speter  if (unsignedp)
414318334Speter    {
414418334Speter      rtx label = gen_label_rtx ();
414518334Speter      rtx temp;
414618334Speter      REAL_VALUE_TYPE offset;
414718334Speter
414818334Speter      emit_queue ();
414918334Speter
415018334Speter      to = protect_from_queue (to, 1);
415118334Speter      from = protect_from_queue (from, 0);
415218334Speter
415318334Speter      if (flag_force_mem)
415418334Speter	from = force_not_mem (from);
415518334Speter
415618334Speter      /* Look for a usable floating mode FMODE wider than the source and at
415718334Speter	 least as wide as the target.  Using FMODE will avoid rounding woes
415818334Speter	 with unsigned values greater than the signed maximum value.  */
415918334Speter
416018334Speter      for (fmode = GET_MODE (to);  fmode != VOIDmode;
416118334Speter	   fmode = GET_MODE_WIDER_MODE (fmode))
416218334Speter	if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
416318334Speter	    && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
416418334Speter	  break;
416518334Speter
416618334Speter      if (fmode == VOIDmode)
416718334Speter	{
416818334Speter	  /* There is no such mode.  Pretend the target is wide enough.  */
416918334Speter	  fmode = GET_MODE (to);
417018334Speter
417150397Sobrien	  /* Avoid double-rounding when TO is narrower than FROM.  */
417218334Speter	  if ((significand_size (fmode) + 1)
417318334Speter	      < GET_MODE_BITSIZE (GET_MODE (from)))
417418334Speter	    {
417518334Speter	      rtx temp1;
417618334Speter	      rtx neglabel = gen_label_rtx ();
417718334Speter
417818334Speter	      /* Don't use TARGET if it isn't a register, is a hard register,
417918334Speter		 or is the wrong mode.  */
418018334Speter	      if (GET_CODE (target) != REG
418118334Speter		  || REGNO (target) < FIRST_PSEUDO_REGISTER
418218334Speter		  || GET_MODE (target) != fmode)
418318334Speter		target = gen_reg_rtx (fmode);
418418334Speter
418518334Speter	      imode = GET_MODE (from);
418618334Speter	      do_pending_stack_adjust ();
418718334Speter
418818334Speter	      /* Test whether the sign bit is set.  */
418990075Sobrien	      emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode,
419090075Sobrien				       0, neglabel);
419118334Speter
419218334Speter	      /* The sign bit is not set.  Convert as signed.  */
419318334Speter	      expand_float (target, from, 0);
419418334Speter	      emit_jump_insn (gen_jump (label));
419518334Speter	      emit_barrier ();
419618334Speter
419718334Speter	      /* The sign bit is set.
419818334Speter		 Convert to a usable (positive signed) value by shifting right
419918334Speter		 one bit, while remembering if a nonzero bit was shifted
420018334Speter		 out; i.e., compute  (from & 1) | (from >> 1).  */
420118334Speter
420218334Speter	      emit_label (neglabel);
420318334Speter	      temp = expand_binop (imode, and_optab, from, const1_rtx,
420418334Speter				   NULL_RTX, 1, OPTAB_LIB_WIDEN);
420518334Speter	      temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
420618334Speter				    NULL_RTX, 1);
420718334Speter	      temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
420818334Speter				   OPTAB_LIB_WIDEN);
420918334Speter	      expand_float (target, temp, 0);
421018334Speter
421118334Speter	      /* Multiply by 2 to undo the shift above.  */
421218334Speter	      temp = expand_binop (fmode, add_optab, target, target,
421318334Speter				     target, 0, OPTAB_LIB_WIDEN);
421418334Speter	      if (temp != target)
421518334Speter		emit_move_insn (target, temp);
421618334Speter
421718334Speter	      do_pending_stack_adjust ();
421818334Speter	      emit_label (label);
421918334Speter	      goto done;
422018334Speter	    }
422118334Speter	}
422218334Speter
422318334Speter      /* If we are about to do some arithmetic to correct for an
422418334Speter	 unsigned operand, do it in a pseudo-register.  */
422518334Speter
422618334Speter      if (GET_MODE (to) != fmode
422718334Speter	  || GET_CODE (to) != REG || REGNO (to) < FIRST_PSEUDO_REGISTER)
422818334Speter	target = gen_reg_rtx (fmode);
422918334Speter
423018334Speter      /* Convert as signed integer to floating.  */
423118334Speter      expand_float (target, from, 0);
423218334Speter
423318334Speter      /* If FROM is negative (and therefore TO is negative),
423418334Speter	 correct its value by 2**bitwidth.  */
423518334Speter
423618334Speter      do_pending_stack_adjust ();
423752284Sobrien      emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
423890075Sobrien			       0, label);
423918334Speter
424018334Speter      /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1).
424118334Speter	 Rather than setting up a dconst_dot_5, let's hope SCO
424218334Speter	 fixes the bug.  */
424318334Speter      offset = REAL_VALUE_LDEXP (dconst1, GET_MODE_BITSIZE (GET_MODE (from)));
424418334Speter      temp = expand_binop (fmode, add_optab, target,
424518334Speter			   CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
424618334Speter			   target, 0, OPTAB_LIB_WIDEN);
424718334Speter      if (temp != target)
424818334Speter	emit_move_insn (target, temp);
424918334Speter
425018334Speter      do_pending_stack_adjust ();
425118334Speter      emit_label (label);
425218334Speter      goto done;
425318334Speter    }
425418334Speter#endif
425518334Speter
425618334Speter  /* No hardware instruction available; call a library routine to convert from
425718334Speter     SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode.  */
425818334Speter    {
425918334Speter      rtx libfcn;
426018334Speter      rtx insns;
426118334Speter      rtx value;
426218334Speter
426318334Speter      to = protect_from_queue (to, 1);
426418334Speter      from = protect_from_queue (from, 0);
426518334Speter
426618334Speter      if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
426718334Speter	from = convert_to_mode (SImode, from, unsignedp);
426818334Speter
426918334Speter      if (flag_force_mem)
427018334Speter	from = force_not_mem (from);
427118334Speter
427218334Speter      if (GET_MODE (to) == SFmode)
427318334Speter	{
427418334Speter	  if (GET_MODE (from) == SImode)
427518334Speter	    libfcn = floatsisf_libfunc;
427618334Speter	  else if (GET_MODE (from) == DImode)
427718334Speter	    libfcn = floatdisf_libfunc;
427818334Speter	  else if (GET_MODE (from) == TImode)
427918334Speter	    libfcn = floattisf_libfunc;
428018334Speter	  else
428118334Speter	    abort ();
428218334Speter	}
428318334Speter      else if (GET_MODE (to) == DFmode)
428418334Speter	{
428518334Speter	  if (GET_MODE (from) == SImode)
428618334Speter	    libfcn = floatsidf_libfunc;
428718334Speter	  else if (GET_MODE (from) == DImode)
428818334Speter	    libfcn = floatdidf_libfunc;
428918334Speter	  else if (GET_MODE (from) == TImode)
429018334Speter	    libfcn = floattidf_libfunc;
429118334Speter	  else
429218334Speter	    abort ();
429318334Speter	}
429418334Speter      else if (GET_MODE (to) == XFmode)
429518334Speter	{
429618334Speter	  if (GET_MODE (from) == SImode)
429718334Speter	    libfcn = floatsixf_libfunc;
429818334Speter	  else if (GET_MODE (from) == DImode)
429918334Speter	    libfcn = floatdixf_libfunc;
430018334Speter	  else if (GET_MODE (from) == TImode)
430118334Speter	    libfcn = floattixf_libfunc;
430218334Speter	  else
430318334Speter	    abort ();
430418334Speter	}
430518334Speter      else if (GET_MODE (to) == TFmode)
430618334Speter	{
430718334Speter	  if (GET_MODE (from) == SImode)
430818334Speter	    libfcn = floatsitf_libfunc;
430918334Speter	  else if (GET_MODE (from) == DImode)
431018334Speter	    libfcn = floatditf_libfunc;
431118334Speter	  else if (GET_MODE (from) == TImode)
431218334Speter	    libfcn = floattitf_libfunc;
431318334Speter	  else
431418334Speter	    abort ();
431518334Speter	}
431618334Speter      else
431718334Speter	abort ();
431818334Speter
431918334Speter      start_sequence ();
432018334Speter
432190075Sobrien      value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
432290075Sobrien				       GET_MODE (to), 1, from,
432390075Sobrien				       GET_MODE (from));
432418334Speter      insns = get_insns ();
432518334Speter      end_sequence ();
432618334Speter
432718334Speter      emit_libcall_block (insns, target, value,
432850397Sobrien			  gen_rtx_FLOAT (GET_MODE (to), from));
432918334Speter    }
433018334Speter
433118334Speter done:
433218334Speter
433318334Speter  /* Copy result to requested destination
433418334Speter     if we have been computing in a temp location.  */
433518334Speter
433618334Speter  if (target != to)
433718334Speter    {
433818334Speter      if (GET_MODE (target) == GET_MODE (to))
433918334Speter	emit_move_insn (to, target);
434018334Speter      else
434118334Speter	convert_move (to, target, 0);
434218334Speter    }
434318334Speter}
434418334Speter
434518334Speter/* expand_fix: generate code to convert FROM to fixed point
434618334Speter   and store in TO.  FROM must be floating point.  */
434718334Speter
434818334Speterstatic rtx
434918334Speterftruncify (x)
435018334Speter     rtx x;
435118334Speter{
435218334Speter  rtx temp = gen_reg_rtx (GET_MODE (x));
435318334Speter  return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0);
435418334Speter}
435518334Speter
435618334Spetervoid
435718334Speterexpand_fix (to, from, unsignedp)
435890075Sobrien     rtx to, from;
435918334Speter     int unsignedp;
436018334Speter{
436118334Speter  enum insn_code icode;
436290075Sobrien  rtx target = to;
436318334Speter  enum machine_mode fmode, imode;
436418334Speter  int must_trunc = 0;
436518334Speter  rtx libfcn = 0;
436618334Speter
436718334Speter  /* We first try to find a pair of modes, one real and one integer, at
436818334Speter     least as wide as FROM and TO, respectively, in which we can open-code
436918334Speter     this conversion.  If the integer mode is wider than the mode of TO,
437018334Speter     we can do the conversion either signed or unsigned.  */
437118334Speter
437290075Sobrien  for (fmode = GET_MODE (from); fmode != VOIDmode;
437390075Sobrien       fmode = GET_MODE_WIDER_MODE (fmode))
437490075Sobrien    for (imode = GET_MODE (to); imode != VOIDmode;
437590075Sobrien	 imode = GET_MODE_WIDER_MODE (imode))
437618334Speter      {
437718334Speter	int doing_unsigned = unsignedp;
437818334Speter
437918334Speter	icode = can_fix_p (imode, fmode, unsignedp, &must_trunc);
438018334Speter	if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp)
438118334Speter	  icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0;
438218334Speter
438318334Speter	if (icode != CODE_FOR_nothing)
438418334Speter	  {
438518334Speter	    to = protect_from_queue (to, 1);
438618334Speter	    from = protect_from_queue (from, 0);
438718334Speter
438818334Speter	    if (fmode != GET_MODE (from))
438918334Speter	      from = convert_to_mode (fmode, from, 0);
439018334Speter
439118334Speter	    if (must_trunc)
439218334Speter	      from = ftruncify (from);
439318334Speter
439418334Speter	    if (imode != GET_MODE (to))
439518334Speter	      target = gen_reg_rtx (imode);
439618334Speter
439718334Speter	    emit_unop_insn (icode, target, from,
439818334Speter			    doing_unsigned ? UNSIGNED_FIX : FIX);
439918334Speter	    if (target != to)
440018334Speter	      convert_move (to, target, unsignedp);
440118334Speter	    return;
440218334Speter	  }
440318334Speter      }
440418334Speter
440518334Speter#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
440618334Speter  /* For an unsigned conversion, there is one more way to do it.
440718334Speter     If we have a signed conversion, we generate code that compares
440818334Speter     the real value to the largest representable positive number.  If if
440918334Speter     is smaller, the conversion is done normally.  Otherwise, subtract
441018334Speter     one plus the highest signed number, convert, and add it back.
441118334Speter
441218334Speter     We only need to check all real modes, since we know we didn't find
441318334Speter     anything with a wider integer mode.  */
441418334Speter
441518334Speter  if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
441618334Speter    for (fmode = GET_MODE (from); fmode != VOIDmode;
441718334Speter	 fmode = GET_MODE_WIDER_MODE (fmode))
441818334Speter      /* Make sure we won't lose significant bits doing this.  */
441918334Speter      if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to))
442018334Speter	  && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
442118334Speter					    &must_trunc))
442218334Speter	{
442318334Speter	  int bitsize;
442418334Speter	  REAL_VALUE_TYPE offset;
442518334Speter	  rtx limit, lab1, lab2, insn;
442618334Speter
442718334Speter	  bitsize = GET_MODE_BITSIZE (GET_MODE (to));
442818334Speter	  offset = REAL_VALUE_LDEXP (dconst1, bitsize - 1);
442918334Speter	  limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
443018334Speter	  lab1 = gen_label_rtx ();
443118334Speter	  lab2 = gen_label_rtx ();
443218334Speter
443318334Speter	  emit_queue ();
443418334Speter	  to = protect_from_queue (to, 1);
443518334Speter	  from = protect_from_queue (from, 0);
443618334Speter
443718334Speter	  if (flag_force_mem)
443818334Speter	    from = force_not_mem (from);
443918334Speter
444018334Speter	  if (fmode != GET_MODE (from))
444118334Speter	    from = convert_to_mode (fmode, from, 0);
444218334Speter
444318334Speter	  /* See if we need to do the subtraction.  */
444418334Speter	  do_pending_stack_adjust ();
444552284Sobrien	  emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
444690075Sobrien				   0, lab1);
444718334Speter
444818334Speter	  /* If not, do the signed "fix" and branch around fixup code.  */
444918334Speter	  expand_fix (to, from, 0);
445018334Speter	  emit_jump_insn (gen_jump (lab2));
445118334Speter	  emit_barrier ();
445218334Speter
445318334Speter	  /* Otherwise, subtract 2**(N-1), convert to signed number,
445418334Speter	     then add 2**(N-1).  Do the addition using XOR since this
445518334Speter	     will often generate better code.  */
445618334Speter	  emit_label (lab1);
445718334Speter	  target = expand_binop (GET_MODE (from), sub_optab, from, limit,
445818334Speter				 NULL_RTX, 0, OPTAB_LIB_WIDEN);
445918334Speter	  expand_fix (to, target, 0);
446018334Speter	  target = expand_binop (GET_MODE (to), xor_optab, to,
446190075Sobrien				 GEN_INT (trunc_int_for_mode
446290075Sobrien					  ((HOST_WIDE_INT) 1 << (bitsize - 1),
446390075Sobrien					   GET_MODE (to))),
446418334Speter				 to, 1, OPTAB_LIB_WIDEN);
446518334Speter
446618334Speter	  if (target != to)
446718334Speter	    emit_move_insn (to, target);
446818334Speter
446918334Speter	  emit_label (lab2);
447018334Speter
447150397Sobrien	  if (mov_optab->handlers[(int) GET_MODE (to)].insn_code
447250397Sobrien	      != CODE_FOR_nothing)
447350397Sobrien	    {
447450397Sobrien	      /* Make a place for a REG_NOTE and add it.  */
447550397Sobrien	      insn = emit_move_insn (to, to);
447652284Sobrien	      set_unique_reg_note (insn,
447752284Sobrien	                           REG_EQUAL,
447852284Sobrien				   gen_rtx_fmt_e (UNSIGNED_FIX,
447952284Sobrien						  GET_MODE (to),
448052284Sobrien						  copy_rtx (from)));
448150397Sobrien	    }
448290075Sobrien
448318334Speter	  return;
448418334Speter	}
448518334Speter#endif
448618334Speter
448718334Speter  /* We can't do it with an insn, so use a library call.  But first ensure
448818334Speter     that the mode of TO is at least as wide as SImode, since those are the
448918334Speter     only library calls we know about.  */
449018334Speter
449118334Speter  if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
449218334Speter    {
449318334Speter      target = gen_reg_rtx (SImode);
449418334Speter
449518334Speter      expand_fix (target, from, unsignedp);
449618334Speter    }
449718334Speter  else if (GET_MODE (from) == SFmode)
449818334Speter    {
449918334Speter      if (GET_MODE (to) == SImode)
450018334Speter	libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc;
450118334Speter      else if (GET_MODE (to) == DImode)
450218334Speter	libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc;
450318334Speter      else if (GET_MODE (to) == TImode)
450418334Speter	libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc;
450518334Speter      else
450618334Speter	abort ();
450718334Speter    }
450818334Speter  else if (GET_MODE (from) == DFmode)
450918334Speter    {
451018334Speter      if (GET_MODE (to) == SImode)
451118334Speter	libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc;
451218334Speter      else if (GET_MODE (to) == DImode)
451318334Speter	libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc;
451418334Speter      else if (GET_MODE (to) == TImode)
451518334Speter	libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc;
451618334Speter      else
451718334Speter	abort ();
451818334Speter    }
451918334Speter  else if (GET_MODE (from) == XFmode)
452018334Speter    {
452118334Speter      if (GET_MODE (to) == SImode)
452218334Speter	libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc;
452318334Speter      else if (GET_MODE (to) == DImode)
452418334Speter	libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc;
452518334Speter      else if (GET_MODE (to) == TImode)
452618334Speter	libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc;
452718334Speter      else
452818334Speter	abort ();
452918334Speter    }
453018334Speter  else if (GET_MODE (from) == TFmode)
453118334Speter    {
453218334Speter      if (GET_MODE (to) == SImode)
453318334Speter	libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc;
453418334Speter      else if (GET_MODE (to) == DImode)
453518334Speter	libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc;
453618334Speter      else if (GET_MODE (to) == TImode)
453718334Speter	libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc;
453818334Speter      else
453918334Speter	abort ();
454018334Speter    }
454118334Speter  else
454218334Speter    abort ();
454318334Speter
454418334Speter  if (libfcn)
454518334Speter    {
454618334Speter      rtx insns;
454718334Speter      rtx value;
454818334Speter
454918334Speter      to = protect_from_queue (to, 1);
455018334Speter      from = protect_from_queue (from, 0);
455118334Speter
455218334Speter      if (flag_force_mem)
455318334Speter	from = force_not_mem (from);
455418334Speter
455518334Speter      start_sequence ();
455618334Speter
455790075Sobrien      value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
455890075Sobrien				       GET_MODE (to), 1, from,
455990075Sobrien				       GET_MODE (from));
456018334Speter      insns = get_insns ();
456118334Speter      end_sequence ();
456218334Speter
456318334Speter      emit_libcall_block (insns, target, value,
456450397Sobrien			  gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
456550397Sobrien					 GET_MODE (to), from));
456618334Speter    }
456718334Speter
456850397Sobrien  if (target != to)
456950397Sobrien    {
457050397Sobrien      if (GET_MODE (to) == GET_MODE (target))
457150397Sobrien        emit_move_insn (to, target);
457250397Sobrien      else
457350397Sobrien        convert_move (to, target, 0);
457450397Sobrien    }
457518334Speter}
457618334Speter
457790075Sobrien/* Report whether we have an instruction to perform the operation
457890075Sobrien   specified by CODE on operands of mode MODE.  */
457990075Sobrienint
458090075Sobrienhave_insn_for (code, mode)
458118334Speter     enum rtx_code code;
458290075Sobrien     enum machine_mode mode;
458318334Speter{
458490075Sobrien  return (code_to_optab[(int) code] != 0
458590075Sobrien	  && (code_to_optab[(int) code]->handlers[(int) mode].insn_code
458690075Sobrien	      != CODE_FOR_nothing));
458790075Sobrien}
458890075Sobrien
458990075Sobrien/* Create a blank optab.  */
459090075Sobrienstatic optab
459190075Sobriennew_optab ()
459290075Sobrien{
459318334Speter  int i;
459418334Speter  optab op = (optab) xmalloc (sizeof (struct optab));
459518334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
459618334Speter    {
459718334Speter      op->handlers[i].insn_code = CODE_FOR_nothing;
459818334Speter      op->handlers[i].libfunc = 0;
459918334Speter    }
460018334Speter
460190075Sobrien  return op;
460290075Sobrien}
460318334Speter
460490075Sobrien/* Same, but fill in its code as CODE, and write it into the
460590075Sobrien   code_to_optab table.  */
460690075Sobrienstatic inline optab
460790075Sobrieninit_optab (code)
460890075Sobrien     enum rtx_code code;
460990075Sobrien{
461090075Sobrien  optab op = new_optab ();
461190075Sobrien  op->code = code;
461290075Sobrien  code_to_optab[(int) code] = op;
461318334Speter  return op;
461418334Speter}
461518334Speter
461690075Sobrien/* Same, but fill in its code as CODE, and do _not_ write it into
461790075Sobrien   the code_to_optab table.  */
461890075Sobrienstatic inline optab
461990075Sobrieninit_optabv (code)
462090075Sobrien     enum rtx_code code;
462190075Sobrien{
462290075Sobrien  optab op = new_optab ();
462390075Sobrien  op->code = code;
462490075Sobrien  return op;
462590075Sobrien}
462690075Sobrien
462718334Speter/* Initialize the libfunc fields of an entire group of entries in some
462818334Speter   optab.  Each entry is set equal to a string consisting of a leading
462918334Speter   pair of underscores followed by a generic operation name followed by
463018334Speter   a mode name (downshifted to lower case) followed by a single character
463118334Speter   representing the number of operands for the given operation (which is
463218334Speter   usually one of the characters '2', '3', or '4').
463318334Speter
463418334Speter   OPTABLE is the table in which libfunc fields are to be initialized.
463518334Speter   FIRST_MODE is the first machine mode index in the given optab to
463618334Speter     initialize.
463718334Speter   LAST_MODE is the last machine mode index in the given optab to
463818334Speter     initialize.
463918334Speter   OPNAME is the generic (string) name of the operation.
464018334Speter   SUFFIX is the character which specifies the number of operands for
464118334Speter     the given generic operation.
464218334Speter*/
464318334Speter
464418334Speterstatic void
464518334Speterinit_libfuncs (optable, first_mode, last_mode, opname, suffix)
464690075Sobrien    optab optable;
464790075Sobrien    int first_mode;
464890075Sobrien    int last_mode;
464990075Sobrien    const char *opname;
465090075Sobrien    int suffix;
465118334Speter{
465290075Sobrien  int mode;
465390075Sobrien  unsigned opname_len = strlen (opname);
465418334Speter
465518334Speter  for (mode = first_mode; (int) mode <= (int) last_mode;
465618334Speter       mode = (enum machine_mode) ((int) mode + 1))
465718334Speter    {
465890075Sobrien      const char *mname = GET_MODE_NAME(mode);
465990075Sobrien      unsigned mname_len = strlen (mname);
466090075Sobrien      char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
466190075Sobrien      char *p;
466290075Sobrien      const char *q;
466318334Speter
466418334Speter      p = libfunc_name;
466518334Speter      *p++ = '_';
466618334Speter      *p++ = '_';
466718334Speter      for (q = opname; *q; )
466818334Speter	*p++ = *q++;
466918334Speter      for (q = mname; *q; q++)
467090075Sobrien	*p++ = TOLOWER (*q);
467118334Speter      *p++ = suffix;
467290075Sobrien      *p = '\0';
467390075Sobrien
467418334Speter      optable->handlers[(int) mode].libfunc
467590075Sobrien	= gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
467690075Sobrien						       p - libfunc_name));
467718334Speter    }
467818334Speter}
467918334Speter
468018334Speter/* Initialize the libfunc fields of an entire group of entries in some
468118334Speter   optab which correspond to all integer mode operations.  The parameters
468218334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
468318334Speter   routine.  (See above).  */
468418334Speter
468518334Speterstatic void
468618334Speterinit_integral_libfuncs (optable, opname, suffix)
468790075Sobrien    optab optable;
468890075Sobrien    const char *opname;
468990075Sobrien    int suffix;
469018334Speter{
469118334Speter  init_libfuncs (optable, SImode, TImode, opname, suffix);
469218334Speter}
469318334Speter
469418334Speter/* Initialize the libfunc fields of an entire group of entries in some
469518334Speter   optab which correspond to all real mode operations.  The parameters
469618334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
469718334Speter   routine.  (See above).  */
469818334Speter
469918334Speterstatic void
470018334Speterinit_floating_libfuncs (optable, opname, suffix)
470190075Sobrien    optab optable;
470290075Sobrien    const char *opname;
470390075Sobrien    int suffix;
470418334Speter{
470518334Speter  init_libfuncs (optable, SFmode, TFmode, opname, suffix);
470618334Speter}
470718334Speter
470890075Sobrienrtx
470990075Sobrieninit_one_libfunc (name)
471090075Sobrien     const char *name;
471190075Sobrien{
471290075Sobrien  /* Create a FUNCTION_DECL that can be passed to ENCODE_SECTION_INFO.  */
471390075Sobrien  /* ??? We don't have any type information except for this is
471490075Sobrien     a function.  Pretend this is "int foo()".  */
471590075Sobrien  tree decl = build_decl (FUNCTION_DECL, get_identifier (name),
471690075Sobrien			  build_function_type (integer_type_node, NULL_TREE));
471790075Sobrien  DECL_ARTIFICIAL (decl) = 1;
471890075Sobrien  DECL_EXTERNAL (decl) = 1;
471990075Sobrien  TREE_PUBLIC (decl) = 1;
472018334Speter
472190075Sobrien  /* Return the symbol_ref from the mem rtx.  */
472290075Sobrien  return XEXP (DECL_RTL (decl), 0);
472390075Sobrien}
472490075Sobrien
472590075Sobrien/* Mark ARG (which is really an OPTAB *) for GC.  */
472690075Sobrien
472790075Sobrienvoid
472890075Sobrienmark_optab (arg)
472990075Sobrien     void *arg;
473090075Sobrien{
473190075Sobrien  optab o = *(optab *) arg;
473290075Sobrien  int i;
473390075Sobrien
473490075Sobrien  for (i = 0; i < NUM_MACHINE_MODES; ++i)
473590075Sobrien    ggc_mark_rtx (o->handlers[i].libfunc);
473690075Sobrien}
473790075Sobrien
473818334Speter/* Call this once to initialize the contents of the optabs
473918334Speter   appropriately for the current target machine.  */
474018334Speter
474118334Spetervoid
474218334Speterinit_optabs ()
474318334Speter{
474490075Sobrien  unsigned int i, j, k;
474550397Sobrien
474618334Speter  /* Start by initializing all tables to contain CODE_FOR_nothing.  */
474718334Speter
474890075Sobrien  for (i = 0; i < ARRAY_SIZE (fixtab); i++)
474990075Sobrien    for (j = 0; j < ARRAY_SIZE (fixtab[0]); j++)
475090075Sobrien      for (k = 0; k < ARRAY_SIZE (fixtab[0][0]); k++)
475190075Sobrien	fixtab[i][j][k] = CODE_FOR_nothing;
475218334Speter
475390075Sobrien  for (i = 0; i < ARRAY_SIZE (fixtrunctab); i++)
475490075Sobrien    for (j = 0; j < ARRAY_SIZE (fixtrunctab[0]); j++)
475590075Sobrien      for (k = 0; k < ARRAY_SIZE (fixtrunctab[0][0]); k++)
475690075Sobrien	fixtrunctab[i][j][k] = CODE_FOR_nothing;
475718334Speter
475890075Sobrien  for (i = 0; i < ARRAY_SIZE (floattab); i++)
475990075Sobrien    for (j = 0; j < ARRAY_SIZE (floattab[0]); j++)
476090075Sobrien      for (k = 0; k < ARRAY_SIZE (floattab[0][0]); k++)
476190075Sobrien	floattab[i][j][k] = CODE_FOR_nothing;
476218334Speter
476390075Sobrien  for (i = 0; i < ARRAY_SIZE (extendtab); i++)
476490075Sobrien    for (j = 0; j < ARRAY_SIZE (extendtab[0]); j++)
476590075Sobrien      for (k = 0; k < ARRAY_SIZE (extendtab[0][0]); k++)
476690075Sobrien	extendtab[i][j][k] = CODE_FOR_nothing;
476718334Speter
476818334Speter  for (i = 0; i < NUM_RTX_CODE; i++)
476918334Speter    setcc_gen_code[i] = CODE_FOR_nothing;
477018334Speter
477118334Speter#ifdef HAVE_conditional_move
477218334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
477318334Speter    movcc_gen_code[i] = CODE_FOR_nothing;
477418334Speter#endif
477518334Speter
477618334Speter  add_optab = init_optab (PLUS);
477790075Sobrien  addv_optab = init_optabv (PLUS);
477818334Speter  sub_optab = init_optab (MINUS);
477990075Sobrien  subv_optab = init_optabv (MINUS);
478018334Speter  smul_optab = init_optab (MULT);
478190075Sobrien  smulv_optab = init_optabv (MULT);
478218334Speter  smul_highpart_optab = init_optab (UNKNOWN);
478318334Speter  umul_highpart_optab = init_optab (UNKNOWN);
478418334Speter  smul_widen_optab = init_optab (UNKNOWN);
478518334Speter  umul_widen_optab = init_optab (UNKNOWN);
478618334Speter  sdiv_optab = init_optab (DIV);
478790075Sobrien  sdivv_optab = init_optabv (DIV);
478818334Speter  sdivmod_optab = init_optab (UNKNOWN);
478918334Speter  udiv_optab = init_optab (UDIV);
479018334Speter  udivmod_optab = init_optab (UNKNOWN);
479118334Speter  smod_optab = init_optab (MOD);
479218334Speter  umod_optab = init_optab (UMOD);
479318334Speter  ftrunc_optab = init_optab (UNKNOWN);
479418334Speter  and_optab = init_optab (AND);
479518334Speter  ior_optab = init_optab (IOR);
479618334Speter  xor_optab = init_optab (XOR);
479718334Speter  ashl_optab = init_optab (ASHIFT);
479818334Speter  ashr_optab = init_optab (ASHIFTRT);
479918334Speter  lshr_optab = init_optab (LSHIFTRT);
480018334Speter  rotl_optab = init_optab (ROTATE);
480118334Speter  rotr_optab = init_optab (ROTATERT);
480218334Speter  smin_optab = init_optab (SMIN);
480318334Speter  smax_optab = init_optab (SMAX);
480418334Speter  umin_optab = init_optab (UMIN);
480518334Speter  umax_optab = init_optab (UMAX);
480690075Sobrien
480790075Sobrien  /* These three have codes assigned exclusively for the sake of
480890075Sobrien     have_insn_for.  */
480990075Sobrien  mov_optab = init_optab (SET);
481090075Sobrien  movstrict_optab = init_optab (STRICT_LOW_PART);
481190075Sobrien  cmp_optab = init_optab (COMPARE);
481290075Sobrien
481318334Speter  ucmp_optab = init_optab (UNKNOWN);
481418334Speter  tst_optab = init_optab (UNKNOWN);
481518334Speter  neg_optab = init_optab (NEG);
481690075Sobrien  negv_optab = init_optabv (NEG);
481718334Speter  abs_optab = init_optab (ABS);
481890075Sobrien  absv_optab = init_optabv (ABS);
481918334Speter  one_cmpl_optab = init_optab (NOT);
482018334Speter  ffs_optab = init_optab (FFS);
482118334Speter  sqrt_optab = init_optab (SQRT);
482218334Speter  sin_optab = init_optab (UNKNOWN);
482318334Speter  cos_optab = init_optab (UNKNOWN);
482418334Speter  strlen_optab = init_optab (UNKNOWN);
482590075Sobrien  cbranch_optab = init_optab (UNKNOWN);
482690075Sobrien  cmov_optab = init_optab (UNKNOWN);
482790075Sobrien  cstore_optab = init_optab (UNKNOWN);
482890075Sobrien  push_optab = init_optab (UNKNOWN);
482918334Speter
483018334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
483118334Speter    {
483218334Speter      movstr_optab[i] = CODE_FOR_nothing;
483350397Sobrien      clrstr_optab[i] = CODE_FOR_nothing;
483418334Speter
483518334Speter#ifdef HAVE_SECONDARY_RELOADS
483618334Speter      reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
483718334Speter#endif
483818334Speter    }
483918334Speter
484018334Speter  /* Fill in the optabs with the insns we support.  */
484118334Speter  init_all_optabs ();
484218334Speter
484318334Speter#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
484418334Speter  /* This flag says the same insns that convert to a signed fixnum
484518334Speter     also convert validly to an unsigned one.  */
484618334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
484718334Speter    for (j = 0; j < NUM_MACHINE_MODES; j++)
484818334Speter      fixtrunctab[i][j][1] = fixtrunctab[i][j][0];
484918334Speter#endif
485018334Speter
485118334Speter  /* Initialize the optabs with the names of the library functions.  */
485218334Speter  init_integral_libfuncs (add_optab, "add", '3');
485318334Speter  init_floating_libfuncs (add_optab, "add", '3');
485490075Sobrien  init_integral_libfuncs (addv_optab, "addv", '3');
485590075Sobrien  init_floating_libfuncs (addv_optab, "add", '3');
485618334Speter  init_integral_libfuncs (sub_optab, "sub", '3');
485718334Speter  init_floating_libfuncs (sub_optab, "sub", '3');
485890075Sobrien  init_integral_libfuncs (subv_optab, "subv", '3');
485990075Sobrien  init_floating_libfuncs (subv_optab, "sub", '3');
486018334Speter  init_integral_libfuncs (smul_optab, "mul", '3');
486118334Speter  init_floating_libfuncs (smul_optab, "mul", '3');
486290075Sobrien  init_integral_libfuncs (smulv_optab, "mulv", '3');
486390075Sobrien  init_floating_libfuncs (smulv_optab, "mul", '3');
486418334Speter  init_integral_libfuncs (sdiv_optab, "div", '3');
486590075Sobrien  init_floating_libfuncs (sdiv_optab, "div", '3');
486690075Sobrien  init_integral_libfuncs (sdivv_optab, "divv", '3');
486718334Speter  init_integral_libfuncs (udiv_optab, "udiv", '3');
486818334Speter  init_integral_libfuncs (sdivmod_optab, "divmod", '4');
486918334Speter  init_integral_libfuncs (udivmod_optab, "udivmod", '4');
487018334Speter  init_integral_libfuncs (smod_optab, "mod", '3');
487118334Speter  init_integral_libfuncs (umod_optab, "umod", '3');
487218334Speter  init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
487318334Speter  init_integral_libfuncs (and_optab, "and", '3');
487418334Speter  init_integral_libfuncs (ior_optab, "ior", '3');
487518334Speter  init_integral_libfuncs (xor_optab, "xor", '3');
487618334Speter  init_integral_libfuncs (ashl_optab, "ashl", '3');
487718334Speter  init_integral_libfuncs (ashr_optab, "ashr", '3');
487818334Speter  init_integral_libfuncs (lshr_optab, "lshr", '3');
487918334Speter  init_integral_libfuncs (smin_optab, "min", '3');
488018334Speter  init_floating_libfuncs (smin_optab, "min", '3');
488118334Speter  init_integral_libfuncs (smax_optab, "max", '3');
488218334Speter  init_floating_libfuncs (smax_optab, "max", '3');
488318334Speter  init_integral_libfuncs (umin_optab, "umin", '3');
488418334Speter  init_integral_libfuncs (umax_optab, "umax", '3');
488518334Speter  init_integral_libfuncs (neg_optab, "neg", '2');
488618334Speter  init_floating_libfuncs (neg_optab, "neg", '2');
488790075Sobrien  init_integral_libfuncs (negv_optab, "negv", '2');
488890075Sobrien  init_floating_libfuncs (negv_optab, "neg", '2');
488918334Speter  init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
489018334Speter  init_integral_libfuncs (ffs_optab, "ffs", '2');
489118334Speter
489218334Speter  /* Comparison libcalls for integers MUST come in pairs, signed/unsigned.  */
489318334Speter  init_integral_libfuncs (cmp_optab, "cmp", '2');
489418334Speter  init_integral_libfuncs (ucmp_optab, "ucmp", '2');
489518334Speter  init_floating_libfuncs (cmp_optab, "cmp", '2');
489618334Speter
489718334Speter#ifdef MULSI3_LIBCALL
489818334Speter  smul_optab->handlers[(int) SImode].libfunc
489990075Sobrien    = init_one_libfunc (MULSI3_LIBCALL);
490018334Speter#endif
490118334Speter#ifdef MULDI3_LIBCALL
490218334Speter  smul_optab->handlers[(int) DImode].libfunc
490390075Sobrien    = init_one_libfunc (MULDI3_LIBCALL);
490418334Speter#endif
490518334Speter
490618334Speter#ifdef DIVSI3_LIBCALL
490718334Speter  sdiv_optab->handlers[(int) SImode].libfunc
490890075Sobrien    = init_one_libfunc (DIVSI3_LIBCALL);
490918334Speter#endif
491018334Speter#ifdef DIVDI3_LIBCALL
491118334Speter  sdiv_optab->handlers[(int) DImode].libfunc
491290075Sobrien    = init_one_libfunc (DIVDI3_LIBCALL);
491318334Speter#endif
491418334Speter
491518334Speter#ifdef UDIVSI3_LIBCALL
491618334Speter  udiv_optab->handlers[(int) SImode].libfunc
491790075Sobrien    = init_one_libfunc (UDIVSI3_LIBCALL);
491818334Speter#endif
491918334Speter#ifdef UDIVDI3_LIBCALL
492018334Speter  udiv_optab->handlers[(int) DImode].libfunc
492190075Sobrien    = init_one_libfunc (UDIVDI3_LIBCALL);
492218334Speter#endif
492318334Speter
492418334Speter#ifdef MODSI3_LIBCALL
492518334Speter  smod_optab->handlers[(int) SImode].libfunc
492690075Sobrien    = init_one_libfunc (MODSI3_LIBCALL);
492718334Speter#endif
492818334Speter#ifdef MODDI3_LIBCALL
492918334Speter  smod_optab->handlers[(int) DImode].libfunc
493090075Sobrien    = init_one_libfunc (MODDI3_LIBCALL);
493118334Speter#endif
493218334Speter
493318334Speter#ifdef UMODSI3_LIBCALL
493418334Speter  umod_optab->handlers[(int) SImode].libfunc
493590075Sobrien    = init_one_libfunc (UMODSI3_LIBCALL);
493618334Speter#endif
493718334Speter#ifdef UMODDI3_LIBCALL
493818334Speter  umod_optab->handlers[(int) DImode].libfunc
493990075Sobrien    = init_one_libfunc (UMODDI3_LIBCALL);
494018334Speter#endif
494118334Speter
494218334Speter  /* Use cabs for DC complex abs, since systems generally have cabs.
494318334Speter     Don't define any libcall for SCmode, so that cabs will be used.  */
494418334Speter  abs_optab->handlers[(int) DCmode].libfunc
494590075Sobrien    = init_one_libfunc ("cabs");
494618334Speter
494718334Speter  /* The ffs function operates on `int'.  */
494890075Sobrien  ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
494990075Sobrien    = init_one_libfunc ("ffs");
495018334Speter
495190075Sobrien  extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2");
495290075Sobrien  extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2");
495390075Sobrien  extendsftf2_libfunc = init_one_libfunc ("__extendsftf2");
495490075Sobrien  extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2");
495590075Sobrien  extenddftf2_libfunc = init_one_libfunc ("__extenddftf2");
495618334Speter
495790075Sobrien  truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2");
495890075Sobrien  truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2");
495990075Sobrien  trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2");
496090075Sobrien  truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2");
496190075Sobrien  trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2");
496218334Speter
496396263Sobrien  abort_libfunc = init_one_libfunc ("abort");
496490075Sobrien  memcpy_libfunc = init_one_libfunc ("memcpy");
496590075Sobrien  memmove_libfunc = init_one_libfunc ("memmove");
496690075Sobrien  bcopy_libfunc = init_one_libfunc ("bcopy");
496790075Sobrien  memcmp_libfunc = init_one_libfunc ("memcmp");
496890075Sobrien  bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");
496990075Sobrien  memset_libfunc = init_one_libfunc ("memset");
497090075Sobrien  bzero_libfunc = init_one_libfunc ("bzero");
497118334Speter
497290075Sobrien  unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
497390075Sobrien					    ? "_Unwind_SjLj_Resume"
497490075Sobrien					    : "_Unwind_Resume");
497550397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
497690075Sobrien  setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
497790075Sobrien  longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
497850397Sobrien#else
497990075Sobrien  setjmp_libfunc = init_one_libfunc ("setjmp");
498090075Sobrien  longjmp_libfunc = init_one_libfunc ("longjmp");
498150397Sobrien#endif
498290075Sobrien  unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
498390075Sobrien  unwind_sjlj_unregister_libfunc
498490075Sobrien    = init_one_libfunc ("_Unwind_SjLj_Unregister");
498518334Speter
498690075Sobrien  eqhf2_libfunc = init_one_libfunc ("__eqhf2");
498790075Sobrien  nehf2_libfunc = init_one_libfunc ("__nehf2");
498890075Sobrien  gthf2_libfunc = init_one_libfunc ("__gthf2");
498990075Sobrien  gehf2_libfunc = init_one_libfunc ("__gehf2");
499090075Sobrien  lthf2_libfunc = init_one_libfunc ("__lthf2");
499190075Sobrien  lehf2_libfunc = init_one_libfunc ("__lehf2");
499290075Sobrien  unordhf2_libfunc = init_one_libfunc ("__unordhf2");
499318334Speter
499490075Sobrien  eqsf2_libfunc = init_one_libfunc ("__eqsf2");
499590075Sobrien  nesf2_libfunc = init_one_libfunc ("__nesf2");
499690075Sobrien  gtsf2_libfunc = init_one_libfunc ("__gtsf2");
499790075Sobrien  gesf2_libfunc = init_one_libfunc ("__gesf2");
499890075Sobrien  ltsf2_libfunc = init_one_libfunc ("__ltsf2");
499990075Sobrien  lesf2_libfunc = init_one_libfunc ("__lesf2");
500090075Sobrien  unordsf2_libfunc = init_one_libfunc ("__unordsf2");
500118334Speter
500290075Sobrien  eqdf2_libfunc = init_one_libfunc ("__eqdf2");
500390075Sobrien  nedf2_libfunc = init_one_libfunc ("__nedf2");
500490075Sobrien  gtdf2_libfunc = init_one_libfunc ("__gtdf2");
500590075Sobrien  gedf2_libfunc = init_one_libfunc ("__gedf2");
500690075Sobrien  ltdf2_libfunc = init_one_libfunc ("__ltdf2");
500790075Sobrien  ledf2_libfunc = init_one_libfunc ("__ledf2");
500890075Sobrien  unorddf2_libfunc = init_one_libfunc ("__unorddf2");
500918334Speter
501090075Sobrien  eqxf2_libfunc = init_one_libfunc ("__eqxf2");
501190075Sobrien  nexf2_libfunc = init_one_libfunc ("__nexf2");
501290075Sobrien  gtxf2_libfunc = init_one_libfunc ("__gtxf2");
501390075Sobrien  gexf2_libfunc = init_one_libfunc ("__gexf2");
501490075Sobrien  ltxf2_libfunc = init_one_libfunc ("__ltxf2");
501590075Sobrien  lexf2_libfunc = init_one_libfunc ("__lexf2");
501690075Sobrien  unordxf2_libfunc = init_one_libfunc ("__unordxf2");
501718334Speter
501890075Sobrien  eqtf2_libfunc = init_one_libfunc ("__eqtf2");
501990075Sobrien  netf2_libfunc = init_one_libfunc ("__netf2");
502090075Sobrien  gttf2_libfunc = init_one_libfunc ("__gttf2");
502190075Sobrien  getf2_libfunc = init_one_libfunc ("__getf2");
502290075Sobrien  lttf2_libfunc = init_one_libfunc ("__lttf2");
502390075Sobrien  letf2_libfunc = init_one_libfunc ("__letf2");
502490075Sobrien  unordtf2_libfunc = init_one_libfunc ("__unordtf2");
502518334Speter
502690075Sobrien  floatsisf_libfunc = init_one_libfunc ("__floatsisf");
502790075Sobrien  floatdisf_libfunc = init_one_libfunc ("__floatdisf");
502890075Sobrien  floattisf_libfunc = init_one_libfunc ("__floattisf");
502918334Speter
503090075Sobrien  floatsidf_libfunc = init_one_libfunc ("__floatsidf");
503190075Sobrien  floatdidf_libfunc = init_one_libfunc ("__floatdidf");
503290075Sobrien  floattidf_libfunc = init_one_libfunc ("__floattidf");
503318334Speter
503490075Sobrien  floatsixf_libfunc = init_one_libfunc ("__floatsixf");
503590075Sobrien  floatdixf_libfunc = init_one_libfunc ("__floatdixf");
503690075Sobrien  floattixf_libfunc = init_one_libfunc ("__floattixf");
503718334Speter
503890075Sobrien  floatsitf_libfunc = init_one_libfunc ("__floatsitf");
503990075Sobrien  floatditf_libfunc = init_one_libfunc ("__floatditf");
504090075Sobrien  floattitf_libfunc = init_one_libfunc ("__floattitf");
504118334Speter
504290075Sobrien  fixsfsi_libfunc = init_one_libfunc ("__fixsfsi");
504390075Sobrien  fixsfdi_libfunc = init_one_libfunc ("__fixsfdi");
504490075Sobrien  fixsfti_libfunc = init_one_libfunc ("__fixsfti");
504518334Speter
504690075Sobrien  fixdfsi_libfunc = init_one_libfunc ("__fixdfsi");
504790075Sobrien  fixdfdi_libfunc = init_one_libfunc ("__fixdfdi");
504890075Sobrien  fixdfti_libfunc = init_one_libfunc ("__fixdfti");
504918334Speter
505090075Sobrien  fixxfsi_libfunc = init_one_libfunc ("__fixxfsi");
505190075Sobrien  fixxfdi_libfunc = init_one_libfunc ("__fixxfdi");
505290075Sobrien  fixxfti_libfunc = init_one_libfunc ("__fixxfti");
505318334Speter
505490075Sobrien  fixtfsi_libfunc = init_one_libfunc ("__fixtfsi");
505590075Sobrien  fixtfdi_libfunc = init_one_libfunc ("__fixtfdi");
505690075Sobrien  fixtfti_libfunc = init_one_libfunc ("__fixtfti");
505718334Speter
505890075Sobrien  fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi");
505990075Sobrien  fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi");
506090075Sobrien  fixunssfti_libfunc = init_one_libfunc ("__fixunssfti");
506118334Speter
506290075Sobrien  fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi");
506390075Sobrien  fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi");
506490075Sobrien  fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti");
506518334Speter
506690075Sobrien  fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi");
506790075Sobrien  fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi");
506890075Sobrien  fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti");
506918334Speter
507090075Sobrien  fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi");
507190075Sobrien  fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi");
507290075Sobrien  fixunstfti_libfunc = init_one_libfunc ("__fixunstfti");
507350397Sobrien
507452284Sobrien  /* For function entry/exit instrumentation.  */
507552284Sobrien  profile_function_entry_libfunc
507690075Sobrien    = init_one_libfunc ("__cyg_profile_func_enter");
507752284Sobrien  profile_function_exit_libfunc
507890075Sobrien    = init_one_libfunc ("__cyg_profile_func_exit");
507952284Sobrien
508050397Sobrien#ifdef HAVE_conditional_trap
508150397Sobrien  init_traps ();
508250397Sobrien#endif
508350397Sobrien
508418334Speter#ifdef INIT_TARGET_OPTABS
508518334Speter  /* Allow the target to add more libcalls or rename some, etc.  */
508618334Speter  INIT_TARGET_OPTABS;
508718334Speter#endif
508818334Speter
508990075Sobrien  /* Add these GC roots.  */
509090075Sobrien  ggc_add_root (optab_table, OTI_MAX, sizeof(optab), mark_optab);
509190075Sobrien  ggc_add_rtx_root (libfunc_table, LTI_MAX);
509218334Speter}
509350397Sobrien
509450397Sobrien#ifdef HAVE_conditional_trap
509550397Sobrien/* The insn generating function can not take an rtx_code argument.
509650397Sobrien   TRAP_RTX is used as an rtx argument.  Its code is replaced with
509750397Sobrien   the code to be used in the trap insn and all other fields are
509890075Sobrien   ignored.  */
509950397Sobrienstatic rtx trap_rtx;
510050397Sobrien
510150397Sobrienstatic void
510250397Sobrieninit_traps ()
510350397Sobrien{
510450397Sobrien  if (HAVE_conditional_trap)
510590075Sobrien    {
510690075Sobrien      trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
510790075Sobrien      ggc_add_rtx_root (&trap_rtx, 1);
510890075Sobrien    }
510950397Sobrien}
511050397Sobrien#endif
511150397Sobrien
511250397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
511350397Sobrien   CODE.  Return 0 on failure.  */
511450397Sobrien
511550397Sobrienrtx
511650397Sobriengen_cond_trap (code, op1, op2, tcode)
511752284Sobrien  enum rtx_code code ATTRIBUTE_UNUSED;
511852284Sobrien  rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED;
511950397Sobrien{
512050397Sobrien  enum machine_mode mode = GET_MODE (op1);
512150397Sobrien
512250397Sobrien  if (mode == VOIDmode)
512350397Sobrien    return 0;
512450397Sobrien
512550397Sobrien#ifdef HAVE_conditional_trap
512650397Sobrien  if (HAVE_conditional_trap
512750397Sobrien      && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
512850397Sobrien    {
512950397Sobrien      rtx insn;
513090075Sobrien      start_sequence();
513150397Sobrien      emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
513250397Sobrien      PUT_CODE (trap_rtx, code);
513350397Sobrien      insn = gen_conditional_trap (trap_rtx, tcode);
513450397Sobrien      if (insn)
513590075Sobrien	{
513690075Sobrien	  emit_insn (insn);
513790075Sobrien	  insn = gen_sequence ();
513890075Sobrien	}
513990075Sobrien      end_sequence();
514090075Sobrien      return insn;
514150397Sobrien    }
514250397Sobrien#endif
514350397Sobrien
514450397Sobrien  return 0;
514550397Sobrien}
5146