optabs.c revision 119256
118334Speter/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
290075Sobrien   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3117395Skan   1999, 2000, 2001, 2002, 2003 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"
43110611Skan#include "basic-block.h"
4418334Speter
4518334Speter/* Each optab contains info on how this target machine
4618334Speter   can perform a particular operation
4718334Speter   for all sizes and kinds of operands.
4818334Speter
4918334Speter   The operation to be performed is often specified
5018334Speter   by passing one of these optabs as an argument.
5118334Speter
5218334Speter   See expr.h for documentation of these optabs.  */
5318334Speter
5490075Sobrienoptab optab_table[OTI_MAX];
5518334Speter
5690075Sobrienrtx libfunc_table[LTI_MAX];
5718334Speter
5818334Speter/* Tables of patterns for extending one integer mode to another.  */
5918334Speterenum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
6018334Speter
6150397Sobrien/* Tables of patterns for converting between fixed and floating point.  */
6218334Speterenum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
6318334Speterenum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
6418334Speterenum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
6518334Speter
6618334Speter/* Contains the optab used for each rtx code.  */
6718334Speteroptab code_to_optab[NUM_RTX_CODE + 1];
6818334Speter
6918334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
7018334Speter   gives the gen_function to make a branch to test that condition.  */
7118334Speter
7218334Speterrtxfun bcc_gen_fctn[NUM_RTX_CODE];
7318334Speter
7418334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
7518334Speter   gives the insn code to make a store-condition insn
7618334Speter   to test that condition.  */
7718334Speter
7818334Speterenum insn_code setcc_gen_code[NUM_RTX_CODE];
7918334Speter
8018334Speter#ifdef HAVE_conditional_move
8118334Speter/* Indexed by the machine mode, gives the insn code to make a conditional
8218334Speter   move insn.  This is not indexed by the rtx-code like bcc_gen_fctn and
8318334Speter   setcc_gen_code to cut down on the number of named patterns.  Consider a day
8418334Speter   when a lot more rtx codes are conditional (eg: for the ARM).  */
8518334Speter
8618334Speterenum insn_code movcc_gen_code[NUM_MACHINE_MODES];
8718334Speter#endif
8818334Speter
89117395Skan/* The insn generating function can not take an rtx_code argument.
90117395Skan   TRAP_RTX is used as an rtx argument.  Its code is replaced with
91117395Skan   the code to be used in the trap insn and all other fields are ignored.  */
92117395Skanstatic GTY(()) rtx trap_rtx;
93117395Skan
9490075Sobrienstatic int add_equal_note	PARAMS ((rtx, rtx, enum rtx_code, rtx, rtx));
9590075Sobrienstatic rtx widen_operand	PARAMS ((rtx, enum machine_mode,
9618334Speter				       enum machine_mode, int, int));
9790075Sobrienstatic int expand_cmplxdiv_straight PARAMS ((rtx, rtx, rtx, rtx,
9852284Sobrien					   rtx, rtx, enum machine_mode,
9952284Sobrien					   int, enum optab_methods,
10052284Sobrien					   enum mode_class, optab));
10190075Sobrienstatic int expand_cmplxdiv_wide PARAMS ((rtx, rtx, rtx, rtx,
10252284Sobrien				       rtx, rtx, enum machine_mode,
10352284Sobrien				       int, enum optab_methods,
10452284Sobrien				       enum mode_class, optab));
10590075Sobrienstatic void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx,
10690075Sobrien				      enum machine_mode *, int *,
10790075Sobrien				      enum can_compare_purpose));
10890075Sobrienstatic enum insn_code can_fix_p	PARAMS ((enum machine_mode, enum machine_mode,
10918334Speter				       int, int *));
11090075Sobrienstatic enum insn_code can_float_p PARAMS ((enum machine_mode,
11190075Sobrien					   enum machine_mode,
11290075Sobrien					   int));
11390075Sobrienstatic rtx ftruncify	PARAMS ((rtx));
11490075Sobrienstatic optab new_optab	PARAMS ((void));
11590075Sobrienstatic inline optab init_optab	PARAMS ((enum rtx_code));
11690075Sobrienstatic inline optab init_optabv	PARAMS ((enum rtx_code));
11790075Sobrienstatic void init_libfuncs PARAMS ((optab, int, int, const char *, int));
11890075Sobrienstatic void init_integral_libfuncs PARAMS ((optab, const char *, int));
11990075Sobrienstatic void init_floating_libfuncs PARAMS ((optab, const char *, int));
12090075Sobrienstatic void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode,
12190075Sobrien					    enum rtx_code, int, rtx));
12290075Sobrienstatic void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *,
12390075Sobrien					 enum machine_mode *, int *));
124117395Skanstatic rtx expand_vector_binop PARAMS ((enum machine_mode, optab,
125117395Skan					rtx, rtx, rtx, int,
126117395Skan					enum optab_methods));
127117395Skanstatic rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx,
128117395Skan				       int));
129117395Skan
130117395Skan#ifndef HAVE_conditional_trap
131117395Skan#define HAVE_conditional_trap 0
132117395Skan#define gen_conditional_trap(a,b) (abort (), NULL_RTX)
133117395Skan#endif
13418334Speter
135117395Skan/* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
13618334Speter   the result of operation CODE applied to OP0 (and OP1 if it is a binary
13718334Speter   operation).
13818334Speter
13918334Speter   If the last insn does not set TARGET, don't do anything, but return 1.
14018334Speter
14118334Speter   If a previous insn sets TARGET and TARGET is one of OP0 or OP1,
14218334Speter   don't add the REG_EQUAL note but return 0.  Our caller can then try
14318334Speter   again, ensuring that TARGET is not one of the operands.  */
14418334Speter
14518334Speterstatic int
146117395Skanadd_equal_note (insns, target, code, op0, op1)
147117395Skan     rtx insns;
14818334Speter     rtx target;
14918334Speter     enum rtx_code code;
15018334Speter     rtx op0, op1;
15118334Speter{
152117395Skan  rtx last_insn, insn, set;
15318334Speter  rtx note;
15418334Speter
155117395Skan  if (! insns
156117395Skan      || ! INSN_P (insns)
157117395Skan      || NEXT_INSN (insns) == NULL_RTX)
158117395Skan    abort ();
159117395Skan
160117395Skan  if (GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2'
161117395Skan      && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<')
16218334Speter    return 1;
16318334Speter
164117395Skan  if (GET_CODE (target) == ZERO_EXTRACT)
165117395Skan    return 1;
166117395Skan
167117395Skan  for (last_insn = insns;
168117395Skan       NEXT_INSN (last_insn) != NULL_RTX;
169117395Skan       last_insn = NEXT_INSN (last_insn))
170117395Skan    ;
171117395Skan
172117395Skan  set = single_set (last_insn);
173117395Skan  if (set == NULL_RTX)
174117395Skan    return 1;
175117395Skan
176117395Skan  if (! rtx_equal_p (SET_DEST (set), target)
177117395Skan      /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the
178117395Skan	 SUBREG.  */
179117395Skan      && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
180117395Skan	  || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
181117395Skan			    target)))
182117395Skan    return 1;
183117395Skan
18418334Speter  /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET
18518334Speter     besides the last insn.  */
18618334Speter  if (reg_overlap_mentioned_p (target, op0)
18718334Speter      || (op1 && reg_overlap_mentioned_p (target, op1)))
188117395Skan    {
189117395Skan      insn = PREV_INSN (last_insn);
190117395Skan      while (insn != NULL_RTX)
191117395Skan	{
192117395Skan	  if (reg_set_p (target, insn))
193117395Skan	    return 0;
19418334Speter
195117395Skan	  insn = PREV_INSN (insn);
196117395Skan	}
197117395Skan    }
198117395Skan
19918334Speter  if (GET_RTX_CLASS (code) == '1')
20050397Sobrien    note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0));
20118334Speter  else
20250397Sobrien    note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
20318334Speter
204117395Skan  set_unique_reg_note (last_insn, REG_EQUAL, note);
20518334Speter
20618334Speter  return 1;
20718334Speter}
20818334Speter
20918334Speter/* Widen OP to MODE and return the rtx for the widened operand.  UNSIGNEDP
21018334Speter   says whether OP is signed or unsigned.  NO_EXTEND is nonzero if we need
21118334Speter   not actually do a sign-extend or zero-extend, but can leave the
21218334Speter   higher-order bits of the result rtx undefined, for example, in the case
21318334Speter   of logical operations, but not right shifts.  */
21418334Speter
21518334Speterstatic rtx
21618334Speterwiden_operand (op, mode, oldmode, unsignedp, no_extend)
21718334Speter     rtx op;
21818334Speter     enum machine_mode mode, oldmode;
21918334Speter     int unsignedp;
22018334Speter     int no_extend;
22118334Speter{
22218334Speter  rtx result;
22318334Speter
22496263Sobrien  /* If we don't have to extend and this is a constant, return it.  */
22596263Sobrien  if (no_extend && GET_MODE (op) == VOIDmode)
22696263Sobrien    return op;
22796263Sobrien
22896263Sobrien  /* If we must extend do so.  If OP is a SUBREG for a promoted object, also
22996263Sobrien     extend since it will be more efficient to do so unless the signedness of
23096263Sobrien     a promoted object differs from our extension.  */
23118334Speter  if (! no_extend
23296263Sobrien      || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)
23396263Sobrien	  && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp))
23418334Speter    return convert_modes (mode, oldmode, op, unsignedp);
23518334Speter
23618334Speter  /* If MODE is no wider than a single word, we return a paradoxical
23718334Speter     SUBREG.  */
23818334Speter  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
23950397Sobrien    return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0);
24018334Speter
24118334Speter  /* Otherwise, get an object of MODE, clobber it, and set the low-order
24218334Speter     part to OP.  */
24318334Speter
24418334Speter  result = gen_reg_rtx (mode);
24550397Sobrien  emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
24618334Speter  emit_move_insn (gen_lowpart (GET_MODE (op), result), op);
24718334Speter  return result;
24818334Speter}
24918334Speter
25052284Sobrien/* Generate code to perform a straightforward complex divide.  */
25152284Sobrien
25252284Sobrienstatic int
25352284Sobrienexpand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
25452284Sobrien			  unsignedp, methods, class, binoptab)
255117395Skan     rtx real0, real1, imag0, imag1, realr, imagr;
256117395Skan     enum machine_mode submode;
257117395Skan     int unsignedp;
258117395Skan     enum optab_methods methods;
259117395Skan     enum mode_class class;
260117395Skan     optab binoptab;
26152284Sobrien{
26252284Sobrien  rtx divisor;
26352284Sobrien  rtx real_t, imag_t;
26452284Sobrien  rtx temp1, temp2;
26552284Sobrien  rtx res;
26690075Sobrien  optab this_add_optab = add_optab;
26790075Sobrien  optab this_sub_optab = sub_optab;
26890075Sobrien  optab this_neg_optab = neg_optab;
26990075Sobrien  optab this_mul_optab = smul_optab;
27052284Sobrien
27190075Sobrien  if (binoptab == sdivv_optab)
27290075Sobrien    {
27390075Sobrien      this_add_optab = addv_optab;
27490075Sobrien      this_sub_optab = subv_optab;
27590075Sobrien      this_neg_optab = negv_optab;
27690075Sobrien      this_mul_optab = smulv_optab;
27790075Sobrien    }
27890075Sobrien
27952284Sobrien  /* Don't fetch these from memory more than once.  */
28052284Sobrien  real0 = force_reg (submode, real0);
28152284Sobrien  real1 = force_reg (submode, real1);
28252284Sobrien
28352284Sobrien  if (imag0 != 0)
28452284Sobrien    imag0 = force_reg (submode, imag0);
28552284Sobrien
28652284Sobrien  imag1 = force_reg (submode, imag1);
28752284Sobrien
28852284Sobrien  /* Divisor: c*c + d*d.  */
28990075Sobrien  temp1 = expand_binop (submode, this_mul_optab, real1, real1,
29052284Sobrien			NULL_RTX, unsignedp, methods);
29152284Sobrien
29290075Sobrien  temp2 = expand_binop (submode, this_mul_optab, imag1, imag1,
29352284Sobrien			NULL_RTX, unsignedp, methods);
29452284Sobrien
29552284Sobrien  if (temp1 == 0 || temp2 == 0)
29652284Sobrien    return 0;
29752284Sobrien
29890075Sobrien  divisor = expand_binop (submode, this_add_optab, temp1, temp2,
29952284Sobrien			  NULL_RTX, unsignedp, methods);
30052284Sobrien  if (divisor == 0)
30152284Sobrien    return 0;
30252284Sobrien
30352284Sobrien  if (imag0 == 0)
30452284Sobrien    {
30552284Sobrien      /* Mathematically, ((a)(c-id))/divisor.  */
30652284Sobrien      /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
30752284Sobrien
30852284Sobrien      /* Calculate the dividend.  */
30990075Sobrien      real_t = expand_binop (submode, this_mul_optab, real0, real1,
31052284Sobrien			     NULL_RTX, unsignedp, methods);
31152284Sobrien
31290075Sobrien      imag_t = expand_binop (submode, this_mul_optab, real0, imag1,
31352284Sobrien			     NULL_RTX, unsignedp, methods);
31452284Sobrien
31552284Sobrien      if (real_t == 0 || imag_t == 0)
31652284Sobrien	return 0;
31752284Sobrien
31890075Sobrien      imag_t = expand_unop (submode, this_neg_optab, imag_t,
31952284Sobrien			    NULL_RTX, unsignedp);
32052284Sobrien    }
32152284Sobrien  else
32252284Sobrien    {
32352284Sobrien      /* Mathematically, ((a+ib)(c-id))/divider.  */
32452284Sobrien      /* Calculate the dividend.  */
32590075Sobrien      temp1 = expand_binop (submode, this_mul_optab, real0, real1,
32652284Sobrien			    NULL_RTX, unsignedp, methods);
32752284Sobrien
32890075Sobrien      temp2 = expand_binop (submode, this_mul_optab, imag0, imag1,
32952284Sobrien			    NULL_RTX, unsignedp, methods);
33052284Sobrien
33152284Sobrien      if (temp1 == 0 || temp2 == 0)
33252284Sobrien	return 0;
33352284Sobrien
33490075Sobrien      real_t = expand_binop (submode, this_add_optab, temp1, temp2,
33552284Sobrien			     NULL_RTX, unsignedp, methods);
33652284Sobrien
33790075Sobrien      temp1 = expand_binop (submode, this_mul_optab, imag0, real1,
33852284Sobrien			    NULL_RTX, unsignedp, methods);
33952284Sobrien
34090075Sobrien      temp2 = expand_binop (submode, this_mul_optab, real0, imag1,
34152284Sobrien			    NULL_RTX, unsignedp, methods);
34252284Sobrien
34352284Sobrien      if (temp1 == 0 || temp2 == 0)
34452284Sobrien	return 0;
34552284Sobrien
34690075Sobrien      imag_t = expand_binop (submode, this_sub_optab, temp1, temp2,
34752284Sobrien			     NULL_RTX, unsignedp, methods);
34852284Sobrien
34952284Sobrien      if (real_t == 0 || imag_t == 0)
35052284Sobrien	return 0;
35152284Sobrien    }
35252284Sobrien
35352284Sobrien  if (class == MODE_COMPLEX_FLOAT)
35452284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
35552284Sobrien			realr, unsignedp, methods);
35652284Sobrien  else
35752284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
35852284Sobrien			 real_t, divisor, realr, unsignedp);
35952284Sobrien
36052284Sobrien  if (res == 0)
36152284Sobrien    return 0;
36252284Sobrien
36352284Sobrien  if (res != realr)
36452284Sobrien    emit_move_insn (realr, res);
36552284Sobrien
36652284Sobrien  if (class == MODE_COMPLEX_FLOAT)
36752284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
36852284Sobrien			imagr, unsignedp, methods);
36952284Sobrien  else
37052284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
37152284Sobrien			 imag_t, divisor, imagr, unsignedp);
37252284Sobrien
37352284Sobrien  if (res == 0)
37452284Sobrien    return 0;
37552284Sobrien
37652284Sobrien  if (res != imagr)
37752284Sobrien    emit_move_insn (imagr, res);
37852284Sobrien
37952284Sobrien  return 1;
38052284Sobrien}
38152284Sobrien
38252284Sobrien/* Generate code to perform a wide-input-range-acceptable complex divide.  */
38352284Sobrien
38452284Sobrienstatic int
38552284Sobrienexpand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
38652284Sobrien		      unsignedp, methods, class, binoptab)
387117395Skan     rtx real0, real1, imag0, imag1, realr, imagr;
388117395Skan     enum machine_mode submode;
389117395Skan     int unsignedp;
390117395Skan     enum optab_methods methods;
391117395Skan     enum mode_class class;
392117395Skan     optab binoptab;
39352284Sobrien{
39452284Sobrien  rtx ratio, divisor;
39552284Sobrien  rtx real_t, imag_t;
39652284Sobrien  rtx temp1, temp2, lab1, lab2;
39752284Sobrien  enum machine_mode mode;
39852284Sobrien  rtx res;
39990075Sobrien  optab this_add_optab = add_optab;
40090075Sobrien  optab this_sub_optab = sub_optab;
40190075Sobrien  optab this_neg_optab = neg_optab;
40290075Sobrien  optab this_mul_optab = smul_optab;
40390075Sobrien
40490075Sobrien  if (binoptab == sdivv_optab)
40590075Sobrien    {
40690075Sobrien      this_add_optab = addv_optab;
40790075Sobrien      this_sub_optab = subv_optab;
40890075Sobrien      this_neg_optab = negv_optab;
40990075Sobrien      this_mul_optab = smulv_optab;
41090075Sobrien    }
41152284Sobrien
41252284Sobrien  /* Don't fetch these from memory more than once.  */
41352284Sobrien  real0 = force_reg (submode, real0);
41452284Sobrien  real1 = force_reg (submode, real1);
41552284Sobrien
41652284Sobrien  if (imag0 != 0)
41752284Sobrien    imag0 = force_reg (submode, imag0);
41852284Sobrien
41952284Sobrien  imag1 = force_reg (submode, imag1);
42052284Sobrien
42152284Sobrien  /* XXX What's an "unsigned" complex number?  */
42252284Sobrien  if (unsignedp)
42352284Sobrien    {
42452284Sobrien      temp1 = real1;
42552284Sobrien      temp2 = imag1;
42652284Sobrien    }
42752284Sobrien  else
42852284Sobrien    {
42990075Sobrien      temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1);
43090075Sobrien      temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1);
43152284Sobrien    }
43252284Sobrien
43352284Sobrien  if (temp1 == 0 || temp2 == 0)
43452284Sobrien    return 0;
43552284Sobrien
43652284Sobrien  mode = GET_MODE (temp1);
43752284Sobrien  lab1 = gen_label_rtx ();
43852284Sobrien  emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX,
43990075Sobrien			   mode, unsignedp, lab1);
44052284Sobrien
44152284Sobrien  /* |c| >= |d|; use ratio d/c to scale dividend and divisor.  */
44252284Sobrien
44352284Sobrien  if (class == MODE_COMPLEX_FLOAT)
44452284Sobrien    ratio = expand_binop (submode, binoptab, imag1, real1,
44552284Sobrien			  NULL_RTX, unsignedp, methods);
44652284Sobrien  else
44752284Sobrien    ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
44852284Sobrien			   imag1, real1, NULL_RTX, unsignedp);
44952284Sobrien
45052284Sobrien  if (ratio == 0)
45152284Sobrien    return 0;
45252284Sobrien
45352284Sobrien  /* Calculate divisor.  */
45452284Sobrien
45590075Sobrien  temp1 = expand_binop (submode, this_mul_optab, imag1, ratio,
45652284Sobrien			NULL_RTX, unsignedp, methods);
45752284Sobrien
45852284Sobrien  if (temp1 == 0)
45952284Sobrien    return 0;
46052284Sobrien
46190075Sobrien  divisor = expand_binop (submode, this_add_optab, temp1, real1,
46252284Sobrien			  NULL_RTX, unsignedp, methods);
46352284Sobrien
46452284Sobrien  if (divisor == 0)
46552284Sobrien    return 0;
46652284Sobrien
46752284Sobrien  /* Calculate dividend.  */
46852284Sobrien
46952284Sobrien  if (imag0 == 0)
47052284Sobrien    {
47152284Sobrien      real_t = real0;
47252284Sobrien
47352284Sobrien      /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)).  */
47452284Sobrien
47590075Sobrien      imag_t = expand_binop (submode, this_mul_optab, real0, ratio,
47652284Sobrien			     NULL_RTX, unsignedp, methods);
47752284Sobrien
47852284Sobrien      if (imag_t == 0)
47952284Sobrien	return 0;
48052284Sobrien
48190075Sobrien      imag_t = expand_unop (submode, this_neg_optab, imag_t,
48252284Sobrien			    NULL_RTX, unsignedp);
48352284Sobrien
48452284Sobrien      if (real_t == 0 || imag_t == 0)
48552284Sobrien	return 0;
48652284Sobrien    }
48752284Sobrien  else
48852284Sobrien    {
48952284Sobrien      /* Compute (a+ib)/(c+id) as
49052284Sobrien	 (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)).  */
49152284Sobrien
49290075Sobrien      temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
49352284Sobrien			    NULL_RTX, unsignedp, methods);
49452284Sobrien
49552284Sobrien      if (temp1 == 0)
49652284Sobrien	return 0;
49752284Sobrien
49890075Sobrien      real_t = expand_binop (submode, this_add_optab, temp1, real0,
49952284Sobrien			     NULL_RTX, unsignedp, methods);
50052284Sobrien
50190075Sobrien      temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
50252284Sobrien			    NULL_RTX, unsignedp, methods);
50352284Sobrien
50452284Sobrien      if (temp1 == 0)
50552284Sobrien	return 0;
50652284Sobrien
50790075Sobrien      imag_t = expand_binop (submode, this_sub_optab, imag0, temp1,
50852284Sobrien			     NULL_RTX, unsignedp, methods);
50952284Sobrien
51052284Sobrien      if (real_t == 0 || imag_t == 0)
51152284Sobrien	return 0;
51252284Sobrien    }
51352284Sobrien
51452284Sobrien  if (class == MODE_COMPLEX_FLOAT)
51552284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
51652284Sobrien			realr, unsignedp, methods);
51752284Sobrien  else
51852284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
51952284Sobrien			 real_t, divisor, realr, unsignedp);
52052284Sobrien
52152284Sobrien  if (res == 0)
52252284Sobrien    return 0;
52352284Sobrien
52452284Sobrien  if (res != realr)
52552284Sobrien    emit_move_insn (realr, res);
52652284Sobrien
52752284Sobrien  if (class == MODE_COMPLEX_FLOAT)
52852284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
52952284Sobrien			imagr, unsignedp, methods);
53052284Sobrien  else
53152284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
53252284Sobrien			 imag_t, divisor, imagr, unsignedp);
53352284Sobrien
53452284Sobrien  if (res == 0)
53552284Sobrien    return 0;
53652284Sobrien
53752284Sobrien  if (res != imagr)
53852284Sobrien    emit_move_insn (imagr, res);
53952284Sobrien
54052284Sobrien  lab2 = gen_label_rtx ();
54152284Sobrien  emit_jump_insn (gen_jump (lab2));
54252284Sobrien  emit_barrier ();
54352284Sobrien
54452284Sobrien  emit_label (lab1);
54552284Sobrien
54652284Sobrien  /* |d| > |c|; use ratio c/d to scale dividend and divisor.  */
54752284Sobrien
54852284Sobrien  if (class == MODE_COMPLEX_FLOAT)
54952284Sobrien    ratio = expand_binop (submode, binoptab, real1, imag1,
55052284Sobrien			  NULL_RTX, unsignedp, methods);
55152284Sobrien  else
55252284Sobrien    ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
55352284Sobrien			   real1, imag1, NULL_RTX, unsignedp);
55452284Sobrien
55552284Sobrien  if (ratio == 0)
55652284Sobrien    return 0;
55752284Sobrien
55852284Sobrien  /* Calculate divisor.  */
55952284Sobrien
56090075Sobrien  temp1 = expand_binop (submode, this_mul_optab, real1, ratio,
56152284Sobrien			NULL_RTX, unsignedp, methods);
56252284Sobrien
56352284Sobrien  if (temp1 == 0)
56452284Sobrien    return 0;
56552284Sobrien
56690075Sobrien  divisor = expand_binop (submode, this_add_optab, temp1, imag1,
56752284Sobrien			  NULL_RTX, unsignedp, methods);
56852284Sobrien
56952284Sobrien  if (divisor == 0)
57052284Sobrien    return 0;
57152284Sobrien
57252284Sobrien  /* Calculate dividend.  */
57352284Sobrien
57452284Sobrien  if (imag0 == 0)
57552284Sobrien    {
57652284Sobrien      /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
57752284Sobrien
57890075Sobrien      real_t = expand_binop (submode, this_mul_optab, real0, ratio,
57952284Sobrien			     NULL_RTX, unsignedp, methods);
58052284Sobrien
58190075Sobrien      imag_t = expand_unop (submode, this_neg_optab, real0,
58252284Sobrien			    NULL_RTX, unsignedp);
58352284Sobrien
58452284Sobrien      if (real_t == 0 || imag_t == 0)
58552284Sobrien	return 0;
58652284Sobrien    }
58752284Sobrien  else
58852284Sobrien    {
58952284Sobrien      /* Compute (a+ib)/(c+id) as
59052284Sobrien	 (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d).  */
59152284Sobrien
59290075Sobrien      temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
59352284Sobrien			    NULL_RTX, unsignedp, methods);
59452284Sobrien
59552284Sobrien      if (temp1 == 0)
59652284Sobrien	return 0;
59752284Sobrien
59890075Sobrien      real_t = expand_binop (submode, this_add_optab, temp1, imag0,
59952284Sobrien			     NULL_RTX, unsignedp, methods);
60052284Sobrien
60190075Sobrien      temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
60252284Sobrien			    NULL_RTX, unsignedp, methods);
60352284Sobrien
60452284Sobrien      if (temp1 == 0)
60552284Sobrien	return 0;
60652284Sobrien
60790075Sobrien      imag_t = expand_binop (submode, this_sub_optab, temp1, real0,
60852284Sobrien			     NULL_RTX, unsignedp, methods);
60952284Sobrien
61052284Sobrien      if (real_t == 0 || imag_t == 0)
61152284Sobrien	return 0;
61252284Sobrien    }
61352284Sobrien
61452284Sobrien  if (class == MODE_COMPLEX_FLOAT)
61552284Sobrien    res = expand_binop (submode, binoptab, real_t, divisor,
61652284Sobrien			realr, unsignedp, methods);
61752284Sobrien  else
61852284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
61952284Sobrien			 real_t, divisor, realr, unsignedp);
62052284Sobrien
62152284Sobrien  if (res == 0)
62252284Sobrien    return 0;
62352284Sobrien
62452284Sobrien  if (res != realr)
62552284Sobrien    emit_move_insn (realr, res);
62652284Sobrien
62752284Sobrien  if (class == MODE_COMPLEX_FLOAT)
62852284Sobrien    res = expand_binop (submode, binoptab, imag_t, divisor,
62952284Sobrien			imagr, unsignedp, methods);
63052284Sobrien  else
63152284Sobrien    res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
63252284Sobrien			 imag_t, divisor, imagr, unsignedp);
63352284Sobrien
63452284Sobrien  if (res == 0)
63552284Sobrien    return 0;
63652284Sobrien
63752284Sobrien  if (res != imagr)
63852284Sobrien    emit_move_insn (imagr, res);
63952284Sobrien
64052284Sobrien  emit_label (lab2);
64152284Sobrien
64252284Sobrien  return 1;
64352284Sobrien}
64452284Sobrien
64590075Sobrien/* Wrapper around expand_binop which takes an rtx code to specify
64690075Sobrien   the operation to perform, not an optab pointer.  All other
64790075Sobrien   arguments are the same.  */
64890075Sobrienrtx
64990075Sobrienexpand_simple_binop (mode, code, op0, op1, target, unsignedp, methods)
65090075Sobrien     enum machine_mode mode;
65190075Sobrien     enum rtx_code code;
65290075Sobrien     rtx op0, op1;
65390075Sobrien     rtx target;
65490075Sobrien     int unsignedp;
65590075Sobrien     enum optab_methods methods;
65690075Sobrien{
657117395Skan  optab binop = code_to_optab[(int) code];
65890075Sobrien  if (binop == 0)
65990075Sobrien    abort ();
66090075Sobrien
66190075Sobrien  return expand_binop (mode, binop, op0, op1, target, unsignedp, methods);
66290075Sobrien}
66390075Sobrien
66418334Speter/* Generate code to perform an operation specified by BINOPTAB
66518334Speter   on operands OP0 and OP1, with result having machine-mode MODE.
66618334Speter
66718334Speter   UNSIGNEDP is for the case where we have to widen the operands
66818334Speter   to perform the operation.  It says to use zero-extension.
66918334Speter
67018334Speter   If TARGET is nonzero, the value
67118334Speter   is generated there, if it is convenient to do so.
67218334Speter   In all cases an rtx is returned for the locus of the value;
67318334Speter   this may or may not be TARGET.  */
67418334Speter
67518334Speterrtx
67618334Speterexpand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
67718334Speter     enum machine_mode mode;
67818334Speter     optab binoptab;
67918334Speter     rtx op0, op1;
68018334Speter     rtx target;
68118334Speter     int unsignedp;
68218334Speter     enum optab_methods methods;
68318334Speter{
68418334Speter  enum optab_methods next_methods
68518334Speter    = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
68618334Speter       ? OPTAB_WIDEN : methods);
68718334Speter  enum mode_class class;
68818334Speter  enum machine_mode wider_mode;
68990075Sobrien  rtx temp;
69018334Speter  int commutative_op = 0;
691117395Skan  int shift_op = (binoptab->code == ASHIFT
69218334Speter		  || binoptab->code == ASHIFTRT
69318334Speter		  || binoptab->code == LSHIFTRT
69418334Speter		  || binoptab->code == ROTATE
69518334Speter		  || binoptab->code == ROTATERT);
69618334Speter  rtx entry_last = get_last_insn ();
69718334Speter  rtx last;
69818334Speter
69918334Speter  class = GET_MODE_CLASS (mode);
70018334Speter
70118334Speter  op0 = protect_from_queue (op0, 0);
70218334Speter  op1 = protect_from_queue (op1, 0);
70318334Speter  if (target)
70418334Speter    target = protect_from_queue (target, 1);
70518334Speter
70618334Speter  if (flag_force_mem)
70718334Speter    {
70818334Speter      op0 = force_not_mem (op0);
70918334Speter      op1 = force_not_mem (op1);
71018334Speter    }
71118334Speter
71218334Speter  /* If subtracting an integer constant, convert this into an addition of
71318334Speter     the negated constant.  */
71418334Speter
71518334Speter  if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT)
71618334Speter    {
71718334Speter      op1 = negate_rtx (mode, op1);
71818334Speter      binoptab = add_optab;
71918334Speter    }
72018334Speter
72118334Speter  /* If we are inside an appropriately-short loop and one operand is an
72218334Speter     expensive constant, force it into a register.  */
72318334Speter  if (CONSTANT_P (op0) && preserve_subexpressions_p ()
72490075Sobrien      && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
72518334Speter    op0 = force_reg (mode, op0);
72618334Speter
72718334Speter  if (CONSTANT_P (op1) && preserve_subexpressions_p ()
72890075Sobrien      && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
72918334Speter    op1 = force_reg (mode, op1);
73018334Speter
73118334Speter  /* Record where to delete back to if we backtrack.  */
73218334Speter  last = get_last_insn ();
73318334Speter
73418334Speter  /* If operation is commutative,
73518334Speter     try to make the first operand a register.
73618334Speter     Even better, try to make it the same as the target.
73718334Speter     Also try to make the last operand a constant.  */
73818334Speter  if (GET_RTX_CLASS (binoptab->code) == 'c'
73918334Speter      || binoptab == smul_widen_optab
74018334Speter      || binoptab == umul_widen_optab
74118334Speter      || binoptab == smul_highpart_optab
74218334Speter      || binoptab == umul_highpart_optab)
74318334Speter    {
74418334Speter      commutative_op = 1;
74518334Speter
74618334Speter      if (((target == 0 || GET_CODE (target) == REG)
74718334Speter	   ? ((GET_CODE (op1) == REG
74818334Speter	       && GET_CODE (op0) != REG)
74918334Speter	      || target == op1)
75018334Speter	   : rtx_equal_p (op1, target))
75118334Speter	  || GET_CODE (op0) == CONST_INT)
75218334Speter	{
75318334Speter	  temp = op1;
75418334Speter	  op1 = op0;
75518334Speter	  op0 = temp;
75618334Speter	}
75718334Speter    }
75818334Speter
75918334Speter  /* If we can do it with a three-operand insn, do so.  */
76018334Speter
76118334Speter  if (methods != OPTAB_MUST_WIDEN
76218334Speter      && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
76318334Speter    {
76418334Speter      int icode = (int) binoptab->handlers[(int) mode].insn_code;
76590075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
76690075Sobrien      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
76718334Speter      rtx pat;
76818334Speter      rtx xop0 = op0, xop1 = op1;
76918334Speter
77018334Speter      if (target)
77118334Speter	temp = target;
77218334Speter      else
77318334Speter	temp = gen_reg_rtx (mode);
77418334Speter
77518334Speter      /* If it is a commutative operator and the modes would match
77650397Sobrien	 if we would swap the operands, we can save the conversions.  */
77718334Speter      if (commutative_op)
77818334Speter	{
77918334Speter	  if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
78018334Speter	      && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
78118334Speter	    {
78290075Sobrien	      rtx tmp;
78318334Speter
78418334Speter	      tmp = op0; op0 = op1; op1 = tmp;
78518334Speter	      tmp = xop0; xop0 = xop1; xop1 = tmp;
78618334Speter	    }
78718334Speter	}
78818334Speter
78918334Speter      /* In case the insn wants input operands in modes different from
790103445Skan	 those of the actual operands, convert the operands.  It would
791103445Skan	 seem that we don't need to convert CONST_INTs, but we do, so
792110611Skan	 that they're properly zero-extended, sign-extended or truncated
793110611Skan	 for their mode.  */
79418334Speter
795117395Skan      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
79690075Sobrien	xop0 = convert_modes (mode0,
79790075Sobrien			      GET_MODE (op0) != VOIDmode
79890075Sobrien			      ? GET_MODE (op0)
799103445Skan			      : mode,
80090075Sobrien			      xop0, unsignedp);
80118334Speter
802117395Skan      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
80390075Sobrien	xop1 = convert_modes (mode1,
80490075Sobrien			      GET_MODE (op1) != VOIDmode
80590075Sobrien			      ? GET_MODE (op1)
806110611Skan			      : mode,
80790075Sobrien			      xop1, unsignedp);
80818334Speter
80918334Speter      /* Now, if insn's predicates don't allow our operands, put them into
81018334Speter	 pseudo regs.  */
81118334Speter
81290075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)
81318334Speter	  && mode0 != VOIDmode)
81418334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
81518334Speter
81690075Sobrien      if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
81718334Speter	  && mode1 != VOIDmode)
81818334Speter	xop1 = copy_to_mode_reg (mode1, xop1);
81918334Speter
82090075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
82118334Speter	temp = gen_reg_rtx (mode);
82218334Speter
82318334Speter      pat = GEN_FCN (icode) (temp, xop0, xop1);
82418334Speter      if (pat)
82518334Speter	{
826117395Skan	  /* If PAT is composed of more than one insn, try to add an appropriate
82718334Speter	     REG_EQUAL note to it.  If we can't because TEMP conflicts with an
82818334Speter	     operand, call ourselves again, this time without a target.  */
829117395Skan	  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
83018334Speter	      && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
83118334Speter	    {
83218334Speter	      delete_insns_since (last);
83318334Speter	      return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
83418334Speter				   unsignedp, methods);
83518334Speter	    }
83618334Speter
83718334Speter	  emit_insn (pat);
83818334Speter	  return temp;
83918334Speter	}
84018334Speter      else
84118334Speter	delete_insns_since (last);
84218334Speter    }
84318334Speter
84418334Speter  /* If this is a multiply, see if we can do a widening operation that
84518334Speter     takes operands of this mode and makes a wider mode.  */
84618334Speter
84718334Speter  if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode
84818334Speter      && (((unsignedp ? umul_widen_optab : smul_widen_optab)
84918334Speter	   ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code)
85018334Speter	  != CODE_FOR_nothing))
85118334Speter    {
85218334Speter      temp = expand_binop (GET_MODE_WIDER_MODE (mode),
85318334Speter			   unsignedp ? umul_widen_optab : smul_widen_optab,
85418334Speter			   op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);
85518334Speter
85618334Speter      if (temp != 0)
85718334Speter	{
85818334Speter	  if (GET_MODE_CLASS (mode) == MODE_INT)
85918334Speter	    return gen_lowpart (mode, temp);
86018334Speter	  else
86118334Speter	    return convert_to_mode (mode, temp, unsignedp);
86218334Speter	}
86318334Speter    }
86418334Speter
86518334Speter  /* Look for a wider mode of the same class for which we think we
86618334Speter     can open-code the operation.  Check for a widening multiply at the
86718334Speter     wider mode as well.  */
86818334Speter
86918334Speter  if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
87018334Speter      && methods != OPTAB_DIRECT && methods != OPTAB_LIB)
87118334Speter    for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
87218334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
87318334Speter      {
87418334Speter	if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
87518334Speter	    || (binoptab == smul_optab
87618334Speter		&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
87718334Speter		&& (((unsignedp ? umul_widen_optab : smul_widen_optab)
87818334Speter		     ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code)
87918334Speter		    != CODE_FOR_nothing)))
88018334Speter	  {
88118334Speter	    rtx xop0 = op0, xop1 = op1;
88218334Speter	    int no_extend = 0;
88318334Speter
88418334Speter	    /* For certain integer operations, we need not actually extend
88518334Speter	       the narrow operands, as long as we will truncate
88690075Sobrien	       the results to the same narrowness.  */
88718334Speter
88818334Speter	    if ((binoptab == ior_optab || binoptab == and_optab
88918334Speter		 || binoptab == xor_optab
89018334Speter		 || binoptab == add_optab || binoptab == sub_optab
89118334Speter		 || binoptab == smul_optab || binoptab == ashl_optab)
89218334Speter		&& class == MODE_INT)
89318334Speter	      no_extend = 1;
89418334Speter
89518334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend);
89618334Speter
89718334Speter	    /* The second operand of a shift must always be extended.  */
89818334Speter	    xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
89918334Speter				  no_extend && binoptab != ashl_optab);
90018334Speter
90118334Speter	    temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
90218334Speter				 unsignedp, OPTAB_DIRECT);
90318334Speter	    if (temp)
90418334Speter	      {
90518334Speter		if (class != MODE_INT)
90618334Speter		  {
90718334Speter		    if (target == 0)
90818334Speter		      target = gen_reg_rtx (mode);
90918334Speter		    convert_move (target, temp, 0);
91018334Speter		    return target;
91118334Speter		  }
91218334Speter		else
91318334Speter		  return gen_lowpart (mode, temp);
91418334Speter	      }
91518334Speter	    else
91618334Speter	      delete_insns_since (last);
91718334Speter	  }
91818334Speter      }
91918334Speter
92018334Speter  /* These can be done a word at a time.  */
92118334Speter  if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
92218334Speter      && class == MODE_INT
92318334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
92418334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
92518334Speter    {
92618334Speter      int i;
92718334Speter      rtx insns;
92818334Speter      rtx equiv_value;
92918334Speter
93018334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
93118334Speter	 won't be accurate, so use a new target.  */
93218334Speter      if (target == 0 || target == op0 || target == op1)
93318334Speter	target = gen_reg_rtx (mode);
93418334Speter
93518334Speter      start_sequence ();
93618334Speter
93718334Speter      /* Do the actual arithmetic.  */
93818334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
93918334Speter	{
94018334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
94118334Speter	  rtx x = expand_binop (word_mode, binoptab,
94218334Speter				operand_subword_force (op0, i, mode),
94318334Speter				operand_subword_force (op1, i, mode),
94418334Speter				target_piece, unsignedp, next_methods);
94518334Speter
94618334Speter	  if (x == 0)
94718334Speter	    break;
94818334Speter
94918334Speter	  if (target_piece != x)
95018334Speter	    emit_move_insn (target_piece, x);
95118334Speter	}
95218334Speter
95318334Speter      insns = get_insns ();
95418334Speter      end_sequence ();
95518334Speter
95618334Speter      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
95718334Speter	{
95818334Speter	  if (binoptab->code != UNKNOWN)
95918334Speter	    equiv_value
96050397Sobrien	      = gen_rtx_fmt_ee (binoptab->code, mode,
96150397Sobrien				copy_rtx (op0), copy_rtx (op1));
96218334Speter	  else
96318334Speter	    equiv_value = 0;
96418334Speter
96518334Speter	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);
96618334Speter	  return target;
96718334Speter	}
96818334Speter    }
96918334Speter
97018334Speter  /* Synthesize double word shifts from single word shifts.  */
97118334Speter  if ((binoptab == lshr_optab || binoptab == ashl_optab
97218334Speter       || binoptab == ashr_optab)
97318334Speter      && class == MODE_INT
97418334Speter      && GET_CODE (op1) == CONST_INT
97518334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
97618334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
97718334Speter      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
97818334Speter      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
97918334Speter    {
98018334Speter      rtx insns, inter, equiv_value;
98118334Speter      rtx into_target, outof_target;
98218334Speter      rtx into_input, outof_input;
98318334Speter      int shift_count, left_shift, outof_word;
98418334Speter
98518334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
98618334Speter	 won't be accurate, so use a new target.  */
98718334Speter      if (target == 0 || target == op0 || target == op1)
98818334Speter	target = gen_reg_rtx (mode);
98918334Speter
99018334Speter      start_sequence ();
99118334Speter
99218334Speter      shift_count = INTVAL (op1);
99318334Speter
99418334Speter      /* OUTOF_* is the word we are shifting bits away from, and
99518334Speter	 INTO_* is the word that we are shifting bits towards, thus
99618334Speter	 they differ depending on the direction of the shift and
99718334Speter	 WORDS_BIG_ENDIAN.  */
99818334Speter
99918334Speter      left_shift = binoptab == ashl_optab;
100018334Speter      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
100118334Speter
100218334Speter      outof_target = operand_subword (target, outof_word, 1, mode);
100318334Speter      into_target = operand_subword (target, 1 - outof_word, 1, mode);
100418334Speter
100518334Speter      outof_input = operand_subword_force (op0, outof_word, mode);
100618334Speter      into_input = operand_subword_force (op0, 1 - outof_word, mode);
100718334Speter
100818334Speter      if (shift_count >= BITS_PER_WORD)
100918334Speter	{
101018334Speter	  inter = expand_binop (word_mode, binoptab,
101118334Speter			       outof_input,
101218334Speter			       GEN_INT (shift_count - BITS_PER_WORD),
101318334Speter			       into_target, unsignedp, next_methods);
101418334Speter
101518334Speter	  if (inter != 0 && inter != into_target)
101618334Speter	    emit_move_insn (into_target, inter);
101718334Speter
101818334Speter	  /* For a signed right shift, we must fill the word we are shifting
101918334Speter	     out of with copies of the sign bit.  Otherwise it is zeroed.  */
102018334Speter	  if (inter != 0 && binoptab != ashr_optab)
102118334Speter	    inter = CONST0_RTX (word_mode);
102218334Speter	  else if (inter != 0)
102318334Speter	    inter = expand_binop (word_mode, binoptab,
102418334Speter				  outof_input,
102518334Speter				  GEN_INT (BITS_PER_WORD - 1),
102618334Speter				  outof_target, unsignedp, next_methods);
102718334Speter
102818334Speter	  if (inter != 0 && inter != outof_target)
102918334Speter	    emit_move_insn (outof_target, inter);
103018334Speter	}
103118334Speter      else
103218334Speter	{
103318334Speter	  rtx carries;
103418334Speter	  optab reverse_unsigned_shift, unsigned_shift;
103518334Speter
103618334Speter	  /* For a shift of less then BITS_PER_WORD, to compute the carry,
103718334Speter	     we must do a logical shift in the opposite direction of the
103818334Speter	     desired shift.  */
103918334Speter
104018334Speter	  reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab);
104118334Speter
104218334Speter	  /* For a shift of less than BITS_PER_WORD, to compute the word
104318334Speter	     shifted towards, we need to unsigned shift the orig value of
104418334Speter	     that word.  */
104518334Speter
104618334Speter	  unsigned_shift = (left_shift ? ashl_optab : lshr_optab);
104718334Speter
104818334Speter	  carries = expand_binop (word_mode, reverse_unsigned_shift,
104918334Speter				  outof_input,
105018334Speter				  GEN_INT (BITS_PER_WORD - shift_count),
105118334Speter				  0, unsignedp, next_methods);
105218334Speter
105318334Speter	  if (carries == 0)
105418334Speter	    inter = 0;
105518334Speter	  else
105618334Speter	    inter = expand_binop (word_mode, unsigned_shift, into_input,
105718334Speter				  op1, 0, unsignedp, next_methods);
105818334Speter
105918334Speter	  if (inter != 0)
106018334Speter	    inter = expand_binop (word_mode, ior_optab, carries, inter,
106118334Speter				  into_target, unsignedp, next_methods);
106218334Speter
106318334Speter	  if (inter != 0 && inter != into_target)
106418334Speter	    emit_move_insn (into_target, inter);
106518334Speter
106618334Speter	  if (inter != 0)
106718334Speter	    inter = expand_binop (word_mode, binoptab, outof_input,
106818334Speter				  op1, outof_target, unsignedp, next_methods);
106918334Speter
107018334Speter	  if (inter != 0 && inter != outof_target)
107118334Speter	    emit_move_insn (outof_target, inter);
107218334Speter	}
107318334Speter
107418334Speter      insns = get_insns ();
107518334Speter      end_sequence ();
107618334Speter
107718334Speter      if (inter != 0)
107818334Speter	{
107918334Speter	  if (binoptab->code != UNKNOWN)
108050397Sobrien	    equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
108118334Speter	  else
108218334Speter	    equiv_value = 0;
108318334Speter
108418334Speter	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);
108518334Speter	  return target;
108618334Speter	}
108718334Speter    }
108818334Speter
108918334Speter  /* Synthesize double word rotates from single word shifts.  */
109018334Speter  if ((binoptab == rotl_optab || binoptab == rotr_optab)
109118334Speter      && class == MODE_INT
109218334Speter      && GET_CODE (op1) == CONST_INT
109318334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
109418334Speter      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
109518334Speter      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
109618334Speter    {
109718334Speter      rtx insns, equiv_value;
109818334Speter      rtx into_target, outof_target;
109918334Speter      rtx into_input, outof_input;
110018334Speter      rtx inter;
110118334Speter      int shift_count, left_shift, outof_word;
110218334Speter
110318334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
110418334Speter	 won't be accurate, so use a new target.  */
110518334Speter      if (target == 0 || target == op0 || target == op1)
110618334Speter	target = gen_reg_rtx (mode);
110718334Speter
110818334Speter      start_sequence ();
110918334Speter
111018334Speter      shift_count = INTVAL (op1);
111118334Speter
111218334Speter      /* OUTOF_* is the word we are shifting bits away from, and
111318334Speter	 INTO_* is the word that we are shifting bits towards, thus
111418334Speter	 they differ depending on the direction of the shift and
111518334Speter	 WORDS_BIG_ENDIAN.  */
111618334Speter
111718334Speter      left_shift = (binoptab == rotl_optab);
111818334Speter      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
111918334Speter
112018334Speter      outof_target = operand_subword (target, outof_word, 1, mode);
112118334Speter      into_target = operand_subword (target, 1 - outof_word, 1, mode);
112218334Speter
112318334Speter      outof_input = operand_subword_force (op0, outof_word, mode);
112418334Speter      into_input = operand_subword_force (op0, 1 - outof_word, mode);
112518334Speter
112618334Speter      if (shift_count == BITS_PER_WORD)
112718334Speter	{
112818334Speter	  /* This is just a word swap.  */
112918334Speter	  emit_move_insn (outof_target, into_input);
113018334Speter	  emit_move_insn (into_target, outof_input);
113118334Speter	  inter = const0_rtx;
113218334Speter	}
113318334Speter      else
113418334Speter	{
113518334Speter	  rtx into_temp1, into_temp2, outof_temp1, outof_temp2;
113618334Speter	  rtx first_shift_count, second_shift_count;
113718334Speter	  optab reverse_unsigned_shift, unsigned_shift;
113818334Speter
113918334Speter	  reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
114018334Speter				    ? lshr_optab : ashl_optab);
114118334Speter
114218334Speter	  unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
114318334Speter			    ? ashl_optab : lshr_optab);
114418334Speter
114518334Speter	  if (shift_count > BITS_PER_WORD)
114618334Speter	    {
114718334Speter	      first_shift_count = GEN_INT (shift_count - BITS_PER_WORD);
1148117395Skan	      second_shift_count = GEN_INT (2 * BITS_PER_WORD - shift_count);
114918334Speter	    }
115018334Speter	  else
115118334Speter	    {
115218334Speter	      first_shift_count = GEN_INT (BITS_PER_WORD - shift_count);
115318334Speter	      second_shift_count = GEN_INT (shift_count);
115418334Speter	    }
115518334Speter
115618334Speter	  into_temp1 = expand_binop (word_mode, unsigned_shift,
115718334Speter				     outof_input, first_shift_count,
115818334Speter				     NULL_RTX, unsignedp, next_methods);
115918334Speter	  into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
116018334Speter				     into_input, second_shift_count,
1161117395Skan				     NULL_RTX, unsignedp, next_methods);
116218334Speter
116318334Speter	  if (into_temp1 != 0 && into_temp2 != 0)
116418334Speter	    inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2,
116518334Speter				  into_target, unsignedp, next_methods);
116618334Speter	  else
116718334Speter	    inter = 0;
116818334Speter
116918334Speter	  if (inter != 0 && inter != into_target)
117018334Speter	    emit_move_insn (into_target, inter);
117118334Speter
117218334Speter	  outof_temp1 = expand_binop (word_mode, unsigned_shift,
117318334Speter				      into_input, first_shift_count,
117418334Speter				      NULL_RTX, unsignedp, next_methods);
117518334Speter	  outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
117618334Speter				      outof_input, second_shift_count,
1177117395Skan				      NULL_RTX, unsignedp, next_methods);
117818334Speter
117918334Speter	  if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)
118018334Speter	    inter = expand_binop (word_mode, ior_optab,
118118334Speter				  outof_temp1, outof_temp2,
118218334Speter				  outof_target, unsignedp, next_methods);
118318334Speter
118418334Speter	  if (inter != 0 && inter != outof_target)
118518334Speter	    emit_move_insn (outof_target, inter);
118618334Speter	}
118718334Speter
118818334Speter      insns = get_insns ();
118918334Speter      end_sequence ();
119018334Speter
119118334Speter      if (inter != 0)
119218334Speter	{
119318334Speter	  if (binoptab->code != UNKNOWN)
119450397Sobrien	    equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
119518334Speter	  else
119618334Speter	    equiv_value = 0;
119718334Speter
119818334Speter	  /* We can't make this a no conflict block if this is a word swap,
119918334Speter	     because the word swap case fails if the input and output values
120018334Speter	     are in the same register.  */
120118334Speter	  if (shift_count != BITS_PER_WORD)
120218334Speter	    emit_no_conflict_block (insns, target, op0, op1, equiv_value);
120318334Speter	  else
1204117395Skan	    emit_insn (insns);
120518334Speter
120618334Speter
120718334Speter	  return target;
120818334Speter	}
120918334Speter    }
121018334Speter
121118334Speter  /* These can be done a word at a time by propagating carries.  */
121218334Speter  if ((binoptab == add_optab || binoptab == sub_optab)
121318334Speter      && class == MODE_INT
121418334Speter      && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD
121518334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
121618334Speter    {
1217117395Skan      unsigned int i;
121818334Speter      optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
1219117395Skan      const unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
122052284Sobrien      rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
1221102780Skan      rtx xop0, xop1, xtarget;
122218334Speter
122318334Speter      /* We can handle either a 1 or -1 value for the carry.  If STORE_FLAG
122418334Speter	 value is one of those, use it.  Otherwise, use 1 since it is the
122518334Speter	 one easiest to get.  */
122618334Speter#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
122718334Speter      int normalizep = STORE_FLAG_VALUE;
122818334Speter#else
122918334Speter      int normalizep = 1;
123018334Speter#endif
123118334Speter
123218334Speter      /* Prepare the operands.  */
123318334Speter      xop0 = force_reg (mode, op0);
123418334Speter      xop1 = force_reg (mode, op1);
123518334Speter
1236102780Skan      xtarget = gen_reg_rtx (mode);
123718334Speter
1238102780Skan      if (target == 0 || GET_CODE (target) != REG)
1239102780Skan	target = xtarget;
1240102780Skan
124118334Speter      /* Indicate for flow that the entire target reg is being set.  */
124218334Speter      if (GET_CODE (target) == REG)
1243102780Skan	emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget));
124418334Speter
124518334Speter      /* Do the actual arithmetic.  */
124618334Speter      for (i = 0; i < nwords; i++)
124718334Speter	{
124818334Speter	  int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
1249102780Skan	  rtx target_piece = operand_subword (xtarget, index, 1, mode);
125018334Speter	  rtx op0_piece = operand_subword_force (xop0, index, mode);
125118334Speter	  rtx op1_piece = operand_subword_force (xop1, index, mode);
125218334Speter	  rtx x;
125318334Speter
125418334Speter	  /* Main add/subtract of the input operands.  */
125518334Speter	  x = expand_binop (word_mode, binoptab,
125618334Speter			    op0_piece, op1_piece,
125718334Speter			    target_piece, unsignedp, next_methods);
125818334Speter	  if (x == 0)
125918334Speter	    break;
126018334Speter
126118334Speter	  if (i + 1 < nwords)
126218334Speter	    {
126318334Speter	      /* Store carry from main add/subtract.  */
126418334Speter	      carry_out = gen_reg_rtx (word_mode);
126550397Sobrien	      carry_out = emit_store_flag_force (carry_out,
126650397Sobrien						 (binoptab == add_optab
126790075Sobrien						  ? LT : GT),
126850397Sobrien						 x, op0_piece,
126950397Sobrien						 word_mode, 1, normalizep);
127018334Speter	    }
127118334Speter
127218334Speter	  if (i > 0)
127318334Speter	    {
127490075Sobrien	      rtx newx;
127590075Sobrien
127618334Speter	      /* Add/subtract previous carry to main result.  */
127790075Sobrien	      newx = expand_binop (word_mode,
127890075Sobrien				   normalizep == 1 ? binoptab : otheroptab,
127990075Sobrien				   x, carry_in,
128090075Sobrien				   NULL_RTX, 1, next_methods);
128118334Speter
128218334Speter	      if (i + 1 < nwords)
128318334Speter		{
128418334Speter		  /* Get out carry from adding/subtracting carry in.  */
128590075Sobrien		  rtx carry_tmp = gen_reg_rtx (word_mode);
128650397Sobrien		  carry_tmp = emit_store_flag_force (carry_tmp,
128790075Sobrien						     (binoptab == add_optab
128890075Sobrien						      ? LT : GT),
128990075Sobrien						     newx, x,
129050397Sobrien						     word_mode, 1, normalizep);
129118334Speter
129218334Speter		  /* Logical-ior the two poss. carry together.  */
129318334Speter		  carry_out = expand_binop (word_mode, ior_optab,
129418334Speter					    carry_out, carry_tmp,
129518334Speter					    carry_out, 0, next_methods);
129618334Speter		  if (carry_out == 0)
129718334Speter		    break;
129818334Speter		}
129990075Sobrien	      emit_move_insn (target_piece, newx);
130018334Speter	    }
130118334Speter
130218334Speter	  carry_in = carry_out;
130318334Speter	}
130418334Speter
1305117395Skan      if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
130618334Speter	{
130750397Sobrien	  if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
130850397Sobrien	    {
1309102780Skan	      rtx temp = emit_move_insn (target, xtarget);
131018334Speter
131152284Sobrien	      set_unique_reg_note (temp,
131252284Sobrien	      			   REG_EQUAL,
131352284Sobrien				   gen_rtx_fmt_ee (binoptab->code, mode,
131452284Sobrien						   copy_rtx (xop0),
131552284Sobrien						   copy_rtx (xop1)));
131650397Sobrien	    }
1317117395Skan	  else
1318117395Skan	    target = xtarget;
131990075Sobrien
132018334Speter	  return target;
132118334Speter	}
132290075Sobrien
132318334Speter      else
132418334Speter	delete_insns_since (last);
132518334Speter    }
132618334Speter
132718334Speter  /* If we want to multiply two two-word values and have normal and widening
132818334Speter     multiplies of single-word values, we can do this with three smaller
132918334Speter     multiplications.  Note that we do not make a REG_NO_CONFLICT block here
133018334Speter     because we are not operating on one word at a time.
133118334Speter
133218334Speter     The multiplication proceeds as follows:
133318334Speter			         _______________________
133418334Speter			        [__op0_high_|__op0_low__]
133518334Speter			         _______________________
133618334Speter        *			[__op1_high_|__op1_low__]
133718334Speter        _______________________________________________
133818334Speter			         _______________________
133918334Speter    (1)				[__op0_low__*__op1_low__]
134018334Speter		     _______________________
134118334Speter    (2a)	    [__op0_low__*__op1_high_]
134218334Speter		     _______________________
134318334Speter    (2b)	    [__op0_high_*__op1_low__]
134418334Speter         _______________________
134518334Speter    (3) [__op0_high_*__op1_high_]
134618334Speter
134718334Speter
134818334Speter    This gives a 4-word result.  Since we are only interested in the
134918334Speter    lower 2 words, partial result (3) and the upper words of (2a) and
135018334Speter    (2b) don't need to be calculated.  Hence (2a) and (2b) can be
135118334Speter    calculated using non-widening multiplication.
135218334Speter
135318334Speter    (1), however, needs to be calculated with an unsigned widening
135418334Speter    multiplication.  If this operation is not directly supported we
135518334Speter    try using a signed widening multiplication and adjust the result.
135618334Speter    This adjustment works as follows:
135718334Speter
135818334Speter      If both operands are positive then no adjustment is needed.
135918334Speter
136018334Speter      If the operands have different signs, for example op0_low < 0 and
136118334Speter      op1_low >= 0, the instruction treats the most significant bit of
136218334Speter      op0_low as a sign bit instead of a bit with significance
136318334Speter      2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low
136418334Speter      with 2**BITS_PER_WORD - op0_low, and two's complements the
136518334Speter      result.  Conclusion: We need to add op1_low * 2**BITS_PER_WORD to
136618334Speter      the result.
136718334Speter
136818334Speter      Similarly, if both operands are negative, we need to add
136918334Speter      (op0_low + op1_low) * 2**BITS_PER_WORD.
137018334Speter
137118334Speter      We use a trick to adjust quickly.  We logically shift op0_low right
137218334Speter      (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to
137318334Speter      op0_high (op1_high) before it is used to calculate 2b (2a).  If no
137418334Speter      logical shift exists, we do an arithmetic right shift and subtract
137518334Speter      the 0 or -1.  */
137618334Speter
137718334Speter  if (binoptab == smul_optab
137818334Speter      && class == MODE_INT
137918334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
138018334Speter      && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
138118334Speter      && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
138218334Speter      && ((umul_widen_optab->handlers[(int) mode].insn_code
138318334Speter	   != CODE_FOR_nothing)
138418334Speter	  || (smul_widen_optab->handlers[(int) mode].insn_code
138518334Speter	      != CODE_FOR_nothing)))
138618334Speter    {
138718334Speter      int low = (WORDS_BIG_ENDIAN ? 1 : 0);
138818334Speter      int high = (WORDS_BIG_ENDIAN ? 0 : 1);
138918334Speter      rtx op0_high = operand_subword_force (op0, high, mode);
139018334Speter      rtx op0_low = operand_subword_force (op0, low, mode);
139118334Speter      rtx op1_high = operand_subword_force (op1, high, mode);
139218334Speter      rtx op1_low = operand_subword_force (op1, low, mode);
139318334Speter      rtx product = 0;
139452284Sobrien      rtx op0_xhigh = NULL_RTX;
139552284Sobrien      rtx op1_xhigh = NULL_RTX;
139618334Speter
139718334Speter      /* If the target is the same as one of the inputs, don't use it.  This
139818334Speter	 prevents problems with the REG_EQUAL note.  */
139918334Speter      if (target == op0 || target == op1
140018334Speter	  || (target != 0 && GET_CODE (target) != REG))
140118334Speter	target = 0;
140218334Speter
140318334Speter      /* Multiply the two lower words to get a double-word product.
140418334Speter	 If unsigned widening multiplication is available, use that;
140518334Speter	 otherwise use the signed form and compensate.  */
140618334Speter
140718334Speter      if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
140818334Speter	{
140918334Speter	  product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,
141018334Speter				  target, 1, OPTAB_DIRECT);
141118334Speter
141218334Speter	  /* If we didn't succeed, delete everything we did so far.  */
141318334Speter	  if (product == 0)
141418334Speter	    delete_insns_since (last);
141518334Speter	  else
141618334Speter	    op0_xhigh = op0_high, op1_xhigh = op1_high;
141718334Speter	}
141818334Speter
141918334Speter      if (product == 0
142018334Speter	  && smul_widen_optab->handlers[(int) mode].insn_code
142118334Speter	       != CODE_FOR_nothing)
142218334Speter	{
142318334Speter	  rtx wordm1 = GEN_INT (BITS_PER_WORD - 1);
142418334Speter	  product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
142518334Speter				  target, 1, OPTAB_DIRECT);
142618334Speter	  op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
142718334Speter				    NULL_RTX, 1, next_methods);
142818334Speter	  if (op0_xhigh)
142918334Speter	    op0_xhigh = expand_binop (word_mode, add_optab, op0_high,
143018334Speter				      op0_xhigh, op0_xhigh, 0, next_methods);
143118334Speter	  else
143218334Speter	    {
143318334Speter	      op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
143418334Speter					NULL_RTX, 0, next_methods);
143518334Speter	      if (op0_xhigh)
143618334Speter		op0_xhigh = expand_binop (word_mode, sub_optab, op0_high,
143718334Speter					  op0_xhigh, op0_xhigh, 0,
143818334Speter					  next_methods);
143918334Speter	    }
144018334Speter
144118334Speter	  op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
144218334Speter				    NULL_RTX, 1, next_methods);
144318334Speter	  if (op1_xhigh)
144418334Speter	    op1_xhigh = expand_binop (word_mode, add_optab, op1_high,
144518334Speter				      op1_xhigh, op1_xhigh, 0, next_methods);
144618334Speter	  else
144718334Speter	    {
144818334Speter	      op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
144918334Speter					NULL_RTX, 0, next_methods);
145018334Speter	      if (op1_xhigh)
145118334Speter		op1_xhigh = expand_binop (word_mode, sub_optab, op1_high,
145218334Speter					  op1_xhigh, op1_xhigh, 0,
145318334Speter					  next_methods);
145418334Speter	    }
145518334Speter	}
145618334Speter
145718334Speter      /* If we have been able to directly compute the product of the
145818334Speter	 low-order words of the operands and perform any required adjustments
145918334Speter	 of the operands, we proceed by trying two more multiplications
146018334Speter	 and then computing the appropriate sum.
146118334Speter
146218334Speter	 We have checked above that the required addition is provided.
146318334Speter	 Full-word addition will normally always succeed, especially if
146418334Speter	 it is provided at all, so we don't worry about its failure.  The
146518334Speter	 multiplication may well fail, however, so we do handle that.  */
146618334Speter
146718334Speter      if (product && op0_xhigh && op1_xhigh)
146818334Speter	{
146918334Speter	  rtx product_high = operand_subword (product, high, 1, mode);
147018334Speter	  rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
147118334Speter				   NULL_RTX, 0, OPTAB_DIRECT);
147218334Speter
1473102780Skan	  if (!REG_P (product_high))
1474102780Skan	    product_high = force_reg (word_mode, product_high);
1475102780Skan
147618334Speter	  if (temp != 0)
147718334Speter	    temp = expand_binop (word_mode, add_optab, temp, product_high,
147818334Speter				 product_high, 0, next_methods);
147918334Speter
148018334Speter	  if (temp != 0 && temp != product_high)
148118334Speter	    emit_move_insn (product_high, temp);
148218334Speter
148318334Speter	  if (temp != 0)
148418334Speter	    temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
148518334Speter				 NULL_RTX, 0, OPTAB_DIRECT);
148618334Speter
148718334Speter	  if (temp != 0)
148818334Speter	    temp = expand_binop (word_mode, add_optab, temp,
148918334Speter				 product_high, product_high,
149018334Speter				 0, next_methods);
149118334Speter
149218334Speter	  if (temp != 0 && temp != product_high)
149318334Speter	    emit_move_insn (product_high, temp);
149418334Speter
1495102780Skan	  emit_move_insn (operand_subword (product, high, 1, mode), product_high);
1496102780Skan
149718334Speter	  if (temp != 0)
149818334Speter	    {
149950397Sobrien	      if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
150050397Sobrien		{
150150397Sobrien		  temp = emit_move_insn (product, product);
150252284Sobrien		  set_unique_reg_note (temp,
150352284Sobrien		  		       REG_EQUAL,
150452284Sobrien				       gen_rtx_fmt_ee (MULT, mode,
150552284Sobrien						       copy_rtx (op0),
150652284Sobrien						       copy_rtx (op1)));
150750397Sobrien		}
150890075Sobrien
150918334Speter	      return product;
151018334Speter	    }
151118334Speter	}
151218334Speter
151318334Speter      /* If we get here, we couldn't do it for some reason even though we
151418334Speter	 originally thought we could.  Delete anything we've emitted in
151518334Speter	 trying to do it.  */
151618334Speter
151718334Speter      delete_insns_since (last);
151818334Speter    }
151918334Speter
1520117395Skan  /* Open-code the vector operations if we have no hardware support
1521117395Skan     for them.  */
1522117395Skan  if (class == MODE_VECTOR_INT || class == MODE_VECTOR_FLOAT)
1523117395Skan    return expand_vector_binop (mode, binoptab, op0, op1, target,
1524117395Skan				unsignedp, methods);
1525117395Skan
152618334Speter  /* We need to open-code the complex type operations: '+, -, * and /' */
152718334Speter
152818334Speter  /* At this point we allow operations between two similar complex
152918334Speter     numbers, and also if one of the operands is not a complex number
153018334Speter     but rather of MODE_FLOAT or MODE_INT. However, the caller
153118334Speter     must make sure that the MODE of the non-complex operand matches
153218334Speter     the SUBMODE of the complex operand.  */
153318334Speter
153418334Speter  if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
153518334Speter    {
153618334Speter      rtx real0 = 0, imag0 = 0;
153718334Speter      rtx real1 = 0, imag1 = 0;
153818334Speter      rtx realr, imagr, res;
153918334Speter      rtx seq;
154018334Speter      rtx equiv_value;
154118334Speter      int ok = 0;
154218334Speter
154318334Speter      /* Find the correct mode for the real and imaginary parts */
1544117395Skan      enum machine_mode submode = GET_MODE_INNER(mode);
154518334Speter
154618334Speter      if (submode == BLKmode)
154718334Speter	abort ();
154818334Speter
154918334Speter      if (! target)
155018334Speter	target = gen_reg_rtx (mode);
155118334Speter
155218334Speter      start_sequence ();
155318334Speter
155452284Sobrien      realr = gen_realpart (submode, target);
155518334Speter      imagr = gen_imagpart (submode, target);
155618334Speter
155718334Speter      if (GET_MODE (op0) == mode)
155818334Speter	{
155952284Sobrien	  real0 = gen_realpart (submode, op0);
156018334Speter	  imag0 = gen_imagpart (submode, op0);
156118334Speter	}
156218334Speter      else
156318334Speter	real0 = op0;
156418334Speter
156518334Speter      if (GET_MODE (op1) == mode)
156618334Speter	{
156752284Sobrien	  real1 = gen_realpart (submode, op1);
156818334Speter	  imag1 = gen_imagpart (submode, op1);
156918334Speter	}
157018334Speter      else
157118334Speter	real1 = op1;
157218334Speter
1573117395Skan      if (real0 == 0 || real1 == 0 || ! (imag0 != 0 || imag1 != 0))
157418334Speter	abort ();
157518334Speter
157618334Speter      switch (binoptab->code)
157718334Speter	{
157818334Speter	case PLUS:
157918334Speter	  /* (a+ib) + (c+id) = (a+c) + i(b+d) */
158018334Speter	case MINUS:
158118334Speter	  /* (a+ib) - (c+id) = (a-c) + i(b-d) */
158218334Speter	  res = expand_binop (submode, binoptab, real0, real1,
158318334Speter			      realr, unsignedp, methods);
158418334Speter
158518334Speter	  if (res == 0)
158618334Speter	    break;
158718334Speter	  else if (res != realr)
158818334Speter	    emit_move_insn (realr, res);
158918334Speter
1590117395Skan	  if (imag0 != 0 && imag1 != 0)
159118334Speter	    res = expand_binop (submode, binoptab, imag0, imag1,
159218334Speter				imagr, unsignedp, methods);
1593117395Skan	  else if (imag0 != 0)
159418334Speter	    res = imag0;
159518334Speter	  else if (binoptab->code == MINUS)
159690075Sobrien            res = expand_unop (submode,
159790075Sobrien                                binoptab == subv_optab ? negv_optab : neg_optab,
159890075Sobrien                                imag1, imagr, unsignedp);
159918334Speter	  else
160018334Speter	    res = imag1;
160118334Speter
160218334Speter	  if (res == 0)
160318334Speter	    break;
160418334Speter	  else if (res != imagr)
160518334Speter	    emit_move_insn (imagr, res);
160618334Speter
160718334Speter	  ok = 1;
160818334Speter	  break;
160918334Speter
161018334Speter	case MULT:
161118334Speter	  /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
161218334Speter
1613117395Skan	  if (imag0 != 0 && imag1 != 0)
161418334Speter	    {
161518334Speter	      rtx temp1, temp2;
161618334Speter
161718334Speter	      /* Don't fetch these from memory more than once.  */
161818334Speter	      real0 = force_reg (submode, real0);
161918334Speter	      real1 = force_reg (submode, real1);
162018334Speter	      imag0 = force_reg (submode, imag0);
162118334Speter	      imag1 = force_reg (submode, imag1);
162218334Speter
162318334Speter	      temp1 = expand_binop (submode, binoptab, real0, real1, NULL_RTX,
162418334Speter				    unsignedp, methods);
162518334Speter
162618334Speter	      temp2 = expand_binop (submode, binoptab, imag0, imag1, NULL_RTX,
162718334Speter				    unsignedp, methods);
162818334Speter
162918334Speter	      if (temp1 == 0 || temp2 == 0)
163018334Speter		break;
163118334Speter
163290075Sobrien	      res = (expand_binop
163390075Sobrien                     (submode,
163490075Sobrien                      binoptab == smulv_optab ? subv_optab : sub_optab,
163590075Sobrien                      temp1, temp2, realr, unsignedp, methods));
163618334Speter
163718334Speter	      if (res == 0)
163818334Speter		break;
163918334Speter	      else if (res != realr)
164018334Speter		emit_move_insn (realr, res);
164118334Speter
164218334Speter	      temp1 = expand_binop (submode, binoptab, real0, imag1,
164318334Speter				    NULL_RTX, unsignedp, methods);
164418334Speter
164518334Speter	      temp2 = expand_binop (submode, binoptab, real1, imag0,
164618334Speter				    NULL_RTX, unsignedp, methods);
164718334Speter
164818334Speter	      if (temp1 == 0 || temp2 == 0)
1649117395Skan		break;
165018334Speter
165190075Sobrien	      res = (expand_binop
165290075Sobrien                     (submode,
165390075Sobrien                      binoptab == smulv_optab ? addv_optab : add_optab,
165490075Sobrien                      temp1, temp2, imagr, unsignedp, methods));
165518334Speter
165618334Speter	      if (res == 0)
165718334Speter		break;
165818334Speter	      else if (res != imagr)
165918334Speter		emit_move_insn (imagr, res);
166018334Speter
166118334Speter	      ok = 1;
166218334Speter	    }
166318334Speter	  else
166418334Speter	    {
166518334Speter	      /* Don't fetch these from memory more than once.  */
166618334Speter	      real0 = force_reg (submode, real0);
166718334Speter	      real1 = force_reg (submode, real1);
166818334Speter
166918334Speter	      res = expand_binop (submode, binoptab, real0, real1,
167018334Speter				  realr, unsignedp, methods);
167118334Speter	      if (res == 0)
167218334Speter		break;
167318334Speter	      else if (res != realr)
167418334Speter		emit_move_insn (realr, res);
167518334Speter
167618334Speter	      if (imag0 != 0)
167718334Speter		res = expand_binop (submode, binoptab,
167818334Speter				    real1, imag0, imagr, unsignedp, methods);
167918334Speter	      else
168018334Speter		res = expand_binop (submode, binoptab,
168118334Speter				    real0, imag1, imagr, unsignedp, methods);
168218334Speter
168318334Speter	      if (res == 0)
168418334Speter		break;
168518334Speter	      else if (res != imagr)
168618334Speter		emit_move_insn (imagr, res);
168718334Speter
168818334Speter	      ok = 1;
168918334Speter	    }
169018334Speter	  break;
169118334Speter
169218334Speter	case DIV:
169318334Speter	  /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
169418334Speter
169518334Speter	  if (imag1 == 0)
169618334Speter	    {
169718334Speter	      /* (a+ib) / (c+i0) = (a/c) + i(b/c) */
169818334Speter
169918334Speter	      /* Don't fetch these from memory more than once.  */
170018334Speter	      real1 = force_reg (submode, real1);
170118334Speter
170218334Speter	      /* Simply divide the real and imaginary parts by `c' */
170318334Speter	      if (class == MODE_COMPLEX_FLOAT)
170418334Speter		res = expand_binop (submode, binoptab, real0, real1,
170518334Speter				    realr, unsignedp, methods);
170618334Speter	      else
170718334Speter		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
170818334Speter				     real0, real1, realr, unsignedp);
170918334Speter
171018334Speter	      if (res == 0)
171118334Speter		break;
171218334Speter	      else if (res != realr)
171318334Speter		emit_move_insn (realr, res);
171418334Speter
171518334Speter	      if (class == MODE_COMPLEX_FLOAT)
171618334Speter		res = expand_binop (submode, binoptab, imag0, real1,
171718334Speter				    imagr, unsignedp, methods);
171818334Speter	      else
171918334Speter		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
172018334Speter				     imag0, real1, imagr, unsignedp);
172118334Speter
172218334Speter	      if (res == 0)
172318334Speter		break;
172418334Speter	      else if (res != imagr)
172518334Speter		emit_move_insn (imagr, res);
172618334Speter
172718334Speter	      ok = 1;
172818334Speter	    }
172918334Speter	  else
173018334Speter	    {
173152284Sobrien	      switch (flag_complex_divide_method)
173218334Speter		{
173352284Sobrien		case 0:
173452284Sobrien		  ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1,
173552284Sobrien						 realr, imagr, submode,
173652284Sobrien						 unsignedp, methods,
173752284Sobrien						 class, binoptab);
173852284Sobrien		  break;
173918334Speter
174052284Sobrien		case 1:
174152284Sobrien		  ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1,
174252284Sobrien					     realr, imagr, submode,
174352284Sobrien					     unsignedp, methods,
174452284Sobrien					     class, binoptab);
174552284Sobrien		  break;
174618334Speter
174752284Sobrien		default:
174852284Sobrien		  abort ();
174918334Speter		}
175018334Speter	    }
175118334Speter	  break;
175218334Speter
175318334Speter	default:
175418334Speter	  abort ();
175518334Speter	}
175618334Speter
175718334Speter      seq = get_insns ();
175818334Speter      end_sequence ();
175918334Speter
176018334Speter      if (ok)
176118334Speter	{
176218334Speter	  if (binoptab->code != UNKNOWN)
176318334Speter	    equiv_value
176450397Sobrien	      = gen_rtx_fmt_ee (binoptab->code, mode,
176550397Sobrien				copy_rtx (op0), copy_rtx (op1));
176618334Speter	  else
176718334Speter	    equiv_value = 0;
176818334Speter
176918334Speter	  emit_no_conflict_block (seq, target, op0, op1, equiv_value);
177018334Speter
177118334Speter	  return target;
177218334Speter	}
177318334Speter    }
177418334Speter
177518334Speter  /* It can't be open-coded in this mode.
177618334Speter     Use a library call if one is available and caller says that's ok.  */
177718334Speter
177818334Speter  if (binoptab->handlers[(int) mode].libfunc
177918334Speter      && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
178018334Speter    {
178118334Speter      rtx insns;
178218334Speter      rtx op1x = op1;
178318334Speter      enum machine_mode op1_mode = mode;
178418334Speter      rtx value;
178518334Speter
178618334Speter      start_sequence ();
178718334Speter
178818334Speter      if (shift_op)
178918334Speter	{
179018334Speter	  op1_mode = word_mode;
179118334Speter	  /* Specify unsigned here,
179218334Speter	     since negative shift counts are meaningless.  */
179318334Speter	  op1x = convert_to_mode (word_mode, op1, 1);
179418334Speter	}
179518334Speter
179618334Speter      if (GET_MODE (op0) != VOIDmode
179718334Speter	  && GET_MODE (op0) != mode)
179818334Speter	op0 = convert_to_mode (mode, op0, unsignedp);
179918334Speter
180018334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
180118334Speter	 if the libcall is cse'd or moved.  */
180218334Speter      value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc,
180390075Sobrien				       NULL_RTX, LCT_CONST, mode, 2,
180418334Speter				       op0, mode, op1x, op1_mode);
180518334Speter
180618334Speter      insns = get_insns ();
180718334Speter      end_sequence ();
180818334Speter
180918334Speter      target = gen_reg_rtx (mode);
181018334Speter      emit_libcall_block (insns, target, value,
181150397Sobrien			  gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
181218334Speter
181318334Speter      return target;
181418334Speter    }
181518334Speter
181618334Speter  delete_insns_since (last);
181718334Speter
181818334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
181918334Speter
182018334Speter  if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN
182118334Speter	 || methods == OPTAB_MUST_WIDEN))
182218334Speter    {
182318334Speter      /* Caller says, don't even try.  */
182418334Speter      delete_insns_since (entry_last);
182518334Speter      return 0;
182618334Speter    }
182718334Speter
182818334Speter  /* Compute the value of METHODS to pass to recursive calls.
182918334Speter     Don't allow widening to be tried recursively.  */
183018334Speter
183118334Speter  methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT);
183218334Speter
183318334Speter  /* Look for a wider mode of the same class for which it appears we can do
183418334Speter     the operation.  */
183518334Speter
183618334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
183718334Speter    {
183818334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
183918334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
184018334Speter	{
184118334Speter	  if ((binoptab->handlers[(int) wider_mode].insn_code
184218334Speter	       != CODE_FOR_nothing)
184318334Speter	      || (methods == OPTAB_LIB
184418334Speter		  && binoptab->handlers[(int) wider_mode].libfunc))
184518334Speter	    {
184618334Speter	      rtx xop0 = op0, xop1 = op1;
184718334Speter	      int no_extend = 0;
184818334Speter
184918334Speter	      /* For certain integer operations, we need not actually extend
185018334Speter		 the narrow operands, as long as we will truncate
185118334Speter		 the results to the same narrowness.  */
185218334Speter
185318334Speter	      if ((binoptab == ior_optab || binoptab == and_optab
185418334Speter		   || binoptab == xor_optab
185518334Speter		   || binoptab == add_optab || binoptab == sub_optab
185618334Speter		   || binoptab == smul_optab || binoptab == ashl_optab)
185718334Speter		  && class == MODE_INT)
185818334Speter		no_extend = 1;
185918334Speter
186018334Speter	      xop0 = widen_operand (xop0, wider_mode, mode,
186118334Speter				    unsignedp, no_extend);
186218334Speter
186318334Speter	      /* The second operand of a shift must always be extended.  */
186418334Speter	      xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
186518334Speter				    no_extend && binoptab != ashl_optab);
186618334Speter
186718334Speter	      temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
186818334Speter				   unsignedp, methods);
186918334Speter	      if (temp)
187018334Speter		{
187118334Speter		  if (class != MODE_INT)
187218334Speter		    {
187318334Speter		      if (target == 0)
187418334Speter			target = gen_reg_rtx (mode);
187518334Speter		      convert_move (target, temp, 0);
187618334Speter		      return target;
187718334Speter		    }
187818334Speter		  else
187918334Speter		    return gen_lowpart (mode, temp);
188018334Speter		}
188118334Speter	      else
188218334Speter		delete_insns_since (last);
188318334Speter	    }
188418334Speter	}
188518334Speter    }
188618334Speter
188718334Speter  delete_insns_since (entry_last);
188818334Speter  return 0;
188918334Speter}
1890117395Skan
1891117395Skan/* Like expand_binop, but for open-coding vectors binops.  */
1892117395Skan
1893117395Skanstatic rtx
1894117395Skanexpand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
1895117395Skan     enum machine_mode mode;
1896117395Skan     optab binoptab;
1897117395Skan     rtx op0, op1;
1898117395Skan     rtx target;
1899117395Skan     int unsignedp;
1900117395Skan     enum optab_methods methods;
1901117395Skan{
1902117395Skan  enum machine_mode submode, tmode;
1903117395Skan  int size, elts, subsize, subbitsize, i;
1904117395Skan  rtx t, a, b, res, seq;
1905117395Skan  enum mode_class class;
1906117395Skan
1907117395Skan  class = GET_MODE_CLASS (mode);
1908117395Skan
1909117395Skan  size = GET_MODE_SIZE (mode);
1910117395Skan  submode = GET_MODE_INNER (mode);
1911117395Skan
1912117395Skan  /* Search for the widest vector mode with the same inner mode that is
1913117395Skan     still narrower than MODE and that allows to open-code this operator.
1914117395Skan     Note, if we find such a mode and the handler later decides it can't
1915117395Skan     do the expansion, we'll be called recursively with the narrower mode.  */
1916117395Skan  for (tmode = GET_CLASS_NARROWEST_MODE (class);
1917117395Skan       GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode);
1918117395Skan       tmode = GET_MODE_WIDER_MODE (tmode))
1919117395Skan    {
1920117395Skan      if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode)
1921117395Skan	  && binoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
1922117395Skan	submode = tmode;
1923117395Skan    }
1924117395Skan
1925117395Skan  switch (binoptab->code)
1926117395Skan    {
1927117395Skan    case AND:
1928117395Skan    case IOR:
1929117395Skan    case XOR:
1930117395Skan      tmode = int_mode_for_mode (mode);
1931117395Skan      if (tmode != BLKmode)
1932117395Skan	submode = tmode;
1933117395Skan    case PLUS:
1934117395Skan    case MINUS:
1935117395Skan    case MULT:
1936117395Skan    case DIV:
1937117395Skan      subsize = GET_MODE_SIZE (submode);
1938117395Skan      subbitsize = GET_MODE_BITSIZE (submode);
1939117395Skan      elts = size / subsize;
1940117395Skan
1941117395Skan      /* If METHODS is OPTAB_DIRECT, we don't insist on the exact mode,
1942117395Skan	 but that we operate on more than one element at a time.  */
1943117395Skan      if (subsize == GET_MODE_UNIT_SIZE (mode) && methods == OPTAB_DIRECT)
1944117395Skan	return 0;
1945117395Skan
1946117395Skan      start_sequence ();
1947117395Skan
1948117395Skan      /* Errors can leave us with a const0_rtx as operand.  */
1949117395Skan      if (GET_MODE (op0) != mode)
1950117395Skan	op0 = copy_to_mode_reg (mode, op0);
1951117395Skan      if (GET_MODE (op1) != mode)
1952117395Skan	op1 = copy_to_mode_reg (mode, op1);
1953117395Skan
1954117395Skan      if (!target)
1955117395Skan	target = gen_reg_rtx (mode);
1956117395Skan
1957117395Skan      for (i = 0; i < elts; ++i)
1958117395Skan	{
1959117395Skan	  /* If this is part of a register, and not the first item in the
1960117395Skan	     word, we can't store using a SUBREG - that would clobber
1961117395Skan	     previous results.
1962117395Skan	     And storing with a SUBREG is only possible for the least
1963117395Skan	     significant part, hence we can't do it for big endian
1964117395Skan	     (unless we want to permute the evaluation order.  */
1965117395Skan	  if (GET_CODE (target) == REG
1966117395Skan	      && (BYTES_BIG_ENDIAN
1967117395Skan		  ? subsize < UNITS_PER_WORD
1968117395Skan		  : ((i * subsize) % UNITS_PER_WORD) != 0))
1969117395Skan	    t = NULL_RTX;
1970117395Skan	  else
1971117395Skan	    t = simplify_gen_subreg (submode, target, mode, i * subsize);
1972117395Skan	  if (CONSTANT_P (op0))
1973117395Skan	    a = simplify_gen_subreg (submode, op0, mode, i * subsize);
1974117395Skan	  else
1975117395Skan	    a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp,
1976117395Skan				   NULL_RTX, submode, submode, size);
1977117395Skan	  if (CONSTANT_P (op1))
1978117395Skan	    b = simplify_gen_subreg (submode, op1, mode, i * subsize);
1979117395Skan	  else
1980117395Skan	    b = extract_bit_field (op1, subbitsize, i * subbitsize, unsignedp,
1981117395Skan				   NULL_RTX, submode, submode, size);
1982117395Skan
1983117395Skan	  if (binoptab->code == DIV)
1984117395Skan	    {
1985117395Skan	      if (class == MODE_VECTOR_FLOAT)
1986117395Skan		res = expand_binop (submode, binoptab, a, b, t,
1987117395Skan				    unsignedp, methods);
1988117395Skan	      else
1989117395Skan		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
1990117395Skan				     a, b, t, unsignedp);
1991117395Skan	    }
1992117395Skan	  else
1993117395Skan	    res = expand_binop (submode, binoptab, a, b, t,
1994117395Skan				unsignedp, methods);
1995117395Skan
1996117395Skan	  if (res == 0)
1997117395Skan	    break;
1998117395Skan
1999117395Skan	  if (t)
2000117395Skan	    emit_move_insn (t, res);
2001117395Skan	  else
2002117395Skan	    store_bit_field (target, subbitsize, i * subbitsize, submode, res,
2003117395Skan			     size);
2004117395Skan	}
2005117395Skan      break;
2006117395Skan
2007117395Skan    default:
2008117395Skan      abort ();
2009117395Skan    }
2010117395Skan
2011117395Skan  seq = get_insns ();
2012117395Skan  end_sequence ();
2013117395Skan  emit_insn (seq);
2014117395Skan
2015117395Skan  return target;
2016117395Skan}
2017117395Skan
2018117395Skan/* Like expand_unop but for open-coding vector unops.  */
2019117395Skan
2020117395Skanstatic rtx
2021117395Skanexpand_vector_unop (mode, unoptab, op0, target, unsignedp)
2022117395Skan     enum machine_mode mode;
2023117395Skan     optab unoptab;
2024117395Skan     rtx op0;
2025117395Skan     rtx target;
2026117395Skan     int unsignedp;
2027117395Skan{
2028117395Skan  enum machine_mode submode, tmode;
2029117395Skan  int size, elts, subsize, subbitsize, i;
2030117395Skan  rtx t, a, res, seq;
2031117395Skan
2032117395Skan  size = GET_MODE_SIZE (mode);
2033117395Skan  submode = GET_MODE_INNER (mode);
2034117395Skan
2035117395Skan  /* Search for the widest vector mode with the same inner mode that is
2036117395Skan     still narrower than MODE and that allows to open-code this operator.
2037117395Skan     Note, if we find such a mode and the handler later decides it can't
2038117395Skan     do the expansion, we'll be called recursively with the narrower mode.  */
2039117395Skan  for (tmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (mode));
2040117395Skan       GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode);
2041117395Skan       tmode = GET_MODE_WIDER_MODE (tmode))
2042117395Skan    {
2043117395Skan      if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode)
2044117395Skan	  && unoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
2045117395Skan	submode = tmode;
2046117395Skan    }
2047117395Skan  /* If there is no negate operation, try doing a subtract from zero.  */
2048117395Skan  if (unoptab == neg_optab && GET_MODE_CLASS (submode) == MODE_INT
2049117395Skan      /* Avoid infinite recursion when an
2050117395Skan	 error has left us with the wrong mode.  */
2051117395Skan      && GET_MODE (op0) == mode)
2052117395Skan    {
2053117395Skan      rtx temp;
2054117395Skan      temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
2055117395Skan                           target, unsignedp, OPTAB_DIRECT);
2056117395Skan      if (temp)
2057117395Skan	return temp;
2058117395Skan    }
2059117395Skan
2060117395Skan  if (unoptab == one_cmpl_optab)
2061117395Skan    {
2062117395Skan      tmode = int_mode_for_mode (mode);
2063117395Skan      if (tmode != BLKmode)
2064117395Skan	submode = tmode;
2065117395Skan    }
2066117395Skan
2067117395Skan  subsize = GET_MODE_SIZE (submode);
2068117395Skan  subbitsize = GET_MODE_BITSIZE (submode);
2069117395Skan  elts = size / subsize;
2070117395Skan
2071117395Skan  /* Errors can leave us with a const0_rtx as operand.  */
2072117395Skan  if (GET_MODE (op0) != mode)
2073117395Skan    op0 = copy_to_mode_reg (mode, op0);
2074117395Skan
2075117395Skan  if (!target)
2076117395Skan    target = gen_reg_rtx (mode);
2077117395Skan
2078117395Skan  start_sequence ();
2079117395Skan
2080117395Skan  for (i = 0; i < elts; ++i)
2081117395Skan    {
2082117395Skan      /* If this is part of a register, and not the first item in the
2083117395Skan	 word, we can't store using a SUBREG - that would clobber
2084117395Skan	 previous results.
2085117395Skan	 And storing with a SUBREG is only possible for the least
2086117395Skan	 significant part, hence we can't do it for big endian
2087117395Skan	 (unless we want to permute the evaluation order.  */
2088117395Skan      if (GET_CODE (target) == REG
2089117395Skan	  && (BYTES_BIG_ENDIAN
2090117395Skan	      ?  subsize < UNITS_PER_WORD
2091117395Skan	      : ((i * subsize) % UNITS_PER_WORD) != 0))
2092117395Skan	t = NULL_RTX;
2093117395Skan      else
2094117395Skan	t = simplify_gen_subreg (submode, target, mode, i * subsize);
2095117395Skan      if (CONSTANT_P (op0))
2096117395Skan	a = simplify_gen_subreg (submode, op0, mode, i * subsize);
2097117395Skan      else
2098117395Skan	a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp,
2099117395Skan			       t, submode, submode, size);
2100117395Skan
2101117395Skan      res = expand_unop (submode, unoptab, a, t, unsignedp);
2102117395Skan
2103117395Skan      if (t)
2104117395Skan	emit_move_insn (t, res);
2105117395Skan      else
2106117395Skan	store_bit_field (target, subbitsize, i * subbitsize, submode, res,
2107117395Skan			 size);
2108117395Skan    }
2109117395Skan
2110117395Skan  seq = get_insns ();
2111117395Skan  end_sequence ();
2112117395Skan  emit_insn (seq);
2113117395Skan
2114117395Skan  return target;
2115117395Skan}
211618334Speter
211718334Speter/* Expand a binary operator which has both signed and unsigned forms.
211818334Speter   UOPTAB is the optab for unsigned operations, and SOPTAB is for
211918334Speter   signed operations.
212018334Speter
212118334Speter   If we widen unsigned operands, we may use a signed wider operation instead
212218334Speter   of an unsigned wider operation, since the result would be the same.  */
212318334Speter
212418334Speterrtx
212518334Spetersign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
2126117395Skan     enum machine_mode mode;
2127117395Skan     optab uoptab, soptab;
2128117395Skan     rtx op0, op1, target;
2129117395Skan     int unsignedp;
2130117395Skan     enum optab_methods methods;
213118334Speter{
213290075Sobrien  rtx temp;
213318334Speter  optab direct_optab = unsignedp ? uoptab : soptab;
213418334Speter  struct optab wide_soptab;
213518334Speter
213618334Speter  /* Do it without widening, if possible.  */
213718334Speter  temp = expand_binop (mode, direct_optab, op0, op1, target,
213818334Speter		       unsignedp, OPTAB_DIRECT);
213918334Speter  if (temp || methods == OPTAB_DIRECT)
214018334Speter    return temp;
214118334Speter
214218334Speter  /* Try widening to a signed int.  Make a fake signed optab that
214318334Speter     hides any signed insn for direct use.  */
214418334Speter  wide_soptab = *soptab;
214518334Speter  wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing;
214618334Speter  wide_soptab.handlers[(int) mode].libfunc = 0;
214718334Speter
214818334Speter  temp = expand_binop (mode, &wide_soptab, op0, op1, target,
214918334Speter		       unsignedp, OPTAB_WIDEN);
215018334Speter
215118334Speter  /* For unsigned operands, try widening to an unsigned int.  */
215218334Speter  if (temp == 0 && unsignedp)
215318334Speter    temp = expand_binop (mode, uoptab, op0, op1, target,
215418334Speter			 unsignedp, OPTAB_WIDEN);
215518334Speter  if (temp || methods == OPTAB_WIDEN)
215618334Speter    return temp;
215718334Speter
215818334Speter  /* Use the right width lib call if that exists.  */
215918334Speter  temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB);
216018334Speter  if (temp || methods == OPTAB_LIB)
216118334Speter    return temp;
216218334Speter
216318334Speter  /* Must widen and use a lib call, use either signed or unsigned.  */
216418334Speter  temp = expand_binop (mode, &wide_soptab, op0, op1, target,
216518334Speter		       unsignedp, methods);
216618334Speter  if (temp != 0)
216718334Speter    return temp;
216818334Speter  if (unsignedp)
216918334Speter    return expand_binop (mode, uoptab, op0, op1, target,
217018334Speter			 unsignedp, methods);
217118334Speter  return 0;
217218334Speter}
217318334Speter
217418334Speter/* Generate code to perform an operation specified by BINOPTAB
217518334Speter   on operands OP0 and OP1, with two results to TARG1 and TARG2.
217618334Speter   We assume that the order of the operands for the instruction
217718334Speter   is TARG0, OP0, OP1, TARG1, which would fit a pattern like
217818334Speter   [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))].
217918334Speter
218018334Speter   Either TARG0 or TARG1 may be zero, but what that means is that
218150397Sobrien   the result is not actually wanted.  We will generate it into
218218334Speter   a dummy pseudo-reg and discard it.  They may not both be zero.
218318334Speter
218418334Speter   Returns 1 if this operation can be performed; 0 if not.  */
218518334Speter
218618334Speterint
218718334Speterexpand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
218818334Speter     optab binoptab;
218918334Speter     rtx op0, op1;
219018334Speter     rtx targ0, targ1;
219118334Speter     int unsignedp;
219218334Speter{
219318334Speter  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
219418334Speter  enum mode_class class;
219518334Speter  enum machine_mode wider_mode;
219618334Speter  rtx entry_last = get_last_insn ();
219718334Speter  rtx last;
219818334Speter
219918334Speter  class = GET_MODE_CLASS (mode);
220018334Speter
220118334Speter  op0 = protect_from_queue (op0, 0);
220218334Speter  op1 = protect_from_queue (op1, 0);
220318334Speter
220418334Speter  if (flag_force_mem)
220518334Speter    {
220618334Speter      op0 = force_not_mem (op0);
220718334Speter      op1 = force_not_mem (op1);
220818334Speter    }
220918334Speter
221018334Speter  /* If we are inside an appropriately-short loop and one operand is an
221118334Speter     expensive constant, force it into a register.  */
221218334Speter  if (CONSTANT_P (op0) && preserve_subexpressions_p ()
221390075Sobrien      && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
221418334Speter    op0 = force_reg (mode, op0);
221518334Speter
221618334Speter  if (CONSTANT_P (op1) && preserve_subexpressions_p ()
221790075Sobrien      && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
221818334Speter    op1 = force_reg (mode, op1);
221918334Speter
222018334Speter  if (targ0)
222118334Speter    targ0 = protect_from_queue (targ0, 1);
222218334Speter  else
222318334Speter    targ0 = gen_reg_rtx (mode);
222418334Speter  if (targ1)
222518334Speter    targ1 = protect_from_queue (targ1, 1);
222618334Speter  else
222718334Speter    targ1 = gen_reg_rtx (mode);
222818334Speter
222918334Speter  /* Record where to go back to if we fail.  */
223018334Speter  last = get_last_insn ();
223118334Speter
223218334Speter  if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
223318334Speter    {
223418334Speter      int icode = (int) binoptab->handlers[(int) mode].insn_code;
223590075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
223690075Sobrien      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
223718334Speter      rtx pat;
223818334Speter      rtx xop0 = op0, xop1 = op1;
223918334Speter
2240117395Skan      /* In case the insn wants input operands in modes different from
2241117395Skan	 those of the actual operands, convert the operands.  It would
2242117395Skan	 seem that we don't need to convert CONST_INTs, but we do, so
2243117395Skan	 that they're properly zero-extended, sign-extended or truncated
2244117395Skan	 for their mode.  */
224518334Speter
2246117395Skan      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
2247117395Skan	xop0 = convert_modes (mode0,
2248117395Skan			      GET_MODE (op0) != VOIDmode
2249117395Skan			      ? GET_MODE (op0)
2250117395Skan			      : mode,
2251117395Skan			      xop0, unsignedp);
225218334Speter
2253117395Skan      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
2254117395Skan	xop1 = convert_modes (mode1,
2255117395Skan			      GET_MODE (op1) != VOIDmode
2256117395Skan			      ? GET_MODE (op1)
2257117395Skan			      : mode,
2258117395Skan			      xop1, unsignedp);
2259117395Skan
226018334Speter      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
226190075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
226218334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
226318334Speter
226490075Sobrien      if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1))
226518334Speter	xop1 = copy_to_mode_reg (mode1, xop1);
226618334Speter
226718334Speter      /* We could handle this, but we should always be called with a pseudo
226818334Speter	 for our targets and all insns should take them as outputs.  */
226990075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
227090075Sobrien	  || ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
227118334Speter	abort ();
227218334Speter
227318334Speter      pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
227418334Speter      if (pat)
227518334Speter	{
227618334Speter	  emit_insn (pat);
227718334Speter	  return 1;
227818334Speter	}
227918334Speter      else
228018334Speter	delete_insns_since (last);
228118334Speter    }
228218334Speter
228318334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
228418334Speter
228518334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
228618334Speter    {
228718334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
228818334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
228918334Speter	{
229018334Speter	  if (binoptab->handlers[(int) wider_mode].insn_code
229118334Speter	      != CODE_FOR_nothing)
229218334Speter	    {
229390075Sobrien	      rtx t0 = gen_reg_rtx (wider_mode);
229490075Sobrien	      rtx t1 = gen_reg_rtx (wider_mode);
229590075Sobrien	      rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp);
229690075Sobrien	      rtx cop1 = convert_modes (wider_mode, mode, op1, unsignedp);
229718334Speter
229890075Sobrien	      if (expand_twoval_binop (binoptab, cop0, cop1,
229918334Speter				       t0, t1, unsignedp))
230018334Speter		{
230118334Speter		  convert_move (targ0, t0, unsignedp);
230218334Speter		  convert_move (targ1, t1, unsignedp);
230318334Speter		  return 1;
230418334Speter		}
230518334Speter	      else
230618334Speter		delete_insns_since (last);
230718334Speter	    }
230818334Speter	}
230918334Speter    }
231018334Speter
231118334Speter  delete_insns_since (entry_last);
231218334Speter  return 0;
231318334Speter}
231418334Speter
231590075Sobrien/* Wrapper around expand_unop which takes an rtx code to specify
231690075Sobrien   the operation to perform, not an optab pointer.  All other
231790075Sobrien   arguments are the same.  */
231890075Sobrienrtx
231990075Sobrienexpand_simple_unop (mode, code, op0, target, unsignedp)
232090075Sobrien     enum machine_mode mode;
232190075Sobrien     enum rtx_code code;
232290075Sobrien     rtx op0;
232390075Sobrien     rtx target;
232490075Sobrien     int unsignedp;
232590075Sobrien{
2326117395Skan  optab unop = code_to_optab[(int) code];
232790075Sobrien  if (unop == 0)
232890075Sobrien    abort ();
232990075Sobrien
233090075Sobrien  return expand_unop (mode, unop, op0, target, unsignedp);
233190075Sobrien}
233290075Sobrien
233318334Speter/* Generate code to perform an operation specified by UNOPTAB
233418334Speter   on operand OP0, with result having machine-mode MODE.
233518334Speter
233618334Speter   UNSIGNEDP is for the case where we have to widen the operands
233718334Speter   to perform the operation.  It says to use zero-extension.
233818334Speter
233918334Speter   If TARGET is nonzero, the value
234018334Speter   is generated there, if it is convenient to do so.
234118334Speter   In all cases an rtx is returned for the locus of the value;
234218334Speter   this may or may not be TARGET.  */
234318334Speter
234418334Speterrtx
234518334Speterexpand_unop (mode, unoptab, op0, target, unsignedp)
234618334Speter     enum machine_mode mode;
234718334Speter     optab unoptab;
234818334Speter     rtx op0;
234918334Speter     rtx target;
235018334Speter     int unsignedp;
235118334Speter{
235218334Speter  enum mode_class class;
235318334Speter  enum machine_mode wider_mode;
235490075Sobrien  rtx temp;
235518334Speter  rtx last = get_last_insn ();
235618334Speter  rtx pat;
235718334Speter
235818334Speter  class = GET_MODE_CLASS (mode);
235918334Speter
236018334Speter  op0 = protect_from_queue (op0, 0);
236118334Speter
236218334Speter  if (flag_force_mem)
236318334Speter    {
236418334Speter      op0 = force_not_mem (op0);
236518334Speter    }
236618334Speter
236718334Speter  if (target)
236818334Speter    target = protect_from_queue (target, 1);
236918334Speter
237018334Speter  if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
237118334Speter    {
237218334Speter      int icode = (int) unoptab->handlers[(int) mode].insn_code;
237390075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
237418334Speter      rtx xop0 = op0;
237518334Speter
237618334Speter      if (target)
237718334Speter	temp = target;
237818334Speter      else
237918334Speter	temp = gen_reg_rtx (mode);
238018334Speter
238118334Speter      if (GET_MODE (xop0) != VOIDmode
238218334Speter	  && GET_MODE (xop0) != mode0)
238318334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
238418334Speter
238518334Speter      /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
238618334Speter
238790075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
238818334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
238918334Speter
239090075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
239118334Speter	temp = gen_reg_rtx (mode);
239218334Speter
239318334Speter      pat = GEN_FCN (icode) (temp, xop0);
239418334Speter      if (pat)
239518334Speter	{
2396117395Skan	  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
239718334Speter	      && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX))
239818334Speter	    {
239918334Speter	      delete_insns_since (last);
240018334Speter	      return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp);
240118334Speter	    }
240218334Speter
240318334Speter	  emit_insn (pat);
240418334Speter
240518334Speter	  return temp;
240618334Speter	}
240718334Speter      else
240818334Speter	delete_insns_since (last);
240918334Speter    }
241018334Speter
241118334Speter  /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
241218334Speter
241318334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
241418334Speter    for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
241518334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
241618334Speter      {
241718334Speter	if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
241818334Speter	  {
241918334Speter	    rtx xop0 = op0;
242018334Speter
242118334Speter	    /* For certain operations, we need not actually extend
242218334Speter	       the narrow operand, as long as we will truncate the
242318334Speter	       results to the same narrowness.  */
242418334Speter
242518334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
242618334Speter				  (unoptab == neg_optab
242718334Speter				   || unoptab == one_cmpl_optab)
242818334Speter				  && class == MODE_INT);
242918334Speter
243018334Speter	    temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
243118334Speter				unsignedp);
243218334Speter
243318334Speter	    if (temp)
243418334Speter	      {
243518334Speter		if (class != MODE_INT)
243618334Speter		  {
243718334Speter		    if (target == 0)
243818334Speter		      target = gen_reg_rtx (mode);
243918334Speter		    convert_move (target, temp, 0);
244018334Speter		    return target;
244118334Speter		  }
244218334Speter		else
244318334Speter		  return gen_lowpart (mode, temp);
244418334Speter	      }
244518334Speter	    else
244618334Speter	      delete_insns_since (last);
244718334Speter	  }
244818334Speter      }
244918334Speter
245018334Speter  /* These can be done a word at a time.  */
245118334Speter  if (unoptab == one_cmpl_optab
245218334Speter      && class == MODE_INT
245318334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
245418334Speter      && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
245518334Speter    {
245618334Speter      int i;
245718334Speter      rtx insns;
245818334Speter
245918334Speter      if (target == 0 || target == op0)
246018334Speter	target = gen_reg_rtx (mode);
246118334Speter
246218334Speter      start_sequence ();
246318334Speter
246418334Speter      /* Do the actual arithmetic.  */
246518334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
246618334Speter	{
246718334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
246818334Speter	  rtx x = expand_unop (word_mode, unoptab,
246918334Speter			       operand_subword_force (op0, i, mode),
247018334Speter			       target_piece, unsignedp);
247190075Sobrien
247218334Speter	  if (target_piece != x)
247318334Speter	    emit_move_insn (target_piece, x);
247418334Speter	}
247518334Speter
247618334Speter      insns = get_insns ();
247718334Speter      end_sequence ();
247818334Speter
247918334Speter      emit_no_conflict_block (insns, target, op0, NULL_RTX,
248050397Sobrien			      gen_rtx_fmt_e (unoptab->code, mode,
248150397Sobrien					     copy_rtx (op0)));
248218334Speter      return target;
248318334Speter    }
248418334Speter
248518334Speter  /* Open-code the complex negation operation.  */
248690075Sobrien  else if (unoptab->code == NEG
248718334Speter	   && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT))
248818334Speter    {
248918334Speter      rtx target_piece;
249018334Speter      rtx x;
249118334Speter      rtx seq;
249218334Speter
249318334Speter      /* Find the correct mode for the real and imaginary parts */
2494117395Skan      enum machine_mode submode = GET_MODE_INNER (mode);
249518334Speter
249618334Speter      if (submode == BLKmode)
249718334Speter	abort ();
249818334Speter
249918334Speter      if (target == 0)
250018334Speter	target = gen_reg_rtx (mode);
250118334Speter
250218334Speter      start_sequence ();
250318334Speter
250418334Speter      target_piece = gen_imagpart (submode, target);
250518334Speter      x = expand_unop (submode, unoptab,
250618334Speter		       gen_imagpart (submode, op0),
250718334Speter		       target_piece, unsignedp);
250818334Speter      if (target_piece != x)
250918334Speter	emit_move_insn (target_piece, x);
251018334Speter
251118334Speter      target_piece = gen_realpart (submode, target);
251218334Speter      x = expand_unop (submode, unoptab,
251318334Speter		       gen_realpart (submode, op0),
251418334Speter		       target_piece, unsignedp);
251518334Speter      if (target_piece != x)
251618334Speter	emit_move_insn (target_piece, x);
251718334Speter
251818334Speter      seq = get_insns ();
251918334Speter      end_sequence ();
252018334Speter
252118334Speter      emit_no_conflict_block (seq, target, op0, 0,
252250397Sobrien			      gen_rtx_fmt_e (unoptab->code, mode,
252350397Sobrien					     copy_rtx (op0)));
252418334Speter      return target;
252518334Speter    }
252618334Speter
252718334Speter  /* Now try a library call in this mode.  */
252818334Speter  if (unoptab->handlers[(int) mode].libfunc)
252918334Speter    {
253018334Speter      rtx insns;
253118334Speter      rtx value;
253218334Speter
253318334Speter      start_sequence ();
253418334Speter
253518334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
253618334Speter	 if the libcall is cse'd or moved.  */
253718334Speter      value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
253890075Sobrien				       NULL_RTX, LCT_CONST, mode, 1, op0, mode);
253918334Speter      insns = get_insns ();
254018334Speter      end_sequence ();
254118334Speter
254218334Speter      target = gen_reg_rtx (mode);
254318334Speter      emit_libcall_block (insns, target, value,
254450397Sobrien			  gen_rtx_fmt_e (unoptab->code, mode, op0));
254518334Speter
254618334Speter      return target;
254718334Speter    }
254818334Speter
2549117395Skan  if (class == MODE_VECTOR_FLOAT || class == MODE_VECTOR_INT)
2550117395Skan    return expand_vector_unop (mode, unoptab, op0, target, unsignedp);
2551117395Skan
255218334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
255318334Speter
255418334Speter  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
255518334Speter    {
255618334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
255718334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
255818334Speter	{
255918334Speter	  if ((unoptab->handlers[(int) wider_mode].insn_code
256018334Speter	       != CODE_FOR_nothing)
256118334Speter	      || unoptab->handlers[(int) wider_mode].libfunc)
256218334Speter	    {
256318334Speter	      rtx xop0 = op0;
256418334Speter
256518334Speter	      /* For certain operations, we need not actually extend
256618334Speter		 the narrow operand, as long as we will truncate the
256718334Speter		 results to the same narrowness.  */
256818334Speter
256918334Speter	      xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
257018334Speter				    (unoptab == neg_optab
257118334Speter				     || unoptab == one_cmpl_optab)
257218334Speter				    && class == MODE_INT);
257318334Speter
257418334Speter	      temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
257518334Speter				  unsignedp);
257618334Speter
257718334Speter	      if (temp)
257818334Speter		{
257918334Speter		  if (class != MODE_INT)
258018334Speter		    {
258118334Speter		      if (target == 0)
258218334Speter			target = gen_reg_rtx (mode);
258318334Speter		      convert_move (target, temp, 0);
258418334Speter		      return target;
258518334Speter		    }
258618334Speter		  else
258718334Speter		    return gen_lowpart (mode, temp);
258818334Speter		}
258918334Speter	      else
259018334Speter		delete_insns_since (last);
259118334Speter	    }
259218334Speter	}
259318334Speter    }
259418334Speter
259518334Speter  /* If there is no negate operation, try doing a subtract from zero.
259618334Speter     The US Software GOFAST library needs this.  */
259790075Sobrien  if (unoptab->code == NEG)
259818334Speter    {
259918334Speter      rtx temp;
260090075Sobrien      temp = expand_binop (mode,
260190075Sobrien                           unoptab == negv_optab ? subv_optab : sub_optab,
260290075Sobrien                           CONST0_RTX (mode), op0,
260390075Sobrien                           target, unsignedp, OPTAB_LIB_WIDEN);
260418334Speter      if (temp)
260518334Speter	return temp;
260618334Speter    }
260718334Speter
260818334Speter  return 0;
260918334Speter}
261018334Speter
261118334Speter/* Emit code to compute the absolute value of OP0, with result to
261218334Speter   TARGET if convenient.  (TARGET may be 0.)  The return value says
261318334Speter   where the result actually is to be found.
261418334Speter
261518334Speter   MODE is the mode of the operand; the mode of the result is
261618334Speter   different but can be deduced from MODE.
261718334Speter
261852284Sobrien */
261918334Speter
262018334Speterrtx
262190075Sobrienexpand_abs (mode, op0, target, result_unsignedp, safe)
262218334Speter     enum machine_mode mode;
262318334Speter     rtx op0;
262418334Speter     rtx target;
262590075Sobrien     int result_unsignedp;
262618334Speter     int safe;
262718334Speter{
262818334Speter  rtx temp, op1;
262918334Speter
263090075Sobrien  if (! flag_trapv)
263190075Sobrien    result_unsignedp = 1;
263290075Sobrien
263318334Speter  /* First try to do it with a special abs instruction.  */
263490075Sobrien  temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab,
263590075Sobrien                      op0, target, 0);
263618334Speter  if (temp != 0)
263718334Speter    return temp;
263818334Speter
263990075Sobrien  /* If we have a MAX insn, we can do this as MAX (x, -x).  */
264090075Sobrien  if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
264190075Sobrien    {
264290075Sobrien      rtx last = get_last_insn ();
264390075Sobrien
264490075Sobrien      temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0);
264590075Sobrien      if (temp != 0)
264690075Sobrien	temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
264790075Sobrien			     OPTAB_WIDEN);
264890075Sobrien
264990075Sobrien      if (temp != 0)
265090075Sobrien	return temp;
265190075Sobrien
265290075Sobrien      delete_insns_since (last);
265390075Sobrien    }
265490075Sobrien
265518334Speter  /* If this machine has expensive jumps, we can do integer absolute
265618334Speter     value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
265718334Speter     where W is the width of MODE.  */
265818334Speter
265918334Speter  if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
266018334Speter    {
266118334Speter      rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
266218334Speter				   size_int (GET_MODE_BITSIZE (mode) - 1),
266318334Speter				   NULL_RTX, 0);
266418334Speter
266518334Speter      temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
266618334Speter			   OPTAB_LIB_WIDEN);
266718334Speter      if (temp != 0)
266890075Sobrien	temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab,
266990075Sobrien                             temp, extended, target, 0, OPTAB_LIB_WIDEN);
267018334Speter
267118334Speter      if (temp != 0)
267218334Speter	return temp;
267318334Speter    }
267418334Speter
267518334Speter  /* If that does not win, use conditional jump and negate.  */
267650397Sobrien
267750397Sobrien  /* It is safe to use the target if it is the same
267850397Sobrien     as the source if this is also a pseudo register */
267950397Sobrien  if (op0 == target && GET_CODE (op0) == REG
268050397Sobrien      && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
268150397Sobrien    safe = 1;
268250397Sobrien
268318334Speter  op1 = gen_label_rtx ();
268418334Speter  if (target == 0 || ! safe
268518334Speter      || GET_MODE (target) != mode
268618334Speter      || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
268718334Speter      || (GET_CODE (target) == REG
268818334Speter	  && REGNO (target) < FIRST_PSEUDO_REGISTER))
268918334Speter    target = gen_reg_rtx (mode);
269018334Speter
269118334Speter  emit_move_insn (target, op0);
269218334Speter  NO_DEFER_POP;
269318334Speter
269418334Speter  /* If this mode is an integer too wide to compare properly,
269518334Speter     compare word by word.  Rely on CSE to optimize constant cases.  */
269690075Sobrien  if (GET_MODE_CLASS (mode) == MODE_INT
269790075Sobrien      && ! can_compare_p (GE, mode, ccp_jump))
269818334Speter    do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
269918334Speter				  NULL_RTX, op1);
270018334Speter  else
270190075Sobrien    do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
270290075Sobrien			     NULL_RTX, NULL_RTX, op1);
270318334Speter
270490075Sobrien  op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
270590075Sobrien                     target, target, 0);
270618334Speter  if (op0 != target)
270718334Speter    emit_move_insn (target, op0);
270818334Speter  emit_label (op1);
270918334Speter  OK_DEFER_POP;
271018334Speter  return target;
271118334Speter}
271218334Speter
271318334Speter/* Emit code to compute the absolute value of OP0, with result to
271418334Speter   TARGET if convenient.  (TARGET may be 0.)  The return value says
271518334Speter   where the result actually is to be found.
271618334Speter
271718334Speter   MODE is the mode of the operand; the mode of the result is
271818334Speter   different but can be deduced from MODE.
271918334Speter
272018334Speter   UNSIGNEDP is relevant for complex integer modes.  */
272118334Speter
272218334Speterrtx
272318334Speterexpand_complex_abs (mode, op0, target, unsignedp)
272418334Speter     enum machine_mode mode;
272518334Speter     rtx op0;
272618334Speter     rtx target;
272718334Speter     int unsignedp;
272818334Speter{
272918334Speter  enum mode_class class = GET_MODE_CLASS (mode);
273018334Speter  enum machine_mode wider_mode;
273190075Sobrien  rtx temp;
273218334Speter  rtx entry_last = get_last_insn ();
273318334Speter  rtx last;
273418334Speter  rtx pat;
273590075Sobrien  optab this_abs_optab;
273618334Speter
273718334Speter  /* Find the correct mode for the real and imaginary parts.  */
2738117395Skan  enum machine_mode submode = GET_MODE_INNER (mode);
273918334Speter
274018334Speter  if (submode == BLKmode)
274118334Speter    abort ();
274218334Speter
274318334Speter  op0 = protect_from_queue (op0, 0);
274418334Speter
274518334Speter  if (flag_force_mem)
274618334Speter    {
274718334Speter      op0 = force_not_mem (op0);
274818334Speter    }
274918334Speter
275018334Speter  last = get_last_insn ();
275118334Speter
275218334Speter  if (target)
275318334Speter    target = protect_from_queue (target, 1);
275418334Speter
275590075Sobrien  this_abs_optab = ! unsignedp && flag_trapv
275690075Sobrien                   && (GET_MODE_CLASS(mode) == MODE_INT)
275790075Sobrien                   ? absv_optab : abs_optab;
275890075Sobrien
275990075Sobrien  if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
276018334Speter    {
276190075Sobrien      int icode = (int) this_abs_optab->handlers[(int) mode].insn_code;
276290075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
276318334Speter      rtx xop0 = op0;
276418334Speter
276518334Speter      if (target)
276618334Speter	temp = target;
276718334Speter      else
276818334Speter	temp = gen_reg_rtx (submode);
276918334Speter
277018334Speter      if (GET_MODE (xop0) != VOIDmode
277118334Speter	  && GET_MODE (xop0) != mode0)
277218334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
277318334Speter
277418334Speter      /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
277518334Speter
277690075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
277718334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
277818334Speter
277990075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (temp, submode))
278018334Speter	temp = gen_reg_rtx (submode);
278118334Speter
278218334Speter      pat = GEN_FCN (icode) (temp, xop0);
278318334Speter      if (pat)
278418334Speter	{
2785117395Skan	  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
278690075Sobrien	      && ! add_equal_note (pat, temp, this_abs_optab->code, xop0,
278790075Sobrien				   NULL_RTX))
278818334Speter	    {
278918334Speter	      delete_insns_since (last);
279090075Sobrien	      return expand_unop (mode, this_abs_optab, op0, NULL_RTX,
279190075Sobrien				  unsignedp);
279218334Speter	    }
279318334Speter
279418334Speter	  emit_insn (pat);
279518334Speter
279618334Speter	  return temp;
279718334Speter	}
279818334Speter      else
279918334Speter	delete_insns_since (last);
280018334Speter    }
280118334Speter
280218334Speter  /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
280318334Speter
280418334Speter  for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
280518334Speter       wider_mode = GET_MODE_WIDER_MODE (wider_mode))
280618334Speter    {
280790075Sobrien      if (this_abs_optab->handlers[(int) wider_mode].insn_code
280890075Sobrien	  != CODE_FOR_nothing)
280918334Speter	{
281018334Speter	  rtx xop0 = op0;
281118334Speter
281218334Speter	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
281318334Speter	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
281418334Speter
281518334Speter	  if (temp)
281618334Speter	    {
281718334Speter	      if (class != MODE_COMPLEX_INT)
281818334Speter		{
281918334Speter		  if (target == 0)
282018334Speter		    target = gen_reg_rtx (submode);
282118334Speter		  convert_move (target, temp, 0);
282218334Speter		  return target;
282318334Speter		}
282418334Speter	      else
282518334Speter		return gen_lowpart (submode, temp);
282618334Speter	    }
282718334Speter	  else
282818334Speter	    delete_insns_since (last);
282918334Speter	}
283018334Speter    }
283118334Speter
283218334Speter  /* Open-code the complex absolute-value operation
283318334Speter     if we can open-code sqrt.  Otherwise it's not worth while.  */
283490075Sobrien  if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
283590075Sobrien      && ! flag_trapv)
283618334Speter    {
283718334Speter      rtx real, imag, total;
283818334Speter
283918334Speter      real = gen_realpart (submode, op0);
284018334Speter      imag = gen_imagpart (submode, op0);
284118334Speter
284218334Speter      /* Square both parts.  */
284318334Speter      real = expand_mult (submode, real, real, NULL_RTX, 0);
284418334Speter      imag = expand_mult (submode, imag, imag, NULL_RTX, 0);
284518334Speter
284618334Speter      /* Sum the parts.  */
284718334Speter      total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
284818334Speter			    0, OPTAB_LIB_WIDEN);
284918334Speter
285018334Speter      /* Get sqrt in TARGET.  Set TARGET to where the result is.  */
285118334Speter      target = expand_unop (submode, sqrt_optab, total, target, 0);
285218334Speter      if (target == 0)
285318334Speter	delete_insns_since (last);
285418334Speter      else
285518334Speter	return target;
285618334Speter    }
285718334Speter
285818334Speter  /* Now try a library call in this mode.  */
285990075Sobrien  if (this_abs_optab->handlers[(int) mode].libfunc)
286018334Speter    {
286118334Speter      rtx insns;
286218334Speter      rtx value;
286318334Speter
286418334Speter      start_sequence ();
286518334Speter
286618334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
286718334Speter	 if the libcall is cse'd or moved.  */
286818334Speter      value = emit_library_call_value (abs_optab->handlers[(int) mode].libfunc,
286990075Sobrien				       NULL_RTX, LCT_CONST, submode, 1, op0, mode);
287018334Speter      insns = get_insns ();
287118334Speter      end_sequence ();
287218334Speter
287318334Speter      target = gen_reg_rtx (submode);
287418334Speter      emit_libcall_block (insns, target, value,
287590075Sobrien			  gen_rtx_fmt_e (this_abs_optab->code, mode, op0));
287618334Speter
287718334Speter      return target;
287818334Speter    }
287918334Speter
288018334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
288118334Speter
288218334Speter  for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
288318334Speter       wider_mode = GET_MODE_WIDER_MODE (wider_mode))
288418334Speter    {
288590075Sobrien      if ((this_abs_optab->handlers[(int) wider_mode].insn_code
288618334Speter	   != CODE_FOR_nothing)
288790075Sobrien	  || this_abs_optab->handlers[(int) wider_mode].libfunc)
288818334Speter	{
288918334Speter	  rtx xop0 = op0;
289018334Speter
289118334Speter	  xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
289218334Speter
289318334Speter	  temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
289418334Speter
289518334Speter	  if (temp)
289618334Speter	    {
289718334Speter	      if (class != MODE_COMPLEX_INT)
289818334Speter		{
289918334Speter		  if (target == 0)
290018334Speter		    target = gen_reg_rtx (submode);
290118334Speter		  convert_move (target, temp, 0);
290218334Speter		  return target;
290318334Speter		}
290418334Speter	      else
290518334Speter		return gen_lowpart (submode, temp);
290618334Speter	    }
290718334Speter	  else
290818334Speter	    delete_insns_since (last);
290918334Speter	}
291018334Speter    }
291118334Speter
291218334Speter  delete_insns_since (entry_last);
291318334Speter  return 0;
291418334Speter}
291518334Speter
291618334Speter/* Generate an instruction whose insn-code is INSN_CODE,
291718334Speter   with two operands: an output TARGET and an input OP0.
291818334Speter   TARGET *must* be nonzero, and the output is always stored there.
291918334Speter   CODE is an rtx code such that (CODE OP0) is an rtx that describes
292018334Speter   the value that is stored into TARGET.  */
292118334Speter
292218334Spetervoid
292318334Speteremit_unop_insn (icode, target, op0, code)
292418334Speter     int icode;
292518334Speter     rtx target;
292618334Speter     rtx op0;
292718334Speter     enum rtx_code code;
292818334Speter{
292990075Sobrien  rtx temp;
293090075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
293118334Speter  rtx pat;
293218334Speter
293318334Speter  temp = target = protect_from_queue (target, 1);
293418334Speter
293518334Speter  op0 = protect_from_queue (op0, 0);
293618334Speter
293750397Sobrien  /* Sign and zero extension from memory is often done specially on
293850397Sobrien     RISC machines, so forcing into a register here can pessimize
293950397Sobrien     code.  */
294050397Sobrien  if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND)
294118334Speter    op0 = force_not_mem (op0);
294218334Speter
294318334Speter  /* Now, if insn does not accept our operands, put them into pseudos.  */
294418334Speter
294590075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
294618334Speter    op0 = copy_to_mode_reg (mode0, op0);
294718334Speter
294890075Sobrien  if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp))
294918334Speter      || (flag_force_mem && GET_CODE (temp) == MEM))
295018334Speter    temp = gen_reg_rtx (GET_MODE (temp));
295118334Speter
295218334Speter  pat = GEN_FCN (icode) (temp, op0);
295318334Speter
2954117395Skan  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN)
295518334Speter    add_equal_note (pat, temp, code, op0, NULL_RTX);
295618334Speter
295718334Speter  emit_insn (pat);
295818334Speter
295918334Speter  if (temp != target)
296018334Speter    emit_move_insn (target, temp);
296118334Speter}
296218334Speter
296318334Speter/* Emit code to perform a series of operations on a multi-word quantity, one
296418334Speter   word at a time.
296518334Speter
296618334Speter   Such a block is preceded by a CLOBBER of the output, consists of multiple
296718334Speter   insns, each setting one word of the output, and followed by a SET copying
296818334Speter   the output to itself.
296918334Speter
297018334Speter   Each of the insns setting words of the output receives a REG_NO_CONFLICT
297118334Speter   note indicating that it doesn't conflict with the (also multi-word)
297218334Speter   inputs.  The entire block is surrounded by REG_LIBCALL and REG_RETVAL
297318334Speter   notes.
297418334Speter
297518334Speter   INSNS is a block of code generated to perform the operation, not including
297618334Speter   the CLOBBER and final copy.  All insns that compute intermediate values
297718334Speter   are first emitted, followed by the block as described above.
297818334Speter
297918334Speter   TARGET, OP0, and OP1 are the output and inputs of the operations,
298018334Speter   respectively.  OP1 may be zero for a unary operation.
298118334Speter
2982117395Skan   EQUIV, if nonzero, is an expression to be placed into a REG_EQUAL note
298318334Speter   on the last insn.
298418334Speter
298518334Speter   If TARGET is not a register, INSNS is simply emitted with no special
298618334Speter   processing.  Likewise if anything in INSNS is not an INSN or if
298718334Speter   there is a libcall block inside INSNS.
298818334Speter
298918334Speter   The final insn emitted is returned.  */
299018334Speter
299118334Speterrtx
299218334Speteremit_no_conflict_block (insns, target, op0, op1, equiv)
299318334Speter     rtx insns;
299418334Speter     rtx target;
299518334Speter     rtx op0, op1;
299618334Speter     rtx equiv;
299718334Speter{
299818334Speter  rtx prev, next, first, last, insn;
299918334Speter
300018334Speter  if (GET_CODE (target) != REG || reload_in_progress)
3001117395Skan    return emit_insn (insns);
300218334Speter  else
300318334Speter    for (insn = insns; insn; insn = NEXT_INSN (insn))
300418334Speter      if (GET_CODE (insn) != INSN
300518334Speter	  || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
3006117395Skan	return emit_insn (insns);
300718334Speter
300818334Speter  /* First emit all insns that do not store into words of the output and remove
300918334Speter     these from the list.  */
301018334Speter  for (insn = insns; insn; insn = next)
301118334Speter    {
301296263Sobrien      rtx set = 0, note;
301318334Speter      int i;
301418334Speter
301518334Speter      next = NEXT_INSN (insn);
301618334Speter
301796263Sobrien      /* Some ports (cris) create an libcall regions at their own.  We must
301896263Sobrien	 avoid any potential nesting of LIBCALLs.  */
301996263Sobrien      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
302096263Sobrien	remove_note (insn, note);
302196263Sobrien      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
302296263Sobrien	remove_note (insn, note);
302396263Sobrien
302490075Sobrien      if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE
302590075Sobrien	  || GET_CODE (PATTERN (insn)) == CLOBBER)
302618334Speter	set = PATTERN (insn);
302718334Speter      else if (GET_CODE (PATTERN (insn)) == PARALLEL)
302818334Speter	{
302918334Speter	  for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
303018334Speter	    if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
303118334Speter	      {
303218334Speter		set = XVECEXP (PATTERN (insn), 0, i);
303318334Speter		break;
303418334Speter	      }
303518334Speter	}
303618334Speter
303718334Speter      if (set == 0)
303818334Speter	abort ();
303918334Speter
304018334Speter      if (! reg_overlap_mentioned_p (target, SET_DEST (set)))
304118334Speter	{
304218334Speter	  if (PREV_INSN (insn))
304318334Speter	    NEXT_INSN (PREV_INSN (insn)) = next;
304418334Speter	  else
304518334Speter	    insns = next;
304618334Speter
304718334Speter	  if (next)
304818334Speter	    PREV_INSN (next) = PREV_INSN (insn);
304918334Speter
305018334Speter	  add_insn (insn);
305118334Speter	}
305218334Speter    }
305318334Speter
305418334Speter  prev = get_last_insn ();
305518334Speter
305618334Speter  /* Now write the CLOBBER of the output, followed by the setting of each
305718334Speter     of the words, followed by the final copy.  */
305818334Speter  if (target != op0 && target != op1)
305950397Sobrien    emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
306018334Speter
306118334Speter  for (insn = insns; insn; insn = next)
306218334Speter    {
306318334Speter      next = NEXT_INSN (insn);
306418334Speter      add_insn (insn);
306518334Speter
306618334Speter      if (op1 && GET_CODE (op1) == REG)
306750397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
306850397Sobrien					      REG_NOTES (insn));
306918334Speter
307018334Speter      if (op0 && GET_CODE (op0) == REG)
307150397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
307250397Sobrien					      REG_NOTES (insn));
307318334Speter    }
307418334Speter
307518334Speter  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
307618334Speter      != CODE_FOR_nothing)
307718334Speter    {
307818334Speter      last = emit_move_insn (target, target);
307918334Speter      if (equiv)
308052284Sobrien	set_unique_reg_note (last, REG_EQUAL, equiv);
308118334Speter    }
308218334Speter  else
308390075Sobrien    {
308490075Sobrien      last = get_last_insn ();
308518334Speter
308690075Sobrien      /* Remove any existing REG_EQUAL note from "last", or else it will
308790075Sobrien	 be mistaken for a note referring to the full contents of the
308890075Sobrien	 alleged libcall value when found together with the REG_RETVAL
308990075Sobrien	 note added below.  An existing note can come from an insn
309090075Sobrien	 expansion at "last".  */
309190075Sobrien      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
309290075Sobrien    }
309390075Sobrien
309418334Speter  if (prev == 0)
309518334Speter    first = get_insns ();
309618334Speter  else
309718334Speter    first = NEXT_INSN (prev);
309818334Speter
309918334Speter  /* Encapsulate the block so it gets manipulated as a unit.  */
310050397Sobrien  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
310150397Sobrien					 REG_NOTES (first));
310250397Sobrien  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
310318334Speter
310418334Speter  return last;
310518334Speter}
310618334Speter
310718334Speter/* Emit code to make a call to a constant function or a library call.
310818334Speter
310918334Speter   INSNS is a list containing all insns emitted in the call.
311018334Speter   These insns leave the result in RESULT.  Our block is to copy RESULT
311118334Speter   to TARGET, which is logically equivalent to EQUIV.
311218334Speter
311318334Speter   We first emit any insns that set a pseudo on the assumption that these are
311418334Speter   loading constants into registers; doing so allows them to be safely cse'ed
311518334Speter   between blocks.  Then we emit all the other insns in the block, followed by
311618334Speter   an insn to move RESULT to TARGET.  This last insn will have a REQ_EQUAL
311718334Speter   note with an operand of EQUIV.
311818334Speter
311918334Speter   Moving assignments to pseudos outside of the block is done to improve
312018334Speter   the generated code, but is not required to generate correct code,
312118334Speter   hence being unable to move an assignment is not grounds for not making
312218334Speter   a libcall block.  There are two reasons why it is safe to leave these
312318334Speter   insns inside the block: First, we know that these pseudos cannot be
312418334Speter   used in generated RTL outside the block since they are created for
312518334Speter   temporary purposes within the block.  Second, CSE will not record the
312618334Speter   values of anything set inside a libcall block, so we know they must
312718334Speter   be dead at the end of the block.
312818334Speter
312918334Speter   Except for the first group of insns (the ones setting pseudos), the
313018334Speter   block is delimited by REG_RETVAL and REG_LIBCALL notes.  */
313118334Speter
313218334Spetervoid
313318334Speteremit_libcall_block (insns, target, result, equiv)
313418334Speter     rtx insns;
313518334Speter     rtx target;
313618334Speter     rtx result;
313718334Speter     rtx equiv;
313818334Speter{
313970635Sobrien  rtx final_dest = target;
314018334Speter  rtx prev, next, first, last, insn;
314118334Speter
314270635Sobrien  /* If this is a reg with REG_USERVAR_P set, then it could possibly turn
314370635Sobrien     into a MEM later.  Protect the libcall block from this change.  */
314470635Sobrien  if (! REG_P (target) || REG_USERVAR_P (target))
314570635Sobrien    target = gen_reg_rtx (GET_MODE (target));
314690075Sobrien
314790075Sobrien  /* If we're using non-call exceptions, a libcall corresponding to an
314890075Sobrien     operation that may trap may also trap.  */
314990075Sobrien  if (flag_non_call_exceptions && may_trap_p (equiv))
315090075Sobrien    {
315190075Sobrien      for (insn = insns; insn; insn = NEXT_INSN (insn))
315290075Sobrien	if (GET_CODE (insn) == CALL_INSN)
315390075Sobrien	  {
315490075Sobrien	    rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
315590075Sobrien
315690075Sobrien	    if (note != 0 && INTVAL (XEXP (note, 0)) <= 0)
315790075Sobrien	      remove_note (insn, note);
315890075Sobrien	  }
315990075Sobrien    }
316090075Sobrien  else
316152284Sobrien  /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION
316290075Sobrien     reg note to indicate that this call cannot throw or execute a nonlocal
316390075Sobrien     goto (unless there is already a REG_EH_REGION note, in which case
316490075Sobrien     we update it).  */
316590075Sobrien    for (insn = insns; insn; insn = NEXT_INSN (insn))
316652284Sobrien      if (GET_CODE (insn) == CALL_INSN)
316790075Sobrien	{
316890075Sobrien	  rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
316990075Sobrien
317090075Sobrien	  if (note != 0)
317190075Sobrien	    XEXP (note, 0) = GEN_INT (-1);
317290075Sobrien	  else
317390075Sobrien	    REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1),
317490075Sobrien						  REG_NOTES (insn));
317590075Sobrien	}
317652284Sobrien
317718334Speter  /* First emit all insns that set pseudos.  Remove them from the list as
317818334Speter     we go.  Avoid insns that set pseudos which were referenced in previous
317918334Speter     insns.  These can be generated by move_by_pieces, for example,
318018334Speter     to update an address.  Similarly, avoid insns that reference things
318118334Speter     set in previous insns.  */
318218334Speter
318318334Speter  for (insn = insns; insn; insn = next)
318418334Speter    {
318518334Speter      rtx set = single_set (insn);
318696263Sobrien      rtx note;
318718334Speter
318896263Sobrien      /* Some ports (cris) create an libcall regions at their own.  We must
318996263Sobrien	 avoid any potential nesting of LIBCALLs.  */
319096263Sobrien      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
319196263Sobrien	remove_note (insn, note);
319296263Sobrien      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
319396263Sobrien	remove_note (insn, note);
319496263Sobrien
319518334Speter      next = NEXT_INSN (insn);
319618334Speter
319718334Speter      if (set != 0 && GET_CODE (SET_DEST (set)) == REG
319818334Speter	  && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
319918334Speter	  && (insn == insns
320090075Sobrien	      || ((! INSN_P(insns)
320190075Sobrien		   || ! reg_mentioned_p (SET_DEST (set), PATTERN (insns)))
320218334Speter		  && ! reg_used_between_p (SET_DEST (set), insns, insn)
320318334Speter		  && ! modified_in_p (SET_SRC (set), insns)
320418334Speter		  && ! modified_between_p (SET_SRC (set), insns, insn))))
320518334Speter	{
320618334Speter	  if (PREV_INSN (insn))
320718334Speter	    NEXT_INSN (PREV_INSN (insn)) = next;
320818334Speter	  else
320918334Speter	    insns = next;
321018334Speter
321118334Speter	  if (next)
321218334Speter	    PREV_INSN (next) = PREV_INSN (insn);
321318334Speter
321418334Speter	  add_insn (insn);
321518334Speter	}
321618334Speter    }
321718334Speter
321818334Speter  prev = get_last_insn ();
321918334Speter
322018334Speter  /* Write the remaining insns followed by the final copy.  */
322118334Speter
322218334Speter  for (insn = insns; insn; insn = next)
322318334Speter    {
322418334Speter      next = NEXT_INSN (insn);
322518334Speter
322618334Speter      add_insn (insn);
322718334Speter    }
322818334Speter
322918334Speter  last = emit_move_insn (target, result);
323050397Sobrien  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
323150397Sobrien      != CODE_FOR_nothing)
323252284Sobrien    set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
323390075Sobrien  else
323490075Sobrien    {
323590075Sobrien      /* Remove any existing REG_EQUAL note from "last", or else it will
323690075Sobrien	 be mistaken for a note referring to the full contents of the
323790075Sobrien	 libcall value when found together with the REG_RETVAL note added
323890075Sobrien	 below.  An existing note can come from an insn expansion at
323990075Sobrien	 "last".  */
324090075Sobrien      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
324190075Sobrien    }
324218334Speter
324370635Sobrien  if (final_dest != target)
324470635Sobrien    emit_move_insn (final_dest, target);
324570635Sobrien
324618334Speter  if (prev == 0)
324718334Speter    first = get_insns ();
324818334Speter  else
324918334Speter    first = NEXT_INSN (prev);
325018334Speter
325118334Speter  /* Encapsulate the block so it gets manipulated as a unit.  */
325290075Sobrien  if (!flag_non_call_exceptions || !may_trap_p (equiv))
325390075Sobrien    {
3254110611Skan      /* We can't attach the REG_LIBCALL and REG_RETVAL notes
3255110611Skan	 when the encapsulated region would not be in one basic block,
3256110611Skan	 i.e. when there is a control_flow_insn_p insn between FIRST and LAST.
3257110611Skan       */
3258110611Skan      bool attach_libcall_retval_notes = true;
3259110611Skan      next = NEXT_INSN (last);
3260110611Skan      for (insn = first; insn != next; insn = NEXT_INSN (insn))
3261110611Skan	if (control_flow_insn_p (insn))
3262110611Skan	  {
3263110611Skan	    attach_libcall_retval_notes = false;
3264110611Skan	    break;
3265110611Skan	  }
3266110611Skan
3267110611Skan      if (attach_libcall_retval_notes)
3268110611Skan	{
3269110611Skan	  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
3270110611Skan						 REG_NOTES (first));
3271110611Skan	  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
3272110611Skan						REG_NOTES (last));
3273110611Skan	}
327490075Sobrien    }
327518334Speter}
327618334Speter
327718334Speter/* Generate code to store zero in X.  */
327818334Speter
327918334Spetervoid
328018334Speteremit_clr_insn (x)
328118334Speter     rtx x;
328218334Speter{
328318334Speter  emit_move_insn (x, const0_rtx);
328418334Speter}
328518334Speter
328618334Speter/* Generate code to store 1 in X
328718334Speter   assuming it contains zero beforehand.  */
328818334Speter
328918334Spetervoid
329018334Speteremit_0_to_1_insn (x)
329118334Speter     rtx x;
329218334Speter{
329318334Speter  emit_move_insn (x, const1_rtx);
329418334Speter}
329518334Speter
329690075Sobrien/* Nonzero if we can perform a comparison of mode MODE straightforwardly.
329790075Sobrien   PURPOSE describes how this comparison will be used.  CODE is the rtx
329890075Sobrien   comparison code we will be using.
329918334Speter
330090075Sobrien   ??? Actually, CODE is slightly weaker than that.  A target is still
330190075Sobrien   required to implement all of the normal bcc operations, but not
330290075Sobrien   required to implement all (or any) of the unordered bcc operations.  */
330390075Sobrien
330490075Sobrienint
330590075Sobriencan_compare_p (code, mode, purpose)
330690075Sobrien     enum rtx_code code;
330790075Sobrien     enum machine_mode mode;
330890075Sobrien     enum can_compare_purpose purpose;
330990075Sobrien{
331090075Sobrien  do
331190075Sobrien    {
3312117395Skan      if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
331390075Sobrien	{
331490075Sobrien	  if (purpose == ccp_jump)
3315117395Skan	    return bcc_gen_fctn[(int) code] != NULL;
331690075Sobrien	  else if (purpose == ccp_store_flag)
3317117395Skan	    return setcc_gen_code[(int) code] != CODE_FOR_nothing;
331890075Sobrien	  else
331990075Sobrien	    /* There's only one cmov entry point, and it's allowed to fail.  */
332090075Sobrien	    return 1;
332190075Sobrien	}
332290075Sobrien      if (purpose == ccp_jump
3323117395Skan	  && cbranch_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
332490075Sobrien	return 1;
332590075Sobrien      if (purpose == ccp_cmov
3326117395Skan	  && cmov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
332790075Sobrien	return 1;
332890075Sobrien      if (purpose == ccp_store_flag
3329117395Skan	  && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
333090075Sobrien	return 1;
333190075Sobrien
333290075Sobrien      mode = GET_MODE_WIDER_MODE (mode);
333390075Sobrien    }
333490075Sobrien  while (mode != VOIDmode);
333590075Sobrien
333690075Sobrien  return 0;
333790075Sobrien}
333890075Sobrien
333990075Sobrien/* This function is called when we are going to emit a compare instruction that
334090075Sobrien   compares the values found in *PX and *PY, using the rtl operator COMPARISON.
334190075Sobrien
334290075Sobrien   *PMODE is the mode of the inputs (in case they are const_int).
334390075Sobrien   *PUNSIGNEDP nonzero says that the operands are unsigned;
334418334Speter   this matters if they need to be widened.
334518334Speter
334690075Sobrien   If they have mode BLKmode, then SIZE specifies the size of both operands.
334718334Speter
334890075Sobrien   This function performs all the setup necessary so that the caller only has
334990075Sobrien   to emit a single comparison insn.  This setup can involve doing a BLKmode
335090075Sobrien   comparison or emitting a library call to perform the comparison if no insn
335190075Sobrien   is available to handle it.
335290075Sobrien   The values which are passed in through pointers can be modified; the caller
335390075Sobrien   should perform the comparison on the modified values.  */
335418334Speter
335590075Sobrienstatic void
335690075Sobrienprepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
335790075Sobrien     rtx *px, *py;
335890075Sobrien     enum rtx_code *pcomparison;
335918334Speter     rtx size;
336090075Sobrien     enum machine_mode *pmode;
336190075Sobrien     int *punsignedp;
336290075Sobrien     enum can_compare_purpose purpose;
336318334Speter{
336490075Sobrien  enum machine_mode mode = *pmode;
336590075Sobrien  rtx x = *px, y = *py;
336690075Sobrien  int unsignedp = *punsignedp;
336718334Speter  enum mode_class class;
336818334Speter
336918334Speter  class = GET_MODE_CLASS (mode);
337018334Speter
337118334Speter  /* They could both be VOIDmode if both args are immediate constants,
337218334Speter     but we should fold that at an earlier stage.
337318334Speter     With no special code here, this will call abort,
337418334Speter     reminding the programmer to implement such folding.  */
337518334Speter
337618334Speter  if (mode != BLKmode && flag_force_mem)
337718334Speter    {
337818334Speter      x = force_not_mem (x);
337918334Speter      y = force_not_mem (y);
338018334Speter    }
338118334Speter
338218334Speter  /* If we are inside an appropriately-short loop and one operand is an
338318334Speter     expensive constant, force it into a register.  */
338490075Sobrien  if (CONSTANT_P (x) && preserve_subexpressions_p ()
338590075Sobrien      && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1))
338618334Speter    x = force_reg (mode, x);
338718334Speter
338890075Sobrien  if (CONSTANT_P (y) && preserve_subexpressions_p ()
338990075Sobrien      && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1))
339018334Speter    y = force_reg (mode, y);
339118334Speter
339252284Sobrien#ifdef HAVE_cc0
339352284Sobrien  /* Abort if we have a non-canonical comparison.  The RTL documentation
339452284Sobrien     states that canonical comparisons are required only for targets which
339552284Sobrien     have cc0.  */
339652284Sobrien  if (CONSTANT_P (x) && ! CONSTANT_P (y))
3397117395Skan    abort ();
339852284Sobrien#endif
339952284Sobrien
340018334Speter  /* Don't let both operands fail to indicate the mode.  */
340118334Speter  if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode)
340218334Speter    x = force_reg (mode, x);
340318334Speter
340418334Speter  /* Handle all BLKmode compares.  */
340518334Speter
340618334Speter  if (mode == BLKmode)
340718334Speter    {
340890075Sobrien      rtx result;
340990075Sobrien      enum machine_mode result_mode;
341090075Sobrien      rtx opalign ATTRIBUTE_UNUSED
341190075Sobrien	= GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
341290075Sobrien
341318334Speter      emit_queue ();
341418334Speter      x = protect_from_queue (x, 0);
341518334Speter      y = protect_from_queue (y, 0);
341618334Speter
341718334Speter      if (size == 0)
341818334Speter	abort ();
341918334Speter#ifdef HAVE_cmpstrqi
342018334Speter      if (HAVE_cmpstrqi
342118334Speter	  && GET_CODE (size) == CONST_INT
342218334Speter	  && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
342318334Speter	{
342490075Sobrien	  result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode;
342590075Sobrien	  result = gen_reg_rtx (result_mode);
342690075Sobrien	  emit_insn (gen_cmpstrqi (result, x, y, size, opalign));
342718334Speter	}
342818334Speter      else
342918334Speter#endif
343018334Speter#ifdef HAVE_cmpstrhi
343118334Speter      if (HAVE_cmpstrhi
343218334Speter	  && GET_CODE (size) == CONST_INT
343318334Speter	  && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
343418334Speter	{
343590075Sobrien	  result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode;
343690075Sobrien	  result = gen_reg_rtx (result_mode);
343790075Sobrien	  emit_insn (gen_cmpstrhi (result, x, y, size, opalign));
343818334Speter	}
343918334Speter      else
344018334Speter#endif
344118334Speter#ifdef HAVE_cmpstrsi
344218334Speter      if (HAVE_cmpstrsi)
344318334Speter	{
344490075Sobrien	  result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
344590075Sobrien	  result = gen_reg_rtx (result_mode);
344618334Speter	  size = protect_from_queue (size, 0);
344718334Speter	  emit_insn (gen_cmpstrsi (result, x, y,
344818334Speter				   convert_to_mode (SImode, size, 1),
344990075Sobrien				   opalign));
345018334Speter	}
345118334Speter      else
345218334Speter#endif
345318334Speter	{
345418334Speter#ifdef TARGET_MEM_FUNCTIONS
3455117395Skan	  result = emit_library_call_value (memcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK,
3456117395Skan					    TYPE_MODE (integer_type_node), 3,
3457117395Skan					    XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
3458117395Skan					    convert_to_mode (TYPE_MODE (sizetype), size,
3459117395Skan							     TREE_UNSIGNED (sizetype)),
3460117395Skan					    TYPE_MODE (sizetype));
346118334Speter#else
3462117395Skan	  result = emit_library_call_value (bcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK,
3463117395Skan					    TYPE_MODE (integer_type_node), 3,
3464117395Skan					    XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
3465117395Skan					    convert_to_mode (TYPE_MODE (integer_type_node),
3466117395Skan							     size,
3467117395Skan							     TREE_UNSIGNED (integer_type_node)),
3468117395Skan					    TYPE_MODE (integer_type_node));
346918334Speter#endif
347050397Sobrien
347190075Sobrien	  result_mode = TYPE_MODE (integer_type_node);
347218334Speter	}
347390075Sobrien      *px = result;
347490075Sobrien      *py = const0_rtx;
347590075Sobrien      *pmode = result_mode;
347618334Speter      return;
347718334Speter    }
347818334Speter
347990075Sobrien  *px = x;
348090075Sobrien  *py = y;
348190075Sobrien  if (can_compare_p (*pcomparison, mode, purpose))
348290075Sobrien    return;
348318334Speter
348418334Speter  /* Handle a lib call just for the mode we are using.  */
348518334Speter
348690075Sobrien  if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
348718334Speter    {
348818334Speter      rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
348950397Sobrien      rtx result;
349050397Sobrien
349118334Speter      /* If we want unsigned, and this mode has a distinct unsigned
349218334Speter	 comparison routine, use that.  */
349318334Speter      if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
349418334Speter	libfunc = ucmp_optab->handlers[(int) mode].libfunc;
349518334Speter
3496117395Skan      result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
3497117395Skan					word_mode, 2, x, mode, y, mode);
349818334Speter
349918334Speter      /* Integer comparison returns a result that must be compared against 1,
350018334Speter	 so that even if we do an unsigned compare afterward,
350118334Speter	 there is still a value that can represent the result "less than".  */
350290075Sobrien      *px = result;
350390075Sobrien      *py = const1_rtx;
350490075Sobrien      *pmode = word_mode;
350518334Speter      return;
350618334Speter    }
350718334Speter
350818334Speter  if (class == MODE_FLOAT)
350990075Sobrien    prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
351018334Speter
351118334Speter  else
351218334Speter    abort ();
351318334Speter}
351418334Speter
351590075Sobrien/* Before emitting an insn with code ICODE, make sure that X, which is going
351690075Sobrien   to be used for operand OPNUM of the insn, is converted from mode MODE to
351790075Sobrien   WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and
351890075Sobrien   that it is accepted by the operand predicate.  Return the new value.  */
351990075Sobrien
352090075Sobrienrtx
352190075Sobrienprepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
352290075Sobrien     int icode;
352390075Sobrien     rtx x;
352490075Sobrien     int opnum;
352590075Sobrien     enum machine_mode mode, wider_mode;
352690075Sobrien     int unsignedp;
352790075Sobrien{
352890075Sobrien  x = protect_from_queue (x, 0);
352990075Sobrien
353090075Sobrien  if (mode != wider_mode)
353190075Sobrien    x = convert_modes (wider_mode, mode, x, unsignedp);
353290075Sobrien
353390075Sobrien  if (! (*insn_data[icode].operand[opnum].predicate)
353490075Sobrien      (x, insn_data[icode].operand[opnum].mode))
3535119256Skan    {
3536119256Skan      if (no_new_pseudos)
3537119256Skan	return NULL_RTX;
3538119256Skan      x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
3539119256Skan    }
3540119256Skan
354190075Sobrien  return x;
354290075Sobrien}
354390075Sobrien
354490075Sobrien/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
354590075Sobrien   we can do the comparison.
354690075Sobrien   The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
354790075Sobrien   be NULL_RTX which indicates that only a comparison is to be generated.  */
354890075Sobrien
354990075Sobrienstatic void
355090075Sobrienemit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
355190075Sobrien     rtx x, y;
355290075Sobrien     enum machine_mode mode;
355390075Sobrien     enum rtx_code comparison;
355490075Sobrien     int unsignedp;
355590075Sobrien     rtx label;
355690075Sobrien{
355790075Sobrien  rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
355890075Sobrien  enum mode_class class = GET_MODE_CLASS (mode);
355990075Sobrien  enum machine_mode wider_mode = mode;
356090075Sobrien
356190075Sobrien  /* Try combined insns first.  */
356290075Sobrien  do
356390075Sobrien    {
356490075Sobrien      enum insn_code icode;
356590075Sobrien      PUT_MODE (test, wider_mode);
356690075Sobrien
356790075Sobrien      if (label)
356890075Sobrien	{
3569117395Skan	  icode = cbranch_optab->handlers[(int) wider_mode].insn_code;
357090075Sobrien
357190075Sobrien	  if (icode != CODE_FOR_nothing
357290075Sobrien	      && (*insn_data[icode].operand[0].predicate) (test, wider_mode))
357390075Sobrien	    {
357490075Sobrien	      x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
357590075Sobrien	      y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
357690075Sobrien	      emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
357790075Sobrien	      return;
357890075Sobrien	    }
357990075Sobrien	}
358090075Sobrien
358190075Sobrien      /* Handle some compares against zero.  */
358290075Sobrien      icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
358390075Sobrien      if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
358490075Sobrien	{
358590075Sobrien	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
358690075Sobrien	  emit_insn (GEN_FCN (icode) (x));
358790075Sobrien	  if (label)
358890075Sobrien	    emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
358990075Sobrien	  return;
359090075Sobrien	}
359190075Sobrien
359290075Sobrien      /* Handle compares for which there is a directly suitable insn.  */
359390075Sobrien
359490075Sobrien      icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code;
359590075Sobrien      if (icode != CODE_FOR_nothing)
359690075Sobrien	{
359790075Sobrien	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
359890075Sobrien	  y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp);
359990075Sobrien	  emit_insn (GEN_FCN (icode) (x, y));
360090075Sobrien	  if (label)
360190075Sobrien	    emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
360290075Sobrien	  return;
360390075Sobrien	}
360490075Sobrien
360590075Sobrien      if (class != MODE_INT && class != MODE_FLOAT
360690075Sobrien	  && class != MODE_COMPLEX_FLOAT)
360790075Sobrien	break;
360890075Sobrien
360990075Sobrien      wider_mode = GET_MODE_WIDER_MODE (wider_mode);
3610117395Skan    }
3611117395Skan  while (wider_mode != VOIDmode);
361290075Sobrien
361390075Sobrien  abort ();
361490075Sobrien}
361590075Sobrien
361652284Sobrien/* Generate code to compare X with Y so that the condition codes are
361752284Sobrien   set and to jump to LABEL if the condition is true.  If X is a
361852284Sobrien   constant and Y is not a constant, then the comparison is swapped to
361952284Sobrien   ensure that the comparison RTL has the canonical form.
362052284Sobrien
362152284Sobrien   UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they
362252284Sobrien   need to be widened by emit_cmp_insn.  UNSIGNEDP is also used to select
362352284Sobrien   the proper branch condition code.
362452284Sobrien
362590075Sobrien   If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y.
362652284Sobrien
362752284Sobrien   MODE is the mode of the inputs (in case they are const_int).
362852284Sobrien
362952284Sobrien   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  It will
363052284Sobrien   be passed unchanged to emit_cmp_insn, then potentially converted into an
363152284Sobrien   unsigned variant based on UNSIGNEDP to select a proper jump instruction.  */
363252284Sobrien
363352284Sobrienvoid
363490075Sobrienemit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label)
363552284Sobrien     rtx x, y;
363652284Sobrien     enum rtx_code comparison;
363752284Sobrien     rtx size;
363852284Sobrien     enum machine_mode mode;
363952284Sobrien     int unsignedp;
364052284Sobrien     rtx label;
364152284Sobrien{
364290075Sobrien  rtx op0 = x, op1 = y;
364390075Sobrien
364490075Sobrien  /* Swap operands and condition to ensure canonical RTL.  */
364590075Sobrien  if (swap_commutative_operands_p (x, y))
364652284Sobrien    {
364790075Sobrien      /* If we're not emitting a branch, this means some caller
364890075Sobrien         is out of sync.  */
364990075Sobrien      if (! label)
365090075Sobrien	abort ();
365190075Sobrien
365290075Sobrien      op0 = y, op1 = x;
365352284Sobrien      comparison = swap_condition (comparison);
365452284Sobrien    }
365552284Sobrien
365652284Sobrien#ifdef HAVE_cc0
365752284Sobrien  /* If OP0 is still a constant, then both X and Y must be constants.  Force
365852284Sobrien     X into a register to avoid aborting in emit_cmp_insn due to non-canonical
365952284Sobrien     RTL.  */
366052284Sobrien  if (CONSTANT_P (op0))
366152284Sobrien    op0 = force_reg (mode, op0);
366252284Sobrien#endif
366352284Sobrien
366490075Sobrien  emit_queue ();
366552284Sobrien  if (unsignedp)
366652284Sobrien    comparison = unsigned_condition (comparison);
366790075Sobrien
366890075Sobrien  prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp,
366990075Sobrien		    ccp_jump);
367090075Sobrien  emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
367152284Sobrien}
367252284Sobrien
367390075Sobrien/* Like emit_cmp_and_jump_insns, but generate only the comparison.  */
367452284Sobrien
367590075Sobrienvoid
367690075Sobrienemit_cmp_insn (x, y, comparison, size, mode, unsignedp)
367790075Sobrien     rtx x, y;
367890075Sobrien     enum rtx_code comparison;
367990075Sobrien     rtx size;
368018334Speter     enum machine_mode mode;
368190075Sobrien     int unsignedp;
368218334Speter{
368390075Sobrien  emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0);
368418334Speter}
368518334Speter
368618334Speter/* Emit a library call comparison between floating point X and Y.
368718334Speter   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
368818334Speter
368990075Sobrienstatic void
369090075Sobrienprepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
369190075Sobrien     rtx *px, *py;
369290075Sobrien     enum rtx_code *pcomparison;
369390075Sobrien     enum machine_mode *pmode;
369490075Sobrien     int *punsignedp;
369518334Speter{
369690075Sobrien  enum rtx_code comparison = *pcomparison;
3697117395Skan  rtx tmp;
369890075Sobrien  rtx x = *px = protect_from_queue (*px, 0);
369990075Sobrien  rtx y = *py = protect_from_queue (*py, 0);
370018334Speter  enum machine_mode mode = GET_MODE (x);
370118334Speter  rtx libfunc = 0;
370250397Sobrien  rtx result;
370318334Speter
370418334Speter  if (mode == HFmode)
370518334Speter    switch (comparison)
370618334Speter      {
370718334Speter      case EQ:
370818334Speter	libfunc = eqhf2_libfunc;
370918334Speter	break;
371018334Speter
371118334Speter      case NE:
371218334Speter	libfunc = nehf2_libfunc;
371318334Speter	break;
371418334Speter
371518334Speter      case GT:
371618334Speter	libfunc = gthf2_libfunc;
3717117395Skan	if (libfunc == NULL_RTX)
3718117395Skan	  {
3719117395Skan	    tmp = x; x = y; y = tmp;
3720117395Skan	    *pcomparison = LT;
3721117395Skan	    libfunc = lthf2_libfunc;
3722117395Skan	  }
372318334Speter	break;
372418334Speter
372518334Speter      case GE:
372618334Speter	libfunc = gehf2_libfunc;
3727117395Skan	if (libfunc == NULL_RTX)
3728117395Skan	  {
3729117395Skan	    tmp = x; x = y; y = tmp;
3730117395Skan	    *pcomparison = LE;
3731117395Skan	    libfunc = lehf2_libfunc;
3732117395Skan	  }
373318334Speter	break;
373418334Speter
373518334Speter      case LT:
373618334Speter	libfunc = lthf2_libfunc;
3737117395Skan	if (libfunc == NULL_RTX)
3738117395Skan	  {
3739117395Skan	    tmp = x; x = y; y = tmp;
3740117395Skan	    *pcomparison = GT;
3741117395Skan	    libfunc = gthf2_libfunc;
3742117395Skan	  }
374318334Speter	break;
374418334Speter
374518334Speter      case LE:
374618334Speter	libfunc = lehf2_libfunc;
3747117395Skan	if (libfunc == NULL_RTX)
3748117395Skan	  {
3749117395Skan	    tmp = x; x = y; y = tmp;
3750117395Skan	    *pcomparison = GE;
3751117395Skan	    libfunc = gehf2_libfunc;
3752117395Skan	  }
375318334Speter	break;
375450397Sobrien
375590075Sobrien      case UNORDERED:
375690075Sobrien	libfunc = unordhf2_libfunc;
375790075Sobrien	break;
375890075Sobrien
375950397Sobrien      default:
376050397Sobrien	break;
376118334Speter      }
376218334Speter  else if (mode == SFmode)
376318334Speter    switch (comparison)
376418334Speter      {
376518334Speter      case EQ:
376618334Speter	libfunc = eqsf2_libfunc;
376718334Speter	break;
376818334Speter
376918334Speter      case NE:
377018334Speter	libfunc = nesf2_libfunc;
377118334Speter	break;
377218334Speter
377318334Speter      case GT:
377418334Speter	libfunc = gtsf2_libfunc;
3775117395Skan	if (libfunc == NULL_RTX)
3776117395Skan	  {
3777117395Skan	    tmp = x; x = y; y = tmp;
3778117395Skan	    *pcomparison = LT;
3779117395Skan	    libfunc = ltsf2_libfunc;
3780117395Skan	  }
378118334Speter	break;
378218334Speter
378318334Speter      case GE:
378418334Speter	libfunc = gesf2_libfunc;
3785117395Skan	if (libfunc == NULL_RTX)
3786117395Skan	  {
3787117395Skan	    tmp = x; x = y; y = tmp;
3788117395Skan	    *pcomparison = LE;
3789117395Skan	    libfunc = lesf2_libfunc;
3790117395Skan	  }
379118334Speter	break;
379218334Speter
379318334Speter      case LT:
379418334Speter	libfunc = ltsf2_libfunc;
3795117395Skan	if (libfunc == NULL_RTX)
3796117395Skan	  {
3797117395Skan	    tmp = x; x = y; y = tmp;
3798117395Skan	    *pcomparison = GT;
3799117395Skan	    libfunc = gtsf2_libfunc;
3800117395Skan	  }
380118334Speter	break;
380218334Speter
380318334Speter      case LE:
380418334Speter	libfunc = lesf2_libfunc;
3805117395Skan	if (libfunc == NULL_RTX)
3806117395Skan	  {
3807117395Skan	    tmp = x; x = y; y = tmp;
3808117395Skan	    *pcomparison = GE;
3809117395Skan	    libfunc = gesf2_libfunc;
3810117395Skan	  }
381118334Speter	break;
381250397Sobrien
381390075Sobrien      case UNORDERED:
381490075Sobrien	libfunc = unordsf2_libfunc;
381590075Sobrien	break;
381690075Sobrien
381750397Sobrien      default:
381850397Sobrien	break;
381918334Speter      }
382018334Speter  else if (mode == DFmode)
382118334Speter    switch (comparison)
382218334Speter      {
382318334Speter      case EQ:
382418334Speter	libfunc = eqdf2_libfunc;
382518334Speter	break;
382618334Speter
382718334Speter      case NE:
382818334Speter	libfunc = nedf2_libfunc;
382918334Speter	break;
383018334Speter
383118334Speter      case GT:
383218334Speter	libfunc = gtdf2_libfunc;
3833117395Skan	if (libfunc == NULL_RTX)
3834117395Skan	  {
3835117395Skan	    tmp = x; x = y; y = tmp;
3836117395Skan	    *pcomparison = LT;
3837117395Skan	    libfunc = ltdf2_libfunc;
3838117395Skan	  }
383918334Speter	break;
384018334Speter
384118334Speter      case GE:
384218334Speter	libfunc = gedf2_libfunc;
3843117395Skan	if (libfunc == NULL_RTX)
3844117395Skan	  {
3845117395Skan	    tmp = x; x = y; y = tmp;
3846117395Skan	    *pcomparison = LE;
3847117395Skan	    libfunc = ledf2_libfunc;
3848117395Skan	  }
384918334Speter	break;
385018334Speter
385118334Speter      case LT:
385218334Speter	libfunc = ltdf2_libfunc;
3853117395Skan	if (libfunc == NULL_RTX)
3854117395Skan	  {
3855117395Skan	    tmp = x; x = y; y = tmp;
3856117395Skan	    *pcomparison = GT;
3857117395Skan	    libfunc = gtdf2_libfunc;
3858117395Skan	  }
385918334Speter	break;
386018334Speter
386118334Speter      case LE:
386218334Speter	libfunc = ledf2_libfunc;
3863117395Skan	if (libfunc == NULL_RTX)
3864117395Skan	  {
3865117395Skan	    tmp = x; x = y; y = tmp;
3866117395Skan	    *pcomparison = GE;
3867117395Skan	    libfunc = gedf2_libfunc;
3868117395Skan	  }
386918334Speter	break;
387050397Sobrien
387190075Sobrien      case UNORDERED:
387290075Sobrien	libfunc = unorddf2_libfunc;
387390075Sobrien	break;
387490075Sobrien
387550397Sobrien      default:
387650397Sobrien	break;
387718334Speter      }
387818334Speter  else if (mode == XFmode)
387918334Speter    switch (comparison)
388018334Speter      {
388118334Speter      case EQ:
388218334Speter	libfunc = eqxf2_libfunc;
388318334Speter	break;
388418334Speter
388518334Speter      case NE:
388618334Speter	libfunc = nexf2_libfunc;
388718334Speter	break;
388818334Speter
388918334Speter      case GT:
389018334Speter	libfunc = gtxf2_libfunc;
3891117395Skan	if (libfunc == NULL_RTX)
3892117395Skan	  {
3893117395Skan	    tmp = x; x = y; y = tmp;
3894117395Skan	    *pcomparison = LT;
3895117395Skan	    libfunc = ltxf2_libfunc;
3896117395Skan	  }
389718334Speter	break;
389818334Speter
389918334Speter      case GE:
390018334Speter	libfunc = gexf2_libfunc;
3901117395Skan	if (libfunc == NULL_RTX)
3902117395Skan	  {
3903117395Skan	    tmp = x; x = y; y = tmp;
3904117395Skan	    *pcomparison = LE;
3905117395Skan	    libfunc = lexf2_libfunc;
3906117395Skan	  }
390718334Speter	break;
390818334Speter
390918334Speter      case LT:
391018334Speter	libfunc = ltxf2_libfunc;
3911117395Skan	if (libfunc == NULL_RTX)
3912117395Skan	  {
3913117395Skan	    tmp = x; x = y; y = tmp;
3914117395Skan	    *pcomparison = GT;
3915117395Skan	    libfunc = gtxf2_libfunc;
3916117395Skan	  }
391718334Speter	break;
391818334Speter
391918334Speter      case LE:
392018334Speter	libfunc = lexf2_libfunc;
3921117395Skan	if (libfunc == NULL_RTX)
3922117395Skan	  {
3923117395Skan	    tmp = x; x = y; y = tmp;
3924117395Skan	    *pcomparison = GE;
3925117395Skan	    libfunc = gexf2_libfunc;
3926117395Skan	  }
392718334Speter	break;
392850397Sobrien
392990075Sobrien      case UNORDERED:
393090075Sobrien	libfunc = unordxf2_libfunc;
393190075Sobrien	break;
393290075Sobrien
393350397Sobrien      default:
393450397Sobrien	break;
393518334Speter      }
393618334Speter  else if (mode == TFmode)
393718334Speter    switch (comparison)
393818334Speter      {
393918334Speter      case EQ:
394018334Speter	libfunc = eqtf2_libfunc;
394118334Speter	break;
394218334Speter
394318334Speter      case NE:
394418334Speter	libfunc = netf2_libfunc;
394518334Speter	break;
394618334Speter
394718334Speter      case GT:
394818334Speter	libfunc = gttf2_libfunc;
3949117395Skan	if (libfunc == NULL_RTX)
3950117395Skan	  {
3951117395Skan	    tmp = x; x = y; y = tmp;
3952117395Skan	    *pcomparison = LT;
3953117395Skan	    libfunc = lttf2_libfunc;
3954117395Skan	  }
395518334Speter	break;
395618334Speter
395718334Speter      case GE:
395818334Speter	libfunc = getf2_libfunc;
3959117395Skan	if (libfunc == NULL_RTX)
3960117395Skan	  {
3961117395Skan	    tmp = x; x = y; y = tmp;
3962117395Skan	    *pcomparison = LE;
3963117395Skan	    libfunc = letf2_libfunc;
3964117395Skan	  }
396518334Speter	break;
396618334Speter
396718334Speter      case LT:
396818334Speter	libfunc = lttf2_libfunc;
3969117395Skan	if (libfunc == NULL_RTX)
3970117395Skan	  {
3971117395Skan	    tmp = x; x = y; y = tmp;
3972117395Skan	    *pcomparison = GT;
3973117395Skan	    libfunc = gttf2_libfunc;
3974117395Skan	  }
397518334Speter	break;
397618334Speter
397718334Speter      case LE:
397818334Speter	libfunc = letf2_libfunc;
3979117395Skan	if (libfunc == NULL_RTX)
3980117395Skan	  {
3981117395Skan	    tmp = x; x = y; y = tmp;
3982117395Skan	    *pcomparison = GE;
3983117395Skan	    libfunc = getf2_libfunc;
3984117395Skan	  }
398518334Speter	break;
398650397Sobrien
398790075Sobrien      case UNORDERED:
398890075Sobrien	libfunc = unordtf2_libfunc;
398990075Sobrien	break;
399090075Sobrien
399150397Sobrien      default:
399250397Sobrien	break;
399318334Speter      }
399418334Speter  else
399518334Speter    {
399618334Speter      enum machine_mode wider_mode;
399718334Speter
399818334Speter      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
399918334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
400018334Speter	{
400118334Speter	  if ((cmp_optab->handlers[(int) wider_mode].insn_code
400218334Speter	       != CODE_FOR_nothing)
400318334Speter	      || (cmp_optab->handlers[(int) wider_mode].libfunc != 0))
400418334Speter	    {
400518334Speter	      x = protect_from_queue (x, 0);
400618334Speter	      y = protect_from_queue (y, 0);
400790075Sobrien	      *px = convert_to_mode (wider_mode, x, 0);
400890075Sobrien	      *py = convert_to_mode (wider_mode, y, 0);
400990075Sobrien	      prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
401018334Speter	      return;
401118334Speter	    }
401218334Speter	}
401318334Speter      abort ();
401418334Speter    }
401518334Speter
401618334Speter  if (libfunc == 0)
401718334Speter    abort ();
401818334Speter
4019117395Skan  result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
4020117395Skan				    word_mode, 2, x, mode, y, mode);
402190075Sobrien  *px = result;
402290075Sobrien  *py = const0_rtx;
402390075Sobrien  *pmode = word_mode;
402490075Sobrien  if (comparison == UNORDERED)
402590075Sobrien    *pcomparison = NE;
402690075Sobrien#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL
402790075Sobrien  else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
402890075Sobrien    *pcomparison = NE;
402990075Sobrien#endif
403090075Sobrien  *punsignedp = 0;
403118334Speter}
403218334Speter
403318334Speter/* Generate code to indirectly jump to a location given in the rtx LOC.  */
403418334Speter
403518334Spetervoid
403618334Speteremit_indirect_jump (loc)
403718334Speter     rtx loc;
403818334Speter{
4039117395Skan  if (! ((*insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate)
404018334Speter	 (loc, Pmode)))
404118334Speter    loc = copy_to_mode_reg (Pmode, loc);
404218334Speter
404318334Speter  emit_jump_insn (gen_indirect_jump (loc));
404418334Speter  emit_barrier ();
404518334Speter}
404618334Speter
404718334Speter#ifdef HAVE_conditional_move
404818334Speter
404918334Speter/* Emit a conditional move instruction if the machine supports one for that
405018334Speter   condition and machine mode.
405118334Speter
405218334Speter   OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
405318334Speter   the mode to use should they be constants.  If it is VOIDmode, they cannot
405418334Speter   both be constants.
405518334Speter
405618334Speter   OP2 should be stored in TARGET if the comparison is true, otherwise OP3
405718334Speter   should be stored there.  MODE is the mode to use should they be constants.
405818334Speter   If it is VOIDmode, they cannot both be constants.
405918334Speter
406018334Speter   The result is either TARGET (perhaps modified) or NULL_RTX if the operation
406118334Speter   is not supported.  */
406218334Speter
406318334Speterrtx
406418334Speteremit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
406518334Speter		       unsignedp)
406618334Speter     rtx target;
406718334Speter     enum rtx_code code;
406818334Speter     rtx op0, op1;
406918334Speter     enum machine_mode cmode;
407018334Speter     rtx op2, op3;
407118334Speter     enum machine_mode mode;
407218334Speter     int unsignedp;
407318334Speter{
407418334Speter  rtx tem, subtarget, comparison, insn;
407518334Speter  enum insn_code icode;
407690075Sobrien  enum rtx_code reversed;
407718334Speter
407818334Speter  /* If one operand is constant, make it the second one.  Only do this
407918334Speter     if the other operand is not constant as well.  */
408018334Speter
408190075Sobrien  if (swap_commutative_operands_p (op0, op1))
408218334Speter    {
408318334Speter      tem = op0;
408418334Speter      op0 = op1;
408518334Speter      op1 = tem;
408618334Speter      code = swap_condition (code);
408718334Speter    }
408818334Speter
408990075Sobrien  /* get_condition will prefer to generate LT and GT even if the old
409090075Sobrien     comparison was against zero, so undo that canonicalization here since
409190075Sobrien     comparisons against zero are cheaper.  */
409290075Sobrien  if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
409390075Sobrien    code = LE, op1 = const0_rtx;
409490075Sobrien  else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
409590075Sobrien    code = GE, op1 = const0_rtx;
409690075Sobrien
409718334Speter  if (cmode == VOIDmode)
409818334Speter    cmode = GET_MODE (op0);
409918334Speter
410090075Sobrien  if (swap_commutative_operands_p (op2, op3)
410190075Sobrien      && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
410290075Sobrien          != UNKNOWN))
410318334Speter    {
410418334Speter      tem = op2;
410518334Speter      op2 = op3;
410618334Speter      op3 = tem;
410790075Sobrien      code = reversed;
410818334Speter    }
410918334Speter
411018334Speter  if (mode == VOIDmode)
411118334Speter    mode = GET_MODE (op2);
411218334Speter
411318334Speter  icode = movcc_gen_code[mode];
411418334Speter
411518334Speter  if (icode == CODE_FOR_nothing)
411618334Speter    return 0;
411718334Speter
411818334Speter  if (flag_force_mem)
411918334Speter    {
412018334Speter      op2 = force_not_mem (op2);
412118334Speter      op3 = force_not_mem (op3);
412218334Speter    }
412318334Speter
412418334Speter  if (target)
412518334Speter    target = protect_from_queue (target, 1);
412618334Speter  else
412718334Speter    target = gen_reg_rtx (mode);
412818334Speter
412918334Speter  subtarget = target;
413018334Speter
413118334Speter  emit_queue ();
413218334Speter
413318334Speter  op2 = protect_from_queue (op2, 0);
413418334Speter  op3 = protect_from_queue (op3, 0);
413518334Speter
413618334Speter  /* If the insn doesn't accept these operands, put them in pseudos.  */
413718334Speter
413890075Sobrien  if (! (*insn_data[icode].operand[0].predicate)
413990075Sobrien      (subtarget, insn_data[icode].operand[0].mode))
414090075Sobrien    subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
414118334Speter
414290075Sobrien  if (! (*insn_data[icode].operand[2].predicate)
414390075Sobrien      (op2, insn_data[icode].operand[2].mode))
414490075Sobrien    op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
414518334Speter
414690075Sobrien  if (! (*insn_data[icode].operand[3].predicate)
414790075Sobrien      (op3, insn_data[icode].operand[3].mode))
414890075Sobrien    op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
414918334Speter
415018334Speter  /* Everything should now be in the suitable form, so emit the compare insn
415118334Speter     and then the conditional move.  */
415218334Speter
415318334Speter  comparison
415490075Sobrien    = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
415518334Speter
415618334Speter  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
415790075Sobrien  /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
415890075Sobrien     return NULL and let the caller figure out how best to deal with this
415990075Sobrien     situation.  */
416018334Speter  if (GET_CODE (comparison) != code)
416190075Sobrien    return NULL_RTX;
416218334Speter
416318334Speter  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
416418334Speter
416518334Speter  /* If that failed, then give up.  */
416618334Speter  if (insn == 0)
416718334Speter    return 0;
416818334Speter
416918334Speter  emit_insn (insn);
417018334Speter
417118334Speter  if (subtarget != target)
417218334Speter    convert_move (target, subtarget, 0);
417318334Speter
417418334Speter  return target;
417518334Speter}
417618334Speter
4177117395Skan/* Return nonzero if a conditional move of mode MODE is supported.
417818334Speter
417918334Speter   This function is for combine so it can tell whether an insn that looks
418018334Speter   like a conditional move is actually supported by the hardware.  If we
418118334Speter   guess wrong we lose a bit on optimization, but that's it.  */
418218334Speter/* ??? sparc64 supports conditionally moving integers values based on fp
418318334Speter   comparisons, and vice versa.  How do we handle them?  */
418418334Speter
418518334Speterint
418618334Spetercan_conditionally_move_p (mode)
418718334Speter     enum machine_mode mode;
418818334Speter{
418918334Speter  if (movcc_gen_code[mode] != CODE_FOR_nothing)
419018334Speter    return 1;
419118334Speter
419218334Speter  return 0;
419318334Speter}
419418334Speter
419518334Speter#endif /* HAVE_conditional_move */
419618334Speter
419790075Sobrien/* These functions generate an insn body and return it
419818334Speter   rather than emitting the insn.
419918334Speter
420018334Speter   They do not protect from queued increments,
420118334Speter   because they may be used 1) in protect_from_queue itself
420218334Speter   and 2) in other passes where there is no queue.  */
420318334Speter
420418334Speter/* Generate and return an insn body to add Y to X.  */
420518334Speter
420618334Speterrtx
420718334Spetergen_add2_insn (x, y)
420818334Speter     rtx x, y;
420918334Speter{
421018334Speter  int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
421118334Speter
421290075Sobrien  if (! ((*insn_data[icode].operand[0].predicate)
421390075Sobrien	 (x, insn_data[icode].operand[0].mode))
421490075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
421590075Sobrien	    (x, insn_data[icode].operand[1].mode))
421690075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
421790075Sobrien	    (y, insn_data[icode].operand[2].mode)))
421818334Speter    abort ();
421918334Speter
422018334Speter  return (GEN_FCN (icode) (x, x, y));
422118334Speter}
422218334Speter
422390075Sobrien/* Generate and return an insn body to add r1 and c,
422490075Sobrien   storing the result in r0.  */
422590075Sobrienrtx
422690075Sobriengen_add3_insn (r0, r1, c)
422790075Sobrien     rtx r0, r1, c;
422890075Sobrien{
422990075Sobrien  int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
423090075Sobrien
4231117395Skan  if (icode == CODE_FOR_nothing
423290075Sobrien      || ! ((*insn_data[icode].operand[0].predicate)
423390075Sobrien	    (r0, insn_data[icode].operand[0].mode))
423490075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
423590075Sobrien	    (r1, insn_data[icode].operand[1].mode))
423690075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
423790075Sobrien	    (c, insn_data[icode].operand[2].mode)))
423890075Sobrien    return NULL_RTX;
423990075Sobrien
424090075Sobrien  return (GEN_FCN (icode) (r0, r1, c));
424190075Sobrien}
424290075Sobrien
424318334Speterint
424490075Sobrienhave_add2_insn (x, y)
424590075Sobrien     rtx x, y;
424618334Speter{
424790075Sobrien  int icode;
424890075Sobrien
424990075Sobrien  if (GET_MODE (x) == VOIDmode)
425090075Sobrien    abort ();
425190075Sobrien
425290075Sobrien  icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
425390075Sobrien
425490075Sobrien  if (icode == CODE_FOR_nothing)
425590075Sobrien    return 0;
425690075Sobrien
425790075Sobrien  if (! ((*insn_data[icode].operand[0].predicate)
425890075Sobrien	 (x, insn_data[icode].operand[0].mode))
425990075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
426090075Sobrien	    (x, insn_data[icode].operand[1].mode))
426190075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
426290075Sobrien	    (y, insn_data[icode].operand[2].mode)))
426390075Sobrien    return 0;
426490075Sobrien
426590075Sobrien  return 1;
426618334Speter}
426718334Speter
426818334Speter/* Generate and return an insn body to subtract Y from X.  */
426918334Speter
427018334Speterrtx
427118334Spetergen_sub2_insn (x, y)
427218334Speter     rtx x, y;
427318334Speter{
427418334Speter  int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
427518334Speter
427690075Sobrien  if (! ((*insn_data[icode].operand[0].predicate)
427790075Sobrien	 (x, insn_data[icode].operand[0].mode))
427890075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
427990075Sobrien	    (x, insn_data[icode].operand[1].mode))
428090075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
428190075Sobrien	    (y, insn_data[icode].operand[2].mode)))
428218334Speter    abort ();
428318334Speter
428418334Speter  return (GEN_FCN (icode) (x, x, y));
428518334Speter}
428618334Speter
428790075Sobrien/* Generate and return an insn body to subtract r1 and c,
428890075Sobrien   storing the result in r0.  */
428990075Sobrienrtx
429090075Sobriengen_sub3_insn (r0, r1, c)
429190075Sobrien     rtx r0, r1, c;
429290075Sobrien{
429390075Sobrien  int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code;
429490075Sobrien
4295117395Skan  if (icode == CODE_FOR_nothing
429690075Sobrien      || ! ((*insn_data[icode].operand[0].predicate)
429790075Sobrien	    (r0, insn_data[icode].operand[0].mode))
429890075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
429990075Sobrien	    (r1, insn_data[icode].operand[1].mode))
430090075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
430190075Sobrien	    (c, insn_data[icode].operand[2].mode)))
430290075Sobrien    return NULL_RTX;
430390075Sobrien
430490075Sobrien  return (GEN_FCN (icode) (r0, r1, c));
430590075Sobrien}
430690075Sobrien
430718334Speterint
430890075Sobrienhave_sub2_insn (x, y)
430990075Sobrien     rtx x, y;
431018334Speter{
431190075Sobrien  int icode;
431290075Sobrien
431390075Sobrien  if (GET_MODE (x) == VOIDmode)
431490075Sobrien    abort ();
431590075Sobrien
431690075Sobrien  icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
431790075Sobrien
431890075Sobrien  if (icode == CODE_FOR_nothing)
431990075Sobrien    return 0;
432090075Sobrien
432190075Sobrien  if (! ((*insn_data[icode].operand[0].predicate)
432290075Sobrien	 (x, insn_data[icode].operand[0].mode))
432390075Sobrien      || ! ((*insn_data[icode].operand[1].predicate)
432490075Sobrien	    (x, insn_data[icode].operand[1].mode))
432590075Sobrien      || ! ((*insn_data[icode].operand[2].predicate)
432690075Sobrien	    (y, insn_data[icode].operand[2].mode)))
432790075Sobrien    return 0;
432890075Sobrien
432990075Sobrien  return 1;
433018334Speter}
433118334Speter
433218334Speter/* Generate the body of an instruction to copy Y into X.
4333117395Skan   It may be a list of insns, if one insn isn't enough.  */
433418334Speter
433518334Speterrtx
433618334Spetergen_move_insn (x, y)
433718334Speter     rtx x, y;
433818334Speter{
433990075Sobrien  enum machine_mode mode = GET_MODE (x);
434018334Speter  enum insn_code insn_code;
434118334Speter  rtx seq;
434218334Speter
434318334Speter  if (mode == VOIDmode)
434418334Speter    mode = GET_MODE (y);
434518334Speter
434618334Speter  insn_code = mov_optab->handlers[(int) mode].insn_code;
434718334Speter
434818334Speter  /* Handle MODE_CC modes:  If we don't have a special move insn for this mode,
434918334Speter     find a mode to do it in.  If we have a movcc, use it.  Otherwise,
435018334Speter     find the MODE_INT mode of the same width.  */
435118334Speter
435218334Speter  if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing)
435318334Speter    {
435418334Speter      enum machine_mode tmode = VOIDmode;
435518334Speter      rtx x1 = x, y1 = y;
435618334Speter
435718334Speter      if (mode != CCmode
435818334Speter	  && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
435918334Speter	tmode = CCmode;
436018334Speter      else
436118334Speter	for (tmode = QImode; tmode != VOIDmode;
436218334Speter	     tmode = GET_MODE_WIDER_MODE (tmode))
436318334Speter	  if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
436418334Speter	    break;
436518334Speter
436618334Speter      if (tmode == VOIDmode)
436718334Speter	abort ();
436818334Speter
436918334Speter      /* Get X and Y in TMODE.  We can't use gen_lowpart here because it
437018334Speter	 may call change_address which is not appropriate if we were
437118334Speter	 called when a reload was in progress.  We don't have to worry
437218334Speter	 about changing the address since the size in bytes is supposed to
437318334Speter	 be the same.  Copy the MEM to change the mode and move any
437418334Speter	 substitutions from the old MEM to the new one.  */
437518334Speter
437618334Speter      if (reload_in_progress)
437718334Speter	{
437818334Speter	  x = gen_lowpart_common (tmode, x1);
437918334Speter	  if (x == 0 && GET_CODE (x1) == MEM)
438018334Speter	    {
438190075Sobrien	      x = adjust_address_nv (x1, tmode, 0);
438218334Speter	      copy_replacements (x1, x);
438318334Speter	    }
438418334Speter
438518334Speter	  y = gen_lowpart_common (tmode, y1);
438618334Speter	  if (y == 0 && GET_CODE (y1) == MEM)
438718334Speter	    {
438890075Sobrien	      y = adjust_address_nv (y1, tmode, 0);
438918334Speter	      copy_replacements (y1, y);
439018334Speter	    }
439118334Speter	}
439218334Speter      else
439318334Speter	{
439418334Speter	  x = gen_lowpart (tmode, x);
439518334Speter	  y = gen_lowpart (tmode, y);
439618334Speter	}
439718334Speter
439818334Speter      insn_code = mov_optab->handlers[(int) tmode].insn_code;
439918334Speter      return (GEN_FCN (insn_code) (x, y));
440018334Speter    }
440118334Speter
440218334Speter  start_sequence ();
440318334Speter  emit_move_insn_1 (x, y);
4404117395Skan  seq = get_insns ();
440518334Speter  end_sequence ();
440618334Speter  return seq;
440718334Speter}
440818334Speter
440918334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE.
441018334Speter   UNSIGNEDP specifies zero-extension instead of sign-extension.  If
441118334Speter   no such operation exists, CODE_FOR_nothing will be returned.  */
441218334Speter
441318334Speterenum insn_code
441418334Spetercan_extend_p (to_mode, from_mode, unsignedp)
441518334Speter     enum machine_mode to_mode, from_mode;
441618334Speter     int unsignedp;
441718334Speter{
441890075Sobrien#ifdef HAVE_ptr_extend
441990075Sobrien  if (unsignedp < 0)
442090075Sobrien    return CODE_FOR_ptr_extend;
442190075Sobrien  else
442290075Sobrien#endif
442390075Sobrien    return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0];
442418334Speter}
442518334Speter
442618334Speter/* Generate the body of an insn to extend Y (with mode MFROM)
442718334Speter   into X (with mode MTO).  Do zero-extension if UNSIGNEDP is nonzero.  */
442818334Speter
442918334Speterrtx
443018334Spetergen_extend_insn (x, y, mto, mfrom, unsignedp)
443118334Speter     rtx x, y;
443218334Speter     enum machine_mode mto, mfrom;
443318334Speter     int unsignedp;
443418334Speter{
443590075Sobrien  return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp != 0]) (x, y));
443618334Speter}
443718334Speter
443818334Speter/* can_fix_p and can_float_p say whether the target machine
443918334Speter   can directly convert a given fixed point type to
444018334Speter   a given floating point type, or vice versa.
444118334Speter   The returned value is the CODE_FOR_... value to use,
444218334Speter   or CODE_FOR_nothing if these modes cannot be directly converted.
444318334Speter
444418334Speter   *TRUNCP_PTR is set to 1 if it is necessary to output
444518334Speter   an explicit FTRUNC insn before the fix insn; otherwise 0.  */
444618334Speter
444718334Speterstatic enum insn_code
444818334Spetercan_fix_p (fixmode, fltmode, unsignedp, truncp_ptr)
444918334Speter     enum machine_mode fltmode, fixmode;
445018334Speter     int unsignedp;
445118334Speter     int *truncp_ptr;
445218334Speter{
445318334Speter  *truncp_ptr = 0;
445490075Sobrien  if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0]
445590075Sobrien      != CODE_FOR_nothing)
445690075Sobrien    return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0];
445718334Speter
445818334Speter  if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing)
445918334Speter    {
446018334Speter      *truncp_ptr = 1;
446190075Sobrien      return fixtab[(int) fltmode][(int) fixmode][unsignedp != 0];
446218334Speter    }
446318334Speter  return CODE_FOR_nothing;
446418334Speter}
446518334Speter
446618334Speterstatic enum insn_code
446718334Spetercan_float_p (fltmode, fixmode, unsignedp)
446818334Speter     enum machine_mode fixmode, fltmode;
446918334Speter     int unsignedp;
447018334Speter{
447190075Sobrien  return floattab[(int) fltmode][(int) fixmode][unsignedp != 0];
447218334Speter}
447318334Speter
447418334Speter/* Generate code to convert FROM to floating point
447518334Speter   and store in TO.  FROM must be fixed point and not VOIDmode.
447618334Speter   UNSIGNEDP nonzero means regard FROM as unsigned.
447718334Speter   Normally this is done by correcting the final value
447818334Speter   if it is negative.  */
447918334Speter
448018334Spetervoid
448118334Speterexpand_float (to, from, unsignedp)
448218334Speter     rtx to, from;
448318334Speter     int unsignedp;
448418334Speter{
448518334Speter  enum insn_code icode;
448690075Sobrien  rtx target = to;
448718334Speter  enum machine_mode fmode, imode;
448818334Speter
448918334Speter  /* Crash now, because we won't be able to decide which mode to use.  */
449018334Speter  if (GET_MODE (from) == VOIDmode)
449118334Speter    abort ();
449218334Speter
449318334Speter  /* Look for an insn to do the conversion.  Do it in the specified
449418334Speter     modes if possible; otherwise convert either input, output or both to
449518334Speter     wider mode.  If the integer mode is wider than the mode of FROM,
449618334Speter     we can do the conversion signed even if the input is unsigned.  */
449718334Speter
4498117395Skan  for (fmode = GET_MODE (to); fmode != VOIDmode;
4499117395Skan       fmode = GET_MODE_WIDER_MODE (fmode))
4500117395Skan    for (imode = GET_MODE (from); imode != VOIDmode;
4501117395Skan	 imode = GET_MODE_WIDER_MODE (imode))
450218334Speter      {
450318334Speter	int doing_unsigned = unsignedp;
450418334Speter
450590075Sobrien	if (fmode != GET_MODE (to)
450690075Sobrien	    && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from)))
450790075Sobrien	  continue;
450890075Sobrien
450918334Speter	icode = can_float_p (fmode, imode, unsignedp);
451018334Speter	if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
451118334Speter	  icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
451218334Speter
451318334Speter	if (icode != CODE_FOR_nothing)
451418334Speter	  {
451518334Speter	    to = protect_from_queue (to, 1);
451618334Speter	    from = protect_from_queue (from, 0);
451718334Speter
451818334Speter	    if (imode != GET_MODE (from))
451918334Speter	      from = convert_to_mode (imode, from, unsignedp);
452018334Speter
452118334Speter	    if (fmode != GET_MODE (to))
452218334Speter	      target = gen_reg_rtx (fmode);
452318334Speter
452418334Speter	    emit_unop_insn (icode, target, from,
452518334Speter			    doing_unsigned ? UNSIGNED_FLOAT : FLOAT);
452618334Speter
452718334Speter	    if (target != to)
452818334Speter	      convert_move (to, target, 0);
452918334Speter	    return;
453018334Speter	  }
4531117395Skan      }
453218334Speter
453318334Speter  /* Unsigned integer, and no way to convert directly.
453418334Speter     Convert as signed, then conditionally adjust the result.  */
453518334Speter  if (unsignedp)
453618334Speter    {
453718334Speter      rtx label = gen_label_rtx ();
453818334Speter      rtx temp;
453918334Speter      REAL_VALUE_TYPE offset;
454018334Speter
454118334Speter      emit_queue ();
454218334Speter
454318334Speter      to = protect_from_queue (to, 1);
454418334Speter      from = protect_from_queue (from, 0);
454518334Speter
454618334Speter      if (flag_force_mem)
454718334Speter	from = force_not_mem (from);
454818334Speter
454918334Speter      /* Look for a usable floating mode FMODE wider than the source and at
455018334Speter	 least as wide as the target.  Using FMODE will avoid rounding woes
455118334Speter	 with unsigned values greater than the signed maximum value.  */
455218334Speter
455318334Speter      for (fmode = GET_MODE (to);  fmode != VOIDmode;
455418334Speter	   fmode = GET_MODE_WIDER_MODE (fmode))
455518334Speter	if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
455618334Speter	    && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
455718334Speter	  break;
455818334Speter
455918334Speter      if (fmode == VOIDmode)
456018334Speter	{
456118334Speter	  /* There is no such mode.  Pretend the target is wide enough.  */
456218334Speter	  fmode = GET_MODE (to);
456318334Speter
456450397Sobrien	  /* Avoid double-rounding when TO is narrower than FROM.  */
456518334Speter	  if ((significand_size (fmode) + 1)
456618334Speter	      < GET_MODE_BITSIZE (GET_MODE (from)))
456718334Speter	    {
456818334Speter	      rtx temp1;
456918334Speter	      rtx neglabel = gen_label_rtx ();
457018334Speter
457118334Speter	      /* Don't use TARGET if it isn't a register, is a hard register,
457218334Speter		 or is the wrong mode.  */
457318334Speter	      if (GET_CODE (target) != REG
457418334Speter		  || REGNO (target) < FIRST_PSEUDO_REGISTER
457518334Speter		  || GET_MODE (target) != fmode)
457618334Speter		target = gen_reg_rtx (fmode);
457718334Speter
457818334Speter	      imode = GET_MODE (from);
457918334Speter	      do_pending_stack_adjust ();
458018334Speter
458118334Speter	      /* Test whether the sign bit is set.  */
458290075Sobrien	      emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode,
458390075Sobrien				       0, neglabel);
458418334Speter
458518334Speter	      /* The sign bit is not set.  Convert as signed.  */
458618334Speter	      expand_float (target, from, 0);
458718334Speter	      emit_jump_insn (gen_jump (label));
458818334Speter	      emit_barrier ();
458918334Speter
459018334Speter	      /* The sign bit is set.
459118334Speter		 Convert to a usable (positive signed) value by shifting right
459218334Speter		 one bit, while remembering if a nonzero bit was shifted
459318334Speter		 out; i.e., compute  (from & 1) | (from >> 1).  */
459418334Speter
459518334Speter	      emit_label (neglabel);
459618334Speter	      temp = expand_binop (imode, and_optab, from, const1_rtx,
459718334Speter				   NULL_RTX, 1, OPTAB_LIB_WIDEN);
459818334Speter	      temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
459918334Speter				    NULL_RTX, 1);
460018334Speter	      temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
460118334Speter				   OPTAB_LIB_WIDEN);
460218334Speter	      expand_float (target, temp, 0);
460318334Speter
460418334Speter	      /* Multiply by 2 to undo the shift above.  */
460518334Speter	      temp = expand_binop (fmode, add_optab, target, target,
4606117395Skan				   target, 0, OPTAB_LIB_WIDEN);
460718334Speter	      if (temp != target)
460818334Speter		emit_move_insn (target, temp);
460918334Speter
461018334Speter	      do_pending_stack_adjust ();
461118334Speter	      emit_label (label);
461218334Speter	      goto done;
461318334Speter	    }
461418334Speter	}
461518334Speter
461618334Speter      /* If we are about to do some arithmetic to correct for an
461718334Speter	 unsigned operand, do it in a pseudo-register.  */
461818334Speter
461918334Speter      if (GET_MODE (to) != fmode
462018334Speter	  || GET_CODE (to) != REG || REGNO (to) < FIRST_PSEUDO_REGISTER)
462118334Speter	target = gen_reg_rtx (fmode);
462218334Speter
462318334Speter      /* Convert as signed integer to floating.  */
462418334Speter      expand_float (target, from, 0);
462518334Speter
462618334Speter      /* If FROM is negative (and therefore TO is negative),
462718334Speter	 correct its value by 2**bitwidth.  */
462818334Speter
462918334Speter      do_pending_stack_adjust ();
463052284Sobrien      emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
463190075Sobrien			       0, label);
463218334Speter
4633117395Skan
4634117395Skan      real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from)));
463518334Speter      temp = expand_binop (fmode, add_optab, target,
463618334Speter			   CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
463718334Speter			   target, 0, OPTAB_LIB_WIDEN);
463818334Speter      if (temp != target)
463918334Speter	emit_move_insn (target, temp);
464018334Speter
464118334Speter      do_pending_stack_adjust ();
464218334Speter      emit_label (label);
464318334Speter      goto done;
464418334Speter    }
464518334Speter
464618334Speter  /* No hardware instruction available; call a library routine to convert from
464718334Speter     SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode.  */
464818334Speter    {
464918334Speter      rtx libfcn;
465018334Speter      rtx insns;
465118334Speter      rtx value;
465218334Speter
465318334Speter      to = protect_from_queue (to, 1);
465418334Speter      from = protect_from_queue (from, 0);
465518334Speter
465618334Speter      if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
465718334Speter	from = convert_to_mode (SImode, from, unsignedp);
465818334Speter
465918334Speter      if (flag_force_mem)
466018334Speter	from = force_not_mem (from);
466118334Speter
466218334Speter      if (GET_MODE (to) == SFmode)
466318334Speter	{
466418334Speter	  if (GET_MODE (from) == SImode)
466518334Speter	    libfcn = floatsisf_libfunc;
466618334Speter	  else if (GET_MODE (from) == DImode)
466718334Speter	    libfcn = floatdisf_libfunc;
466818334Speter	  else if (GET_MODE (from) == TImode)
466918334Speter	    libfcn = floattisf_libfunc;
467018334Speter	  else
467118334Speter	    abort ();
467218334Speter	}
467318334Speter      else if (GET_MODE (to) == DFmode)
467418334Speter	{
467518334Speter	  if (GET_MODE (from) == SImode)
467618334Speter	    libfcn = floatsidf_libfunc;
467718334Speter	  else if (GET_MODE (from) == DImode)
467818334Speter	    libfcn = floatdidf_libfunc;
467918334Speter	  else if (GET_MODE (from) == TImode)
468018334Speter	    libfcn = floattidf_libfunc;
468118334Speter	  else
468218334Speter	    abort ();
468318334Speter	}
468418334Speter      else if (GET_MODE (to) == XFmode)
468518334Speter	{
468618334Speter	  if (GET_MODE (from) == SImode)
468718334Speter	    libfcn = floatsixf_libfunc;
468818334Speter	  else if (GET_MODE (from) == DImode)
468918334Speter	    libfcn = floatdixf_libfunc;
469018334Speter	  else if (GET_MODE (from) == TImode)
469118334Speter	    libfcn = floattixf_libfunc;
469218334Speter	  else
469318334Speter	    abort ();
469418334Speter	}
469518334Speter      else if (GET_MODE (to) == TFmode)
469618334Speter	{
469718334Speter	  if (GET_MODE (from) == SImode)
469818334Speter	    libfcn = floatsitf_libfunc;
469918334Speter	  else if (GET_MODE (from) == DImode)
470018334Speter	    libfcn = floatditf_libfunc;
470118334Speter	  else if (GET_MODE (from) == TImode)
470218334Speter	    libfcn = floattitf_libfunc;
470318334Speter	  else
470418334Speter	    abort ();
470518334Speter	}
470618334Speter      else
470718334Speter	abort ();
470818334Speter
470918334Speter      start_sequence ();
471018334Speter
471190075Sobrien      value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
471290075Sobrien				       GET_MODE (to), 1, from,
471390075Sobrien				       GET_MODE (from));
471418334Speter      insns = get_insns ();
471518334Speter      end_sequence ();
471618334Speter
471718334Speter      emit_libcall_block (insns, target, value,
471850397Sobrien			  gen_rtx_FLOAT (GET_MODE (to), from));
471918334Speter    }
472018334Speter
472118334Speter done:
472218334Speter
472318334Speter  /* Copy result to requested destination
472418334Speter     if we have been computing in a temp location.  */
472518334Speter
472618334Speter  if (target != to)
472718334Speter    {
472818334Speter      if (GET_MODE (target) == GET_MODE (to))
472918334Speter	emit_move_insn (to, target);
473018334Speter      else
473118334Speter	convert_move (to, target, 0);
473218334Speter    }
473318334Speter}
473418334Speter
473518334Speter/* expand_fix: generate code to convert FROM to fixed point
473618334Speter   and store in TO.  FROM must be floating point.  */
473718334Speter
473818334Speterstatic rtx
473918334Speterftruncify (x)
474018334Speter     rtx x;
474118334Speter{
474218334Speter  rtx temp = gen_reg_rtx (GET_MODE (x));
474318334Speter  return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0);
474418334Speter}
474518334Speter
474618334Spetervoid
474718334Speterexpand_fix (to, from, unsignedp)
474890075Sobrien     rtx to, from;
474918334Speter     int unsignedp;
475018334Speter{
475118334Speter  enum insn_code icode;
475290075Sobrien  rtx target = to;
475318334Speter  enum machine_mode fmode, imode;
475418334Speter  int must_trunc = 0;
475518334Speter  rtx libfcn = 0;
475618334Speter
475718334Speter  /* We first try to find a pair of modes, one real and one integer, at
475818334Speter     least as wide as FROM and TO, respectively, in which we can open-code
475918334Speter     this conversion.  If the integer mode is wider than the mode of TO,
476018334Speter     we can do the conversion either signed or unsigned.  */
476118334Speter
476290075Sobrien  for (fmode = GET_MODE (from); fmode != VOIDmode;
476390075Sobrien       fmode = GET_MODE_WIDER_MODE (fmode))
476490075Sobrien    for (imode = GET_MODE (to); imode != VOIDmode;
476590075Sobrien	 imode = GET_MODE_WIDER_MODE (imode))
476618334Speter      {
476718334Speter	int doing_unsigned = unsignedp;
476818334Speter
476918334Speter	icode = can_fix_p (imode, fmode, unsignedp, &must_trunc);
477018334Speter	if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp)
477118334Speter	  icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0;
477218334Speter
477318334Speter	if (icode != CODE_FOR_nothing)
477418334Speter	  {
477518334Speter	    to = protect_from_queue (to, 1);
477618334Speter	    from = protect_from_queue (from, 0);
477718334Speter
477818334Speter	    if (fmode != GET_MODE (from))
477918334Speter	      from = convert_to_mode (fmode, from, 0);
478018334Speter
478118334Speter	    if (must_trunc)
478218334Speter	      from = ftruncify (from);
478318334Speter
478418334Speter	    if (imode != GET_MODE (to))
478518334Speter	      target = gen_reg_rtx (imode);
478618334Speter
478718334Speter	    emit_unop_insn (icode, target, from,
478818334Speter			    doing_unsigned ? UNSIGNED_FIX : FIX);
478918334Speter	    if (target != to)
479018334Speter	      convert_move (to, target, unsignedp);
479118334Speter	    return;
479218334Speter	  }
479318334Speter      }
479418334Speter
479518334Speter  /* For an unsigned conversion, there is one more way to do it.
479618334Speter     If we have a signed conversion, we generate code that compares
479718334Speter     the real value to the largest representable positive number.  If if
479818334Speter     is smaller, the conversion is done normally.  Otherwise, subtract
479918334Speter     one plus the highest signed number, convert, and add it back.
480018334Speter
480118334Speter     We only need to check all real modes, since we know we didn't find
480218334Speter     anything with a wider integer mode.  */
480318334Speter
480418334Speter  if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
480518334Speter    for (fmode = GET_MODE (from); fmode != VOIDmode;
480618334Speter	 fmode = GET_MODE_WIDER_MODE (fmode))
480718334Speter      /* Make sure we won't lose significant bits doing this.  */
480818334Speter      if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to))
480918334Speter	  && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
481018334Speter					    &must_trunc))
481118334Speter	{
481218334Speter	  int bitsize;
481318334Speter	  REAL_VALUE_TYPE offset;
481418334Speter	  rtx limit, lab1, lab2, insn;
481518334Speter
481618334Speter	  bitsize = GET_MODE_BITSIZE (GET_MODE (to));
4817117395Skan	  real_2expN (&offset, bitsize - 1);
481818334Speter	  limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
481918334Speter	  lab1 = gen_label_rtx ();
482018334Speter	  lab2 = gen_label_rtx ();
482118334Speter
482218334Speter	  emit_queue ();
482318334Speter	  to = protect_from_queue (to, 1);
482418334Speter	  from = protect_from_queue (from, 0);
482518334Speter
482618334Speter	  if (flag_force_mem)
482718334Speter	    from = force_not_mem (from);
482818334Speter
482918334Speter	  if (fmode != GET_MODE (from))
483018334Speter	    from = convert_to_mode (fmode, from, 0);
483118334Speter
483218334Speter	  /* See if we need to do the subtraction.  */
483318334Speter	  do_pending_stack_adjust ();
483452284Sobrien	  emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
483590075Sobrien				   0, lab1);
483618334Speter
483718334Speter	  /* If not, do the signed "fix" and branch around fixup code.  */
483818334Speter	  expand_fix (to, from, 0);
483918334Speter	  emit_jump_insn (gen_jump (lab2));
484018334Speter	  emit_barrier ();
484118334Speter
484218334Speter	  /* Otherwise, subtract 2**(N-1), convert to signed number,
484318334Speter	     then add 2**(N-1).  Do the addition using XOR since this
484418334Speter	     will often generate better code.  */
484518334Speter	  emit_label (lab1);
484618334Speter	  target = expand_binop (GET_MODE (from), sub_optab, from, limit,
484718334Speter				 NULL_RTX, 0, OPTAB_LIB_WIDEN);
484818334Speter	  expand_fix (to, target, 0);
484918334Speter	  target = expand_binop (GET_MODE (to), xor_optab, to,
4850117395Skan				 gen_int_mode
4851117395Skan				 ((HOST_WIDE_INT) 1 << (bitsize - 1),
4852117395Skan				  GET_MODE (to)),
485318334Speter				 to, 1, OPTAB_LIB_WIDEN);
485418334Speter
485518334Speter	  if (target != to)
485618334Speter	    emit_move_insn (to, target);
485718334Speter
485818334Speter	  emit_label (lab2);
485918334Speter
486050397Sobrien	  if (mov_optab->handlers[(int) GET_MODE (to)].insn_code
486150397Sobrien	      != CODE_FOR_nothing)
486250397Sobrien	    {
486350397Sobrien	      /* Make a place for a REG_NOTE and add it.  */
486450397Sobrien	      insn = emit_move_insn (to, to);
486552284Sobrien	      set_unique_reg_note (insn,
486652284Sobrien	                           REG_EQUAL,
486752284Sobrien				   gen_rtx_fmt_e (UNSIGNED_FIX,
486852284Sobrien						  GET_MODE (to),
486952284Sobrien						  copy_rtx (from)));
487050397Sobrien	    }
487190075Sobrien
487218334Speter	  return;
487318334Speter	}
487418334Speter
487518334Speter  /* We can't do it with an insn, so use a library call.  But first ensure
487618334Speter     that the mode of TO is at least as wide as SImode, since those are the
487718334Speter     only library calls we know about.  */
487818334Speter
487918334Speter  if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
488018334Speter    {
488118334Speter      target = gen_reg_rtx (SImode);
488218334Speter
488318334Speter      expand_fix (target, from, unsignedp);
488418334Speter    }
488518334Speter  else if (GET_MODE (from) == SFmode)
488618334Speter    {
488718334Speter      if (GET_MODE (to) == SImode)
488818334Speter	libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc;
488918334Speter      else if (GET_MODE (to) == DImode)
489018334Speter	libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc;
489118334Speter      else if (GET_MODE (to) == TImode)
489218334Speter	libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc;
489318334Speter      else
489418334Speter	abort ();
489518334Speter    }
489618334Speter  else if (GET_MODE (from) == DFmode)
489718334Speter    {
489818334Speter      if (GET_MODE (to) == SImode)
489918334Speter	libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc;
490018334Speter      else if (GET_MODE (to) == DImode)
490118334Speter	libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc;
490218334Speter      else if (GET_MODE (to) == TImode)
490318334Speter	libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc;
490418334Speter      else
490518334Speter	abort ();
490618334Speter    }
490718334Speter  else if (GET_MODE (from) == XFmode)
490818334Speter    {
490918334Speter      if (GET_MODE (to) == SImode)
491018334Speter	libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc;
491118334Speter      else if (GET_MODE (to) == DImode)
491218334Speter	libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc;
491318334Speter      else if (GET_MODE (to) == TImode)
491418334Speter	libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc;
491518334Speter      else
491618334Speter	abort ();
491718334Speter    }
491818334Speter  else if (GET_MODE (from) == TFmode)
491918334Speter    {
492018334Speter      if (GET_MODE (to) == SImode)
492118334Speter	libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc;
492218334Speter      else if (GET_MODE (to) == DImode)
492318334Speter	libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc;
492418334Speter      else if (GET_MODE (to) == TImode)
492518334Speter	libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc;
492618334Speter      else
492718334Speter	abort ();
492818334Speter    }
492918334Speter  else
493018334Speter    abort ();
493118334Speter
493218334Speter  if (libfcn)
493318334Speter    {
493418334Speter      rtx insns;
493518334Speter      rtx value;
493618334Speter
493718334Speter      to = protect_from_queue (to, 1);
493818334Speter      from = protect_from_queue (from, 0);
493918334Speter
494018334Speter      if (flag_force_mem)
494118334Speter	from = force_not_mem (from);
494218334Speter
494318334Speter      start_sequence ();
494418334Speter
494590075Sobrien      value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
494690075Sobrien				       GET_MODE (to), 1, from,
494790075Sobrien				       GET_MODE (from));
494818334Speter      insns = get_insns ();
494918334Speter      end_sequence ();
495018334Speter
495118334Speter      emit_libcall_block (insns, target, value,
495250397Sobrien			  gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
495350397Sobrien					 GET_MODE (to), from));
495418334Speter    }
495518334Speter
495650397Sobrien  if (target != to)
495750397Sobrien    {
495850397Sobrien      if (GET_MODE (to) == GET_MODE (target))
495950397Sobrien        emit_move_insn (to, target);
496050397Sobrien      else
496150397Sobrien        convert_move (to, target, 0);
496250397Sobrien    }
496318334Speter}
496418334Speter
496590075Sobrien/* Report whether we have an instruction to perform the operation
496690075Sobrien   specified by CODE on operands of mode MODE.  */
496790075Sobrienint
496890075Sobrienhave_insn_for (code, mode)
496918334Speter     enum rtx_code code;
497090075Sobrien     enum machine_mode mode;
497118334Speter{
497290075Sobrien  return (code_to_optab[(int) code] != 0
497390075Sobrien	  && (code_to_optab[(int) code]->handlers[(int) mode].insn_code
497490075Sobrien	      != CODE_FOR_nothing));
497590075Sobrien}
497690075Sobrien
497790075Sobrien/* Create a blank optab.  */
497890075Sobrienstatic optab
497990075Sobriennew_optab ()
498090075Sobrien{
498118334Speter  int i;
4982117395Skan  optab op = (optab) ggc_alloc (sizeof (struct optab));
498318334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
498418334Speter    {
498518334Speter      op->handlers[i].insn_code = CODE_FOR_nothing;
498618334Speter      op->handlers[i].libfunc = 0;
498718334Speter    }
498818334Speter
498990075Sobrien  return op;
499090075Sobrien}
499118334Speter
499290075Sobrien/* Same, but fill in its code as CODE, and write it into the
499390075Sobrien   code_to_optab table.  */
499490075Sobrienstatic inline optab
499590075Sobrieninit_optab (code)
499690075Sobrien     enum rtx_code code;
499790075Sobrien{
499890075Sobrien  optab op = new_optab ();
499990075Sobrien  op->code = code;
500090075Sobrien  code_to_optab[(int) code] = op;
500118334Speter  return op;
500218334Speter}
500318334Speter
500490075Sobrien/* Same, but fill in its code as CODE, and do _not_ write it into
500590075Sobrien   the code_to_optab table.  */
500690075Sobrienstatic inline optab
500790075Sobrieninit_optabv (code)
500890075Sobrien     enum rtx_code code;
500990075Sobrien{
501090075Sobrien  optab op = new_optab ();
501190075Sobrien  op->code = code;
501290075Sobrien  return op;
501390075Sobrien}
501490075Sobrien
501518334Speter/* Initialize the libfunc fields of an entire group of entries in some
501618334Speter   optab.  Each entry is set equal to a string consisting of a leading
501718334Speter   pair of underscores followed by a generic operation name followed by
501818334Speter   a mode name (downshifted to lower case) followed by a single character
501918334Speter   representing the number of operands for the given operation (which is
502018334Speter   usually one of the characters '2', '3', or '4').
502118334Speter
502218334Speter   OPTABLE is the table in which libfunc fields are to be initialized.
502318334Speter   FIRST_MODE is the first machine mode index in the given optab to
502418334Speter     initialize.
502518334Speter   LAST_MODE is the last machine mode index in the given optab to
502618334Speter     initialize.
502718334Speter   OPNAME is the generic (string) name of the operation.
502818334Speter   SUFFIX is the character which specifies the number of operands for
502918334Speter     the given generic operation.
503018334Speter*/
503118334Speter
503218334Speterstatic void
503318334Speterinit_libfuncs (optable, first_mode, last_mode, opname, suffix)
5034117395Skan     optab optable;
5035117395Skan     int first_mode;
5036117395Skan     int last_mode;
5037117395Skan     const char *opname;
5038117395Skan     int suffix;
503918334Speter{
504090075Sobrien  int mode;
504190075Sobrien  unsigned opname_len = strlen (opname);
504218334Speter
504318334Speter  for (mode = first_mode; (int) mode <= (int) last_mode;
504418334Speter       mode = (enum machine_mode) ((int) mode + 1))
504518334Speter    {
5046117395Skan      const char *mname = GET_MODE_NAME (mode);
504790075Sobrien      unsigned mname_len = strlen (mname);
504890075Sobrien      char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
504990075Sobrien      char *p;
505090075Sobrien      const char *q;
505118334Speter
505218334Speter      p = libfunc_name;
505318334Speter      *p++ = '_';
505418334Speter      *p++ = '_';
505518334Speter      for (q = opname; *q; )
505618334Speter	*p++ = *q++;
505718334Speter      for (q = mname; *q; q++)
505890075Sobrien	*p++ = TOLOWER (*q);
505918334Speter      *p++ = suffix;
506090075Sobrien      *p = '\0';
506190075Sobrien
506218334Speter      optable->handlers[(int) mode].libfunc
506390075Sobrien	= gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
506490075Sobrien						       p - libfunc_name));
506518334Speter    }
506618334Speter}
506718334Speter
506818334Speter/* Initialize the libfunc fields of an entire group of entries in some
506918334Speter   optab which correspond to all integer mode operations.  The parameters
507018334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
507118334Speter   routine.  (See above).  */
507218334Speter
507318334Speterstatic void
507418334Speterinit_integral_libfuncs (optable, opname, suffix)
5075117395Skan     optab optable;
5076117395Skan     const char *opname;
5077117395Skan     int suffix;
507818334Speter{
507918334Speter  init_libfuncs (optable, SImode, TImode, opname, suffix);
508018334Speter}
508118334Speter
508218334Speter/* Initialize the libfunc fields of an entire group of entries in some
508318334Speter   optab which correspond to all real mode operations.  The parameters
508418334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
508518334Speter   routine.  (See above).  */
508618334Speter
508718334Speterstatic void
508818334Speterinit_floating_libfuncs (optable, opname, suffix)
5089117395Skan     optab optable;
5090117395Skan     const char *opname;
5091117395Skan     int suffix;
509218334Speter{
509318334Speter  init_libfuncs (optable, SFmode, TFmode, opname, suffix);
509418334Speter}
509518334Speter
509690075Sobrienrtx
509790075Sobrieninit_one_libfunc (name)
509890075Sobrien     const char *name;
509990075Sobrien{
5100117395Skan  /* Create a FUNCTION_DECL that can be passed to
5101117395Skan     targetm.encode_section_info.  */
510290075Sobrien  /* ??? We don't have any type information except for this is
510390075Sobrien     a function.  Pretend this is "int foo()".  */
510490075Sobrien  tree decl = build_decl (FUNCTION_DECL, get_identifier (name),
510590075Sobrien			  build_function_type (integer_type_node, NULL_TREE));
510690075Sobrien  DECL_ARTIFICIAL (decl) = 1;
510790075Sobrien  DECL_EXTERNAL (decl) = 1;
510890075Sobrien  TREE_PUBLIC (decl) = 1;
510918334Speter
511090075Sobrien  /* Return the symbol_ref from the mem rtx.  */
511190075Sobrien  return XEXP (DECL_RTL (decl), 0);
511290075Sobrien}
511390075Sobrien
511418334Speter/* Call this once to initialize the contents of the optabs
511518334Speter   appropriately for the current target machine.  */
511618334Speter
511718334Spetervoid
511818334Speterinit_optabs ()
511918334Speter{
512090075Sobrien  unsigned int i, j, k;
512150397Sobrien
512218334Speter  /* Start by initializing all tables to contain CODE_FOR_nothing.  */
512318334Speter
512490075Sobrien  for (i = 0; i < ARRAY_SIZE (fixtab); i++)
512590075Sobrien    for (j = 0; j < ARRAY_SIZE (fixtab[0]); j++)
512690075Sobrien      for (k = 0; k < ARRAY_SIZE (fixtab[0][0]); k++)
512790075Sobrien	fixtab[i][j][k] = CODE_FOR_nothing;
512818334Speter
512990075Sobrien  for (i = 0; i < ARRAY_SIZE (fixtrunctab); i++)
513090075Sobrien    for (j = 0; j < ARRAY_SIZE (fixtrunctab[0]); j++)
513190075Sobrien      for (k = 0; k < ARRAY_SIZE (fixtrunctab[0][0]); k++)
513290075Sobrien	fixtrunctab[i][j][k] = CODE_FOR_nothing;
513318334Speter
513490075Sobrien  for (i = 0; i < ARRAY_SIZE (floattab); i++)
513590075Sobrien    for (j = 0; j < ARRAY_SIZE (floattab[0]); j++)
513690075Sobrien      for (k = 0; k < ARRAY_SIZE (floattab[0][0]); k++)
513790075Sobrien	floattab[i][j][k] = CODE_FOR_nothing;
513818334Speter
513990075Sobrien  for (i = 0; i < ARRAY_SIZE (extendtab); i++)
514090075Sobrien    for (j = 0; j < ARRAY_SIZE (extendtab[0]); j++)
514190075Sobrien      for (k = 0; k < ARRAY_SIZE (extendtab[0][0]); k++)
514290075Sobrien	extendtab[i][j][k] = CODE_FOR_nothing;
514318334Speter
514418334Speter  for (i = 0; i < NUM_RTX_CODE; i++)
514518334Speter    setcc_gen_code[i] = CODE_FOR_nothing;
514618334Speter
514718334Speter#ifdef HAVE_conditional_move
514818334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
514918334Speter    movcc_gen_code[i] = CODE_FOR_nothing;
515018334Speter#endif
515118334Speter
515218334Speter  add_optab = init_optab (PLUS);
515390075Sobrien  addv_optab = init_optabv (PLUS);
515418334Speter  sub_optab = init_optab (MINUS);
515590075Sobrien  subv_optab = init_optabv (MINUS);
515618334Speter  smul_optab = init_optab (MULT);
515790075Sobrien  smulv_optab = init_optabv (MULT);
515818334Speter  smul_highpart_optab = init_optab (UNKNOWN);
515918334Speter  umul_highpart_optab = init_optab (UNKNOWN);
516018334Speter  smul_widen_optab = init_optab (UNKNOWN);
516118334Speter  umul_widen_optab = init_optab (UNKNOWN);
516218334Speter  sdiv_optab = init_optab (DIV);
516390075Sobrien  sdivv_optab = init_optabv (DIV);
516418334Speter  sdivmod_optab = init_optab (UNKNOWN);
516518334Speter  udiv_optab = init_optab (UDIV);
516618334Speter  udivmod_optab = init_optab (UNKNOWN);
516718334Speter  smod_optab = init_optab (MOD);
516818334Speter  umod_optab = init_optab (UMOD);
516918334Speter  ftrunc_optab = init_optab (UNKNOWN);
517018334Speter  and_optab = init_optab (AND);
517118334Speter  ior_optab = init_optab (IOR);
517218334Speter  xor_optab = init_optab (XOR);
517318334Speter  ashl_optab = init_optab (ASHIFT);
517418334Speter  ashr_optab = init_optab (ASHIFTRT);
517518334Speter  lshr_optab = init_optab (LSHIFTRT);
517618334Speter  rotl_optab = init_optab (ROTATE);
517718334Speter  rotr_optab = init_optab (ROTATERT);
517818334Speter  smin_optab = init_optab (SMIN);
517918334Speter  smax_optab = init_optab (SMAX);
518018334Speter  umin_optab = init_optab (UMIN);
518118334Speter  umax_optab = init_optab (UMAX);
518290075Sobrien
518390075Sobrien  /* These three have codes assigned exclusively for the sake of
518490075Sobrien     have_insn_for.  */
518590075Sobrien  mov_optab = init_optab (SET);
518690075Sobrien  movstrict_optab = init_optab (STRICT_LOW_PART);
518790075Sobrien  cmp_optab = init_optab (COMPARE);
518890075Sobrien
518918334Speter  ucmp_optab = init_optab (UNKNOWN);
519018334Speter  tst_optab = init_optab (UNKNOWN);
519118334Speter  neg_optab = init_optab (NEG);
519290075Sobrien  negv_optab = init_optabv (NEG);
519318334Speter  abs_optab = init_optab (ABS);
519490075Sobrien  absv_optab = init_optabv (ABS);
519518334Speter  one_cmpl_optab = init_optab (NOT);
519618334Speter  ffs_optab = init_optab (FFS);
519718334Speter  sqrt_optab = init_optab (SQRT);
519818334Speter  sin_optab = init_optab (UNKNOWN);
519918334Speter  cos_optab = init_optab (UNKNOWN);
5200117395Skan  exp_optab = init_optab (UNKNOWN);
5201117395Skan  log_optab = init_optab (UNKNOWN);
520218334Speter  strlen_optab = init_optab (UNKNOWN);
520390075Sobrien  cbranch_optab = init_optab (UNKNOWN);
520490075Sobrien  cmov_optab = init_optab (UNKNOWN);
520590075Sobrien  cstore_optab = init_optab (UNKNOWN);
520690075Sobrien  push_optab = init_optab (UNKNOWN);
520718334Speter
520818334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
520918334Speter    {
521018334Speter      movstr_optab[i] = CODE_FOR_nothing;
521150397Sobrien      clrstr_optab[i] = CODE_FOR_nothing;
521218334Speter
521318334Speter#ifdef HAVE_SECONDARY_RELOADS
521418334Speter      reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
521518334Speter#endif
521618334Speter    }
521718334Speter
521818334Speter  /* Fill in the optabs with the insns we support.  */
521918334Speter  init_all_optabs ();
522018334Speter
522118334Speter#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
522218334Speter  /* This flag says the same insns that convert to a signed fixnum
522318334Speter     also convert validly to an unsigned one.  */
522418334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
522518334Speter    for (j = 0; j < NUM_MACHINE_MODES; j++)
522618334Speter      fixtrunctab[i][j][1] = fixtrunctab[i][j][0];
522718334Speter#endif
522818334Speter
522918334Speter  /* Initialize the optabs with the names of the library functions.  */
523018334Speter  init_integral_libfuncs (add_optab, "add", '3');
523118334Speter  init_floating_libfuncs (add_optab, "add", '3');
523290075Sobrien  init_integral_libfuncs (addv_optab, "addv", '3');
523390075Sobrien  init_floating_libfuncs (addv_optab, "add", '3');
523418334Speter  init_integral_libfuncs (sub_optab, "sub", '3');
523518334Speter  init_floating_libfuncs (sub_optab, "sub", '3');
523690075Sobrien  init_integral_libfuncs (subv_optab, "subv", '3');
523790075Sobrien  init_floating_libfuncs (subv_optab, "sub", '3');
523818334Speter  init_integral_libfuncs (smul_optab, "mul", '3');
523918334Speter  init_floating_libfuncs (smul_optab, "mul", '3');
524090075Sobrien  init_integral_libfuncs (smulv_optab, "mulv", '3');
524190075Sobrien  init_floating_libfuncs (smulv_optab, "mul", '3');
524218334Speter  init_integral_libfuncs (sdiv_optab, "div", '3');
524390075Sobrien  init_floating_libfuncs (sdiv_optab, "div", '3');
524490075Sobrien  init_integral_libfuncs (sdivv_optab, "divv", '3');
524518334Speter  init_integral_libfuncs (udiv_optab, "udiv", '3');
524618334Speter  init_integral_libfuncs (sdivmod_optab, "divmod", '4');
524718334Speter  init_integral_libfuncs (udivmod_optab, "udivmod", '4');
524818334Speter  init_integral_libfuncs (smod_optab, "mod", '3');
524918334Speter  init_integral_libfuncs (umod_optab, "umod", '3');
525018334Speter  init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
525118334Speter  init_integral_libfuncs (and_optab, "and", '3');
525218334Speter  init_integral_libfuncs (ior_optab, "ior", '3');
525318334Speter  init_integral_libfuncs (xor_optab, "xor", '3');
525418334Speter  init_integral_libfuncs (ashl_optab, "ashl", '3');
525518334Speter  init_integral_libfuncs (ashr_optab, "ashr", '3');
525618334Speter  init_integral_libfuncs (lshr_optab, "lshr", '3');
525718334Speter  init_integral_libfuncs (smin_optab, "min", '3');
525818334Speter  init_floating_libfuncs (smin_optab, "min", '3');
525918334Speter  init_integral_libfuncs (smax_optab, "max", '3');
526018334Speter  init_floating_libfuncs (smax_optab, "max", '3');
526118334Speter  init_integral_libfuncs (umin_optab, "umin", '3');
526218334Speter  init_integral_libfuncs (umax_optab, "umax", '3');
526318334Speter  init_integral_libfuncs (neg_optab, "neg", '2');
526418334Speter  init_floating_libfuncs (neg_optab, "neg", '2');
526590075Sobrien  init_integral_libfuncs (negv_optab, "negv", '2');
526690075Sobrien  init_floating_libfuncs (negv_optab, "neg", '2');
526718334Speter  init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
526818334Speter  init_integral_libfuncs (ffs_optab, "ffs", '2');
526918334Speter
527018334Speter  /* Comparison libcalls for integers MUST come in pairs, signed/unsigned.  */
527118334Speter  init_integral_libfuncs (cmp_optab, "cmp", '2');
527218334Speter  init_integral_libfuncs (ucmp_optab, "ucmp", '2');
527318334Speter  init_floating_libfuncs (cmp_optab, "cmp", '2');
527418334Speter
527518334Speter#ifdef MULSI3_LIBCALL
527618334Speter  smul_optab->handlers[(int) SImode].libfunc
527790075Sobrien    = init_one_libfunc (MULSI3_LIBCALL);
527818334Speter#endif
527918334Speter#ifdef MULDI3_LIBCALL
528018334Speter  smul_optab->handlers[(int) DImode].libfunc
528190075Sobrien    = init_one_libfunc (MULDI3_LIBCALL);
528218334Speter#endif
528318334Speter
528418334Speter#ifdef DIVSI3_LIBCALL
528518334Speter  sdiv_optab->handlers[(int) SImode].libfunc
528690075Sobrien    = init_one_libfunc (DIVSI3_LIBCALL);
528718334Speter#endif
528818334Speter#ifdef DIVDI3_LIBCALL
528918334Speter  sdiv_optab->handlers[(int) DImode].libfunc
529090075Sobrien    = init_one_libfunc (DIVDI3_LIBCALL);
529118334Speter#endif
529218334Speter
529318334Speter#ifdef UDIVSI3_LIBCALL
529418334Speter  udiv_optab->handlers[(int) SImode].libfunc
529590075Sobrien    = init_one_libfunc (UDIVSI3_LIBCALL);
529618334Speter#endif
529718334Speter#ifdef UDIVDI3_LIBCALL
529818334Speter  udiv_optab->handlers[(int) DImode].libfunc
529990075Sobrien    = init_one_libfunc (UDIVDI3_LIBCALL);
530018334Speter#endif
530118334Speter
530218334Speter#ifdef MODSI3_LIBCALL
530318334Speter  smod_optab->handlers[(int) SImode].libfunc
530490075Sobrien    = init_one_libfunc (MODSI3_LIBCALL);
530518334Speter#endif
530618334Speter#ifdef MODDI3_LIBCALL
530718334Speter  smod_optab->handlers[(int) DImode].libfunc
530890075Sobrien    = init_one_libfunc (MODDI3_LIBCALL);
530918334Speter#endif
531018334Speter
531118334Speter#ifdef UMODSI3_LIBCALL
531218334Speter  umod_optab->handlers[(int) SImode].libfunc
531390075Sobrien    = init_one_libfunc (UMODSI3_LIBCALL);
531418334Speter#endif
531518334Speter#ifdef UMODDI3_LIBCALL
531618334Speter  umod_optab->handlers[(int) DImode].libfunc
531790075Sobrien    = init_one_libfunc (UMODDI3_LIBCALL);
531818334Speter#endif
531918334Speter
532018334Speter  /* Use cabs for DC complex abs, since systems generally have cabs.
532118334Speter     Don't define any libcall for SCmode, so that cabs will be used.  */
532218334Speter  abs_optab->handlers[(int) DCmode].libfunc
532390075Sobrien    = init_one_libfunc ("cabs");
532418334Speter
532518334Speter  /* The ffs function operates on `int'.  */
532690075Sobrien  ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
532790075Sobrien    = init_one_libfunc ("ffs");
532818334Speter
532990075Sobrien  extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2");
533090075Sobrien  extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2");
533190075Sobrien  extendsftf2_libfunc = init_one_libfunc ("__extendsftf2");
533290075Sobrien  extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2");
533390075Sobrien  extenddftf2_libfunc = init_one_libfunc ("__extenddftf2");
533418334Speter
533590075Sobrien  truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2");
533690075Sobrien  truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2");
533790075Sobrien  trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2");
533890075Sobrien  truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2");
533990075Sobrien  trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2");
534018334Speter
534196263Sobrien  abort_libfunc = init_one_libfunc ("abort");
534290075Sobrien  memcpy_libfunc = init_one_libfunc ("memcpy");
534390075Sobrien  memmove_libfunc = init_one_libfunc ("memmove");
534490075Sobrien  bcopy_libfunc = init_one_libfunc ("bcopy");
534590075Sobrien  memcmp_libfunc = init_one_libfunc ("memcmp");
534690075Sobrien  bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");
534790075Sobrien  memset_libfunc = init_one_libfunc ("memset");
534890075Sobrien  bzero_libfunc = init_one_libfunc ("bzero");
534918334Speter
535090075Sobrien  unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
535190075Sobrien					    ? "_Unwind_SjLj_Resume"
535290075Sobrien					    : "_Unwind_Resume");
535350397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
535490075Sobrien  setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
535590075Sobrien  longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
535650397Sobrien#else
535790075Sobrien  setjmp_libfunc = init_one_libfunc ("setjmp");
535890075Sobrien  longjmp_libfunc = init_one_libfunc ("longjmp");
535950397Sobrien#endif
536090075Sobrien  unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
536190075Sobrien  unwind_sjlj_unregister_libfunc
536290075Sobrien    = init_one_libfunc ("_Unwind_SjLj_Unregister");
536318334Speter
536490075Sobrien  eqhf2_libfunc = init_one_libfunc ("__eqhf2");
536590075Sobrien  nehf2_libfunc = init_one_libfunc ("__nehf2");
536690075Sobrien  gthf2_libfunc = init_one_libfunc ("__gthf2");
536790075Sobrien  gehf2_libfunc = init_one_libfunc ("__gehf2");
536890075Sobrien  lthf2_libfunc = init_one_libfunc ("__lthf2");
536990075Sobrien  lehf2_libfunc = init_one_libfunc ("__lehf2");
537090075Sobrien  unordhf2_libfunc = init_one_libfunc ("__unordhf2");
537118334Speter
537290075Sobrien  eqsf2_libfunc = init_one_libfunc ("__eqsf2");
537390075Sobrien  nesf2_libfunc = init_one_libfunc ("__nesf2");
537490075Sobrien  gtsf2_libfunc = init_one_libfunc ("__gtsf2");
537590075Sobrien  gesf2_libfunc = init_one_libfunc ("__gesf2");
537690075Sobrien  ltsf2_libfunc = init_one_libfunc ("__ltsf2");
537790075Sobrien  lesf2_libfunc = init_one_libfunc ("__lesf2");
537890075Sobrien  unordsf2_libfunc = init_one_libfunc ("__unordsf2");
537918334Speter
538090075Sobrien  eqdf2_libfunc = init_one_libfunc ("__eqdf2");
538190075Sobrien  nedf2_libfunc = init_one_libfunc ("__nedf2");
538290075Sobrien  gtdf2_libfunc = init_one_libfunc ("__gtdf2");
538390075Sobrien  gedf2_libfunc = init_one_libfunc ("__gedf2");
538490075Sobrien  ltdf2_libfunc = init_one_libfunc ("__ltdf2");
538590075Sobrien  ledf2_libfunc = init_one_libfunc ("__ledf2");
538690075Sobrien  unorddf2_libfunc = init_one_libfunc ("__unorddf2");
538718334Speter
538890075Sobrien  eqxf2_libfunc = init_one_libfunc ("__eqxf2");
538990075Sobrien  nexf2_libfunc = init_one_libfunc ("__nexf2");
539090075Sobrien  gtxf2_libfunc = init_one_libfunc ("__gtxf2");
539190075Sobrien  gexf2_libfunc = init_one_libfunc ("__gexf2");
539290075Sobrien  ltxf2_libfunc = init_one_libfunc ("__ltxf2");
539390075Sobrien  lexf2_libfunc = init_one_libfunc ("__lexf2");
539490075Sobrien  unordxf2_libfunc = init_one_libfunc ("__unordxf2");
539518334Speter
539690075Sobrien  eqtf2_libfunc = init_one_libfunc ("__eqtf2");
539790075Sobrien  netf2_libfunc = init_one_libfunc ("__netf2");
539890075Sobrien  gttf2_libfunc = init_one_libfunc ("__gttf2");
539990075Sobrien  getf2_libfunc = init_one_libfunc ("__getf2");
540090075Sobrien  lttf2_libfunc = init_one_libfunc ("__lttf2");
540190075Sobrien  letf2_libfunc = init_one_libfunc ("__letf2");
540290075Sobrien  unordtf2_libfunc = init_one_libfunc ("__unordtf2");
540318334Speter
540490075Sobrien  floatsisf_libfunc = init_one_libfunc ("__floatsisf");
540590075Sobrien  floatdisf_libfunc = init_one_libfunc ("__floatdisf");
540690075Sobrien  floattisf_libfunc = init_one_libfunc ("__floattisf");
540718334Speter
540890075Sobrien  floatsidf_libfunc = init_one_libfunc ("__floatsidf");
540990075Sobrien  floatdidf_libfunc = init_one_libfunc ("__floatdidf");
541090075Sobrien  floattidf_libfunc = init_one_libfunc ("__floattidf");
541118334Speter
541290075Sobrien  floatsixf_libfunc = init_one_libfunc ("__floatsixf");
541390075Sobrien  floatdixf_libfunc = init_one_libfunc ("__floatdixf");
541490075Sobrien  floattixf_libfunc = init_one_libfunc ("__floattixf");
541518334Speter
541690075Sobrien  floatsitf_libfunc = init_one_libfunc ("__floatsitf");
541790075Sobrien  floatditf_libfunc = init_one_libfunc ("__floatditf");
541890075Sobrien  floattitf_libfunc = init_one_libfunc ("__floattitf");
541918334Speter
542090075Sobrien  fixsfsi_libfunc = init_one_libfunc ("__fixsfsi");
542190075Sobrien  fixsfdi_libfunc = init_one_libfunc ("__fixsfdi");
542290075Sobrien  fixsfti_libfunc = init_one_libfunc ("__fixsfti");
542318334Speter
542490075Sobrien  fixdfsi_libfunc = init_one_libfunc ("__fixdfsi");
542590075Sobrien  fixdfdi_libfunc = init_one_libfunc ("__fixdfdi");
542690075Sobrien  fixdfti_libfunc = init_one_libfunc ("__fixdfti");
542718334Speter
542890075Sobrien  fixxfsi_libfunc = init_one_libfunc ("__fixxfsi");
542990075Sobrien  fixxfdi_libfunc = init_one_libfunc ("__fixxfdi");
543090075Sobrien  fixxfti_libfunc = init_one_libfunc ("__fixxfti");
543118334Speter
543290075Sobrien  fixtfsi_libfunc = init_one_libfunc ("__fixtfsi");
543390075Sobrien  fixtfdi_libfunc = init_one_libfunc ("__fixtfdi");
543490075Sobrien  fixtfti_libfunc = init_one_libfunc ("__fixtfti");
543518334Speter
543690075Sobrien  fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi");
543790075Sobrien  fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi");
543890075Sobrien  fixunssfti_libfunc = init_one_libfunc ("__fixunssfti");
543918334Speter
544090075Sobrien  fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi");
544190075Sobrien  fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi");
544290075Sobrien  fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti");
544318334Speter
544490075Sobrien  fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi");
544590075Sobrien  fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi");
544690075Sobrien  fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti");
544718334Speter
544890075Sobrien  fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi");
544990075Sobrien  fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi");
545090075Sobrien  fixunstfti_libfunc = init_one_libfunc ("__fixunstfti");
545150397Sobrien
545252284Sobrien  /* For function entry/exit instrumentation.  */
545352284Sobrien  profile_function_entry_libfunc
545490075Sobrien    = init_one_libfunc ("__cyg_profile_func_enter");
545552284Sobrien  profile_function_exit_libfunc
545690075Sobrien    = init_one_libfunc ("__cyg_profile_func_exit");
545752284Sobrien
5458117395Skan  if (HAVE_conditional_trap)
5459117395Skan    trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
546050397Sobrien
546118334Speter#ifdef INIT_TARGET_OPTABS
546218334Speter  /* Allow the target to add more libcalls or rename some, etc.  */
546318334Speter  INIT_TARGET_OPTABS;
546418334Speter#endif
546518334Speter}
546650397Sobrien
546750397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
546850397Sobrien   CODE.  Return 0 on failure.  */
546950397Sobrien
547050397Sobrienrtx
547150397Sobriengen_cond_trap (code, op1, op2, tcode)
5472117395Skan     enum rtx_code code ATTRIBUTE_UNUSED;
5473117395Skan     rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED;
547450397Sobrien{
547550397Sobrien  enum machine_mode mode = GET_MODE (op1);
5476117395Skan  enum insn_code icode;
5477117395Skan  rtx insn;
547850397Sobrien
5479117395Skan  if (!HAVE_conditional_trap)
5480117395Skan    return 0;
5481117395Skan
548250397Sobrien  if (mode == VOIDmode)
548350397Sobrien    return 0;
548450397Sobrien
5485117395Skan  icode = cmp_optab->handlers[(int) mode].insn_code;
5486117395Skan  if (icode == CODE_FOR_nothing)
5487117395Skan    return 0;
5488117395Skan
5489117395Skan  start_sequence ();
5490117395Skan  op1 = prepare_operand (icode, op1, 0, mode, mode, 0);
5491119256Skan  op2 = prepare_operand (icode, op2, 1, mode, mode, 0);
5492119256Skan  if (!op1 || !op2)
5493119256Skan    {
5494119256Skan      end_sequence ();
5495119256Skan      return 0;
5496119256Skan    }
5497117395Skan  emit_insn (GEN_FCN (icode) (op1, op2));
5498117395Skan
5499117395Skan  PUT_CODE (trap_rtx, code);
5500117395Skan  insn = gen_conditional_trap (trap_rtx, tcode);
5501117395Skan  if (insn)
550250397Sobrien    {
5503117395Skan      emit_insn (insn);
5504117395Skan      insn = get_insns ();
550550397Sobrien    }
5506117395Skan  end_sequence ();
550750397Sobrien
5508117395Skan  return insn;
550950397Sobrien}
5510117395Skan
5511117395Skan#include "gt-optabs.h"
5512