118334Speter/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
290075Sobrien   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3169689Skan   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
4169689Skan   Free Software Foundation, Inc.
518334Speter
690075SobrienThis file is part of GCC.
718334Speter
890075SobrienGCC is free software; you can redistribute it and/or modify it under
990075Sobrienthe terms of the GNU General Public License as published by the Free
1090075SobrienSoftware Foundation; either version 2, or (at your option) any later
1190075Sobrienversion.
1218334Speter
1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1590075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1690075Sobrienfor more details.
1718334Speter
1818334SpeterYou should have received a copy of the GNU General Public License
1990075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21169689Skan02110-1301, USA.  */
2218334Speter
2318334Speter
2418334Speter#include "config.h"
2550397Sobrien#include "system.h"
26132718Skan#include "coretypes.h"
27132718Skan#include "tm.h"
2852284Sobrien#include "toplev.h"
2952284Sobrien
3052284Sobrien/* Include insn-config.h before expr.h so that HAVE_conditional_move
3190075Sobrien   is properly defined.  */
3252284Sobrien#include "insn-config.h"
3318334Speter#include "rtl.h"
3418334Speter#include "tree.h"
3590075Sobrien#include "tm_p.h"
3618334Speter#include "flags.h"
3790075Sobrien#include "function.h"
3890075Sobrien#include "except.h"
3918334Speter#include "expr.h"
4090075Sobrien#include "optabs.h"
4190075Sobrien#include "libfuncs.h"
4218334Speter#include "recog.h"
4318334Speter#include "reload.h"
4490075Sobrien#include "ggc.h"
4590075Sobrien#include "real.h"
46110611Skan#include "basic-block.h"
47132718Skan#include "target.h"
4818334Speter
4918334Speter/* Each optab contains info on how this target machine
5018334Speter   can perform a particular operation
5118334Speter   for all sizes and kinds of operands.
5218334Speter
5318334Speter   The operation to be performed is often specified
5418334Speter   by passing one of these optabs as an argument.
5518334Speter
5618334Speter   See expr.h for documentation of these optabs.  */
5718334Speter
5890075Sobrienoptab optab_table[OTI_MAX];
5918334Speter
6090075Sobrienrtx libfunc_table[LTI_MAX];
6118334Speter
62132718Skan/* Tables of patterns for converting one mode to another.  */
63169689Skanconvert_optab convert_optab_table[COI_MAX];
6418334Speter
6518334Speter/* Contains the optab used for each rtx code.  */
6618334Speteroptab code_to_optab[NUM_RTX_CODE + 1];
6718334Speter
6818334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
6918334Speter   gives the gen_function to make a branch to test that condition.  */
7018334Speter
7118334Speterrtxfun bcc_gen_fctn[NUM_RTX_CODE];
7218334Speter
7318334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
7418334Speter   gives the insn code to make a store-condition insn
7518334Speter   to test that condition.  */
7618334Speter
7718334Speterenum insn_code setcc_gen_code[NUM_RTX_CODE];
7818334Speter
7918334Speter#ifdef HAVE_conditional_move
8018334Speter/* Indexed by the machine mode, gives the insn code to make a conditional
8118334Speter   move insn.  This is not indexed by the rtx-code like bcc_gen_fctn and
8218334Speter   setcc_gen_code to cut down on the number of named patterns.  Consider a day
8318334Speter   when a lot more rtx codes are conditional (eg: for the ARM).  */
8418334Speter
8518334Speterenum insn_code movcc_gen_code[NUM_MACHINE_MODES];
8618334Speter#endif
8718334Speter
88169689Skan/* Indexed by the machine mode, gives the insn code for vector conditional
89169689Skan   operation.  */
90169689Skan
91169689Skanenum insn_code vcond_gen_code[NUM_MACHINE_MODES];
92169689Skanenum insn_code vcondu_gen_code[NUM_MACHINE_MODES];
93169689Skan
94117395Skan/* The insn generating function can not take an rtx_code argument.
95117395Skan   TRAP_RTX is used as an rtx argument.  Its code is replaced with
96117395Skan   the code to be used in the trap insn and all other fields are ignored.  */
97117395Skanstatic GTY(()) rtx trap_rtx;
98117395Skan
99132718Skanstatic int add_equal_note (rtx, rtx, enum rtx_code, rtx, rtx);
100132718Skanstatic rtx widen_operand (rtx, enum machine_mode, enum machine_mode, int,
101132718Skan			  int);
102132718Skanstatic void prepare_cmp_insn (rtx *, rtx *, enum rtx_code *, rtx,
103132718Skan			      enum machine_mode *, int *,
104132718Skan			      enum can_compare_purpose);
105132718Skanstatic enum insn_code can_fix_p (enum machine_mode, enum machine_mode, int,
106132718Skan				 int *);
107132718Skanstatic enum insn_code can_float_p (enum machine_mode, enum machine_mode, int);
108132718Skanstatic optab new_optab (void);
109132718Skanstatic convert_optab new_convert_optab (void);
110132718Skanstatic inline optab init_optab (enum rtx_code);
111132718Skanstatic inline optab init_optabv (enum rtx_code);
112132718Skanstatic inline convert_optab init_convert_optab (enum rtx_code);
113132718Skanstatic void init_libfuncs (optab, int, int, const char *, int);
114132718Skanstatic void init_integral_libfuncs (optab, const char *, int);
115132718Skanstatic void init_floating_libfuncs (optab, const char *, int);
116132718Skanstatic void init_interclass_conv_libfuncs (convert_optab, const char *,
117132718Skan					   enum mode_class, enum mode_class);
118132718Skanstatic void init_intraclass_conv_libfuncs (convert_optab, const char *,
119132718Skan					   enum mode_class, bool);
120132718Skanstatic void emit_cmp_and_jump_insn_1 (rtx, rtx, enum machine_mode,
121132718Skan				      enum rtx_code, int, rtx);
122132718Skanstatic void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
123132718Skan				   enum machine_mode *, int *);
124132718Skanstatic rtx widen_clz (enum machine_mode, rtx, rtx);
125132718Skanstatic rtx expand_parity (enum machine_mode, rtx, rtx);
126169689Skanstatic enum rtx_code get_rtx_code (enum tree_code, bool);
127169689Skanstatic rtx vector_compare_rtx (tree, bool, enum insn_code);
128117395Skan
129117395Skan#ifndef HAVE_conditional_trap
130117395Skan#define HAVE_conditional_trap 0
131169689Skan#define gen_conditional_trap(a,b) (gcc_unreachable (), NULL_RTX)
132117395Skan#endif
13318334Speter
134117395Skan/* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
13518334Speter   the result of operation CODE applied to OP0 (and OP1 if it is a binary
13618334Speter   operation).
13718334Speter
13818334Speter   If the last insn does not set TARGET, don't do anything, but return 1.
13918334Speter
14018334Speter   If a previous insn sets TARGET and TARGET is one of OP0 or OP1,
14118334Speter   don't add the REG_EQUAL note but return 0.  Our caller can then try
14218334Speter   again, ensuring that TARGET is not one of the operands.  */
14318334Speter
14418334Speterstatic int
145132718Skanadd_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
14618334Speter{
147117395Skan  rtx last_insn, insn, set;
14818334Speter  rtx note;
14918334Speter
150169689Skan  gcc_assert (insns && INSN_P (insns) && NEXT_INSN (insns));
151117395Skan
152169689Skan  if (GET_RTX_CLASS (code) != RTX_COMM_ARITH
153169689Skan      && GET_RTX_CLASS (code) != RTX_BIN_ARITH
154169689Skan      && GET_RTX_CLASS (code) != RTX_COMM_COMPARE
155169689Skan      && GET_RTX_CLASS (code) != RTX_COMPARE
156169689Skan      && GET_RTX_CLASS (code) != RTX_UNARY)
15718334Speter    return 1;
15818334Speter
159117395Skan  if (GET_CODE (target) == ZERO_EXTRACT)
160117395Skan    return 1;
161117395Skan
162117395Skan  for (last_insn = insns;
163117395Skan       NEXT_INSN (last_insn) != NULL_RTX;
164117395Skan       last_insn = NEXT_INSN (last_insn))
165117395Skan    ;
166117395Skan
167117395Skan  set = single_set (last_insn);
168117395Skan  if (set == NULL_RTX)
169117395Skan    return 1;
170117395Skan
171117395Skan  if (! rtx_equal_p (SET_DEST (set), target)
172132718Skan      /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside it.  */
173117395Skan      && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
174132718Skan	  || ! rtx_equal_p (XEXP (SET_DEST (set), 0), target)))
175117395Skan    return 1;
176117395Skan
17718334Speter  /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET
17818334Speter     besides the last insn.  */
17918334Speter  if (reg_overlap_mentioned_p (target, op0)
18018334Speter      || (op1 && reg_overlap_mentioned_p (target, op1)))
181117395Skan    {
182117395Skan      insn = PREV_INSN (last_insn);
183117395Skan      while (insn != NULL_RTX)
184117395Skan	{
185117395Skan	  if (reg_set_p (target, insn))
186117395Skan	    return 0;
18718334Speter
188117395Skan	  insn = PREV_INSN (insn);
189117395Skan	}
190117395Skan    }
191117395Skan
192169689Skan  if (GET_RTX_CLASS (code) == RTX_UNARY)
19350397Sobrien    note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0));
19418334Speter  else
19550397Sobrien    note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
19618334Speter
197117395Skan  set_unique_reg_note (last_insn, REG_EQUAL, note);
19818334Speter
19918334Speter  return 1;
20018334Speter}
20118334Speter
20218334Speter/* Widen OP to MODE and return the rtx for the widened operand.  UNSIGNEDP
20318334Speter   says whether OP is signed or unsigned.  NO_EXTEND is nonzero if we need
204132718Skan   not actually do a sign-extend or zero-extend, but can leave the
20518334Speter   higher-order bits of the result rtx undefined, for example, in the case
20618334Speter   of logical operations, but not right shifts.  */
20718334Speter
20818334Speterstatic rtx
209132718Skanwiden_operand (rtx op, enum machine_mode mode, enum machine_mode oldmode,
210132718Skan	       int unsignedp, int no_extend)
21118334Speter{
21218334Speter  rtx result;
21318334Speter
21496263Sobrien  /* If we don't have to extend and this is a constant, return it.  */
21596263Sobrien  if (no_extend && GET_MODE (op) == VOIDmode)
21696263Sobrien    return op;
21796263Sobrien
21896263Sobrien  /* If we must extend do so.  If OP is a SUBREG for a promoted object, also
21996263Sobrien     extend since it will be more efficient to do so unless the signedness of
22096263Sobrien     a promoted object differs from our extension.  */
22118334Speter  if (! no_extend
22296263Sobrien      || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)
22396263Sobrien	  && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp))
22418334Speter    return convert_modes (mode, oldmode, op, unsignedp);
22518334Speter
22618334Speter  /* If MODE is no wider than a single word, we return a paradoxical
22718334Speter     SUBREG.  */
22818334Speter  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
22950397Sobrien    return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0);
23018334Speter
23118334Speter  /* Otherwise, get an object of MODE, clobber it, and set the low-order
23218334Speter     part to OP.  */
23318334Speter
23418334Speter  result = gen_reg_rtx (mode);
23550397Sobrien  emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
23618334Speter  emit_move_insn (gen_lowpart (GET_MODE (op), result), op);
23718334Speter  return result;
23818334Speter}
23918334Speter
240169689Skan/* Return the optab used for computing the operation given by
241169689Skan   the tree code, CODE.  This function is not always usable (for
242169689Skan   example, it cannot give complete results for multiplication
243169689Skan   or division) but probably ought to be relied on more widely
244169689Skan   throughout the expander.  */
245169689Skanoptab
246169689Skanoptab_for_tree_code (enum tree_code code, tree type)
24752284Sobrien{
248169689Skan  bool trapv;
249169689Skan  switch (code)
25090075Sobrien    {
251169689Skan    case BIT_AND_EXPR:
252169689Skan      return and_optab;
25390075Sobrien
254169689Skan    case BIT_IOR_EXPR:
255169689Skan      return ior_optab;
25652284Sobrien
257169689Skan    case BIT_NOT_EXPR:
258169689Skan      return one_cmpl_optab;
25952284Sobrien
260169689Skan    case BIT_XOR_EXPR:
261169689Skan      return xor_optab;
26252284Sobrien
263169689Skan    case TRUNC_MOD_EXPR:
264169689Skan    case CEIL_MOD_EXPR:
265169689Skan    case FLOOR_MOD_EXPR:
266169689Skan    case ROUND_MOD_EXPR:
267169689Skan      return TYPE_UNSIGNED (type) ? umod_optab : smod_optab;
26852284Sobrien
269169689Skan    case RDIV_EXPR:
270169689Skan    case TRUNC_DIV_EXPR:
271169689Skan    case CEIL_DIV_EXPR:
272169689Skan    case FLOOR_DIV_EXPR:
273169689Skan    case ROUND_DIV_EXPR:
274169689Skan    case EXACT_DIV_EXPR:
275169689Skan      return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
27652284Sobrien
277169689Skan    case LSHIFT_EXPR:
278169689Skan      return ashl_optab;
27952284Sobrien
280169689Skan    case RSHIFT_EXPR:
281169689Skan      return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab;
28252284Sobrien
283169689Skan    case LROTATE_EXPR:
284169689Skan      return rotl_optab;
28552284Sobrien
286169689Skan    case RROTATE_EXPR:
287169689Skan      return rotr_optab;
288132718Skan
289169689Skan    case MAX_EXPR:
290169689Skan      return TYPE_UNSIGNED (type) ? umax_optab : smax_optab;
29152284Sobrien
292169689Skan    case MIN_EXPR:
293169689Skan      return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
29452284Sobrien
295169689Skan    case REALIGN_LOAD_EXPR:
296169689Skan      return vec_realign_load_optab;
29752284Sobrien
298169689Skan    case WIDEN_SUM_EXPR:
299169689Skan      return TYPE_UNSIGNED (type) ? usum_widen_optab : ssum_widen_optab;
30052284Sobrien
301169689Skan    case DOT_PROD_EXPR:
302169689Skan      return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab;
30352284Sobrien
304169689Skan    case REDUC_MAX_EXPR:
305169689Skan      return TYPE_UNSIGNED (type) ? reduc_umax_optab : reduc_smax_optab;
306132718Skan
307169689Skan    case REDUC_MIN_EXPR:
308169689Skan      return TYPE_UNSIGNED (type) ? reduc_umin_optab : reduc_smin_optab;
30952284Sobrien
310169689Skan    case REDUC_PLUS_EXPR:
311169689Skan      return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
31252284Sobrien
313169689Skan    case VEC_LSHIFT_EXPR:
314169689Skan      return vec_shl_optab;
31552284Sobrien
316169689Skan    case VEC_RSHIFT_EXPR:
317169689Skan      return vec_shr_optab;
31852284Sobrien
319169689Skan    default:
320169689Skan      break;
32152284Sobrien    }
32252284Sobrien
323169689Skan  trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
324169689Skan  switch (code)
325169689Skan    {
326169689Skan    case PLUS_EXPR:
327169689Skan      return trapv ? addv_optab : add_optab;
32852284Sobrien
329169689Skan    case MINUS_EXPR:
330169689Skan      return trapv ? subv_optab : sub_optab;
33152284Sobrien
332169689Skan    case MULT_EXPR:
333169689Skan      return trapv ? smulv_optab : smul_optab;
33452284Sobrien
335169689Skan    case NEGATE_EXPR:
336169689Skan      return trapv ? negv_optab : neg_optab;
33752284Sobrien
338169689Skan    case ABS_EXPR:
339169689Skan      return trapv ? absv_optab : abs_optab;
34052284Sobrien
341169689Skan    default:
342169689Skan      return NULL;
343169689Skan    }
34452284Sobrien}
34552284Sobrien
34652284Sobrien
347169689Skan/* Expand vector widening operations.
34890075Sobrien
349169689Skan   There are two different classes of operations handled here:
350169689Skan   1) Operations whose result is wider than all the arguments to the operation.
351169689Skan      Examples: VEC_UNPACK_HI/LO_EXPR, VEC_WIDEN_MULT_HI/LO_EXPR
352169689Skan      In this case OP0 and optionally OP1 would be initialized,
353169689Skan      but WIDE_OP wouldn't (not relevant for this case).
354169689Skan   2) Operations whose result is of the same size as the last argument to the
355169689Skan      operation, but wider than all the other arguments to the operation.
356169689Skan      Examples: WIDEN_SUM_EXPR, VEC_DOT_PROD_EXPR.
357169689Skan      In the case WIDE_OP, OP0 and optionally OP1 would be initialized.
358169689Skan
359169689Skan   E.g, when called to expand the following operations, this is how
360169689Skan   the arguments will be initialized:
361169689Skan                                nops    OP0     OP1     WIDE_OP
362169689Skan   widening-sum                 2       oprnd0  -       oprnd1
363169689Skan   widening-dot-product         3       oprnd0  oprnd1  oprnd2
364169689Skan   widening-mult                2       oprnd0  oprnd1  -
365169689Skan   type-promotion (vec-unpack)  1       oprnd0  -       -  */
366169689Skan
367169689Skanrtx
368169689Skanexpand_widen_pattern_expr (tree exp, rtx op0, rtx op1, rtx wide_op, rtx target,
369169689Skan                           int unsignedp)
370169689Skan{
371169689Skan  tree oprnd0, oprnd1, oprnd2;
372169689Skan  enum machine_mode wmode = 0, tmode0, tmode1 = 0;
373169689Skan  optab widen_pattern_optab;
374169689Skan  int icode;
375169689Skan  enum machine_mode xmode0, xmode1 = 0, wxmode = 0;
376169689Skan  rtx temp;
377169689Skan  rtx pat;
378169689Skan  rtx xop0, xop1, wxop;
379169689Skan  int nops = TREE_CODE_LENGTH (TREE_CODE (exp));
380169689Skan
381169689Skan  oprnd0 = TREE_OPERAND (exp, 0);
382169689Skan  tmode0 = TYPE_MODE (TREE_TYPE (oprnd0));
383169689Skan  widen_pattern_optab =
384169689Skan        optab_for_tree_code (TREE_CODE (exp), TREE_TYPE (oprnd0));
385169689Skan  icode = (int) widen_pattern_optab->handlers[(int) tmode0].insn_code;
386169689Skan  gcc_assert (icode != CODE_FOR_nothing);
387169689Skan  xmode0 = insn_data[icode].operand[1].mode;
388169689Skan
389169689Skan  if (nops >= 2)
39090075Sobrien    {
391169689Skan      oprnd1 = TREE_OPERAND (exp, 1);
392169689Skan      tmode1 = TYPE_MODE (TREE_TYPE (oprnd1));
393169689Skan      xmode1 = insn_data[icode].operand[2].mode;
39490075Sobrien    }
395132718Skan
396169689Skan  /* The last operand is of a wider mode than the rest of the operands.  */
397169689Skan  if (nops == 2)
398169689Skan    {
399169689Skan      wmode = tmode1;
400169689Skan      wxmode = xmode1;
401169689Skan    }
402169689Skan  else if (nops == 3)
403169689Skan    {
404169689Skan      gcc_assert (tmode1 == tmode0);
405169689Skan      gcc_assert (op1);
406169689Skan      oprnd2 = TREE_OPERAND (exp, 2);
407169689Skan      wmode = TYPE_MODE (TREE_TYPE (oprnd2));
408169689Skan      wxmode = insn_data[icode].operand[3].mode;
409169689Skan    }
41052284Sobrien
411169689Skan  if (!wide_op)
412169689Skan    wmode = wxmode = insn_data[icode].operand[0].mode;
41352284Sobrien
414169689Skan  if (!target
415169689Skan      || ! (*insn_data[icode].operand[0].predicate) (target, wmode))
416169689Skan    temp = gen_reg_rtx (wmode);
417169689Skan  else
418169689Skan    temp = target;
41952284Sobrien
420169689Skan  xop0 = op0;
421169689Skan  xop1 = op1;
422169689Skan  wxop = wide_op;
423169689Skan
424169689Skan  /* In case the insn wants input operands in modes different from
425169689Skan     those of the actual operands, convert the operands.  It would
426169689Skan     seem that we don't need to convert CONST_INTs, but we do, so
427169689Skan     that they're properly zero-extended, sign-extended or truncated
428169689Skan     for their mode.  */
429169689Skan
430169689Skan  if (GET_MODE (op0) != xmode0 && xmode0 != VOIDmode)
431169689Skan    xop0 = convert_modes (xmode0,
432169689Skan                          GET_MODE (op0) != VOIDmode
433169689Skan                          ? GET_MODE (op0)
434169689Skan                          : tmode0,
435169689Skan                          xop0, unsignedp);
436169689Skan
437169689Skan  if (op1)
438169689Skan    if (GET_MODE (op1) != xmode1 && xmode1 != VOIDmode)
439169689Skan      xop1 = convert_modes (xmode1,
440169689Skan                            GET_MODE (op1) != VOIDmode
441169689Skan                            ? GET_MODE (op1)
442169689Skan                            : tmode1,
443169689Skan                            xop1, unsignedp);
444169689Skan
445169689Skan  if (wide_op)
446169689Skan    if (GET_MODE (wide_op) != wxmode && wxmode != VOIDmode)
447169689Skan      wxop = convert_modes (wxmode,
448169689Skan                            GET_MODE (wide_op) != VOIDmode
449169689Skan                            ? GET_MODE (wide_op)
450169689Skan                            : wmode,
451169689Skan                            wxop, unsignedp);
452169689Skan
453169689Skan  /* Now, if insn's predicates don't allow our operands, put them into
454169689Skan     pseudo regs.  */
455169689Skan
456169689Skan  if (! (*insn_data[icode].operand[1].predicate) (xop0, xmode0)
457169689Skan      && xmode0 != VOIDmode)
458169689Skan    xop0 = copy_to_mode_reg (xmode0, xop0);
459169689Skan
460169689Skan  if (op1)
46152284Sobrien    {
462169689Skan      if (! (*insn_data[icode].operand[2].predicate) (xop1, xmode1)
463169689Skan          && xmode1 != VOIDmode)
464169689Skan        xop1 = copy_to_mode_reg (xmode1, xop1);
465169689Skan
466169689Skan      if (wide_op)
467169689Skan        {
468169689Skan          if (! (*insn_data[icode].operand[3].predicate) (wxop, wxmode)
469169689Skan              && wxmode != VOIDmode)
470169689Skan            wxop = copy_to_mode_reg (wxmode, wxop);
471169689Skan
472169689Skan          pat = GEN_FCN (icode) (temp, xop0, xop1, wxop);
473169689Skan        }
474169689Skan      else
475169689Skan        pat = GEN_FCN (icode) (temp, xop0, xop1);
47652284Sobrien    }
47752284Sobrien  else
47852284Sobrien    {
479169689Skan      if (wide_op)
480169689Skan        {
481169689Skan          if (! (*insn_data[icode].operand[2].predicate) (wxop, wxmode)
482169689Skan              && wxmode != VOIDmode)
483169689Skan            wxop = copy_to_mode_reg (wxmode, wxop);
484169689Skan
485169689Skan          pat = GEN_FCN (icode) (temp, xop0, wxop);
486169689Skan        }
487169689Skan      else
488169689Skan        pat = GEN_FCN (icode) (temp, xop0);
48952284Sobrien    }
49052284Sobrien
491169689Skan  emit_insn (pat);
492169689Skan  return temp;
493169689Skan}
49452284Sobrien
495169689Skan/* Generate code to perform an operation specified by TERNARY_OPTAB
496169689Skan   on operands OP0, OP1 and OP2, with result having machine-mode MODE.
49752284Sobrien
498169689Skan   UNSIGNEDP is for the case where we have to widen the operands
499169689Skan   to perform the operation.  It says to use zero-extension.
50052284Sobrien
501169689Skan   If TARGET is nonzero, the value
502169689Skan   is generated there, if it is convenient to do so.
503169689Skan   In all cases an rtx is returned for the locus of the value;
504169689Skan   this may or may not be TARGET.  */
505169689Skan
506169689Skanrtx
507169689Skanexpand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
508169689Skan		   rtx op1, rtx op2, rtx target, int unsignedp)
509169689Skan{
510169689Skan  int icode = (int) ternary_optab->handlers[(int) mode].insn_code;
511169689Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
512169689Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
513169689Skan  enum machine_mode mode2 = insn_data[icode].operand[3].mode;
514169689Skan  rtx temp;
515169689Skan  rtx pat;
516169689Skan  rtx xop0 = op0, xop1 = op1, xop2 = op2;
517169689Skan
518169689Skan  gcc_assert (ternary_optab->handlers[(int) mode].insn_code
519169689Skan	      != CODE_FOR_nothing);
520169689Skan
521169689Skan  if (!target || !insn_data[icode].operand[0].predicate (target, mode))
522169689Skan    temp = gen_reg_rtx (mode);
52352284Sobrien  else
524169689Skan    temp = target;
52552284Sobrien
526169689Skan  /* In case the insn wants input operands in modes different from
527169689Skan     those of the actual operands, convert the operands.  It would
528169689Skan     seem that we don't need to convert CONST_INTs, but we do, so
529169689Skan     that they're properly zero-extended, sign-extended or truncated
530169689Skan     for their mode.  */
53152284Sobrien
532169689Skan  if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
533169689Skan    xop0 = convert_modes (mode0,
534169689Skan                          GET_MODE (op0) != VOIDmode
535169689Skan                          ? GET_MODE (op0)
536169689Skan                          : mode,
537169689Skan                          xop0, unsignedp);
53852284Sobrien
539169689Skan  if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
540169689Skan    xop1 = convert_modes (mode1,
541169689Skan                          GET_MODE (op1) != VOIDmode
542169689Skan                          ? GET_MODE (op1)
543169689Skan                          : mode,
544169689Skan                          xop1, unsignedp);
54552284Sobrien
546169689Skan  if (GET_MODE (op2) != mode2 && mode2 != VOIDmode)
547169689Skan    xop2 = convert_modes (mode2,
548169689Skan                          GET_MODE (op2) != VOIDmode
549169689Skan                          ? GET_MODE (op2)
550169689Skan                          : mode,
551169689Skan                          xop2, unsignedp);
55252284Sobrien
553169689Skan  /* Now, if insn's predicates don't allow our operands, put them into
554169689Skan     pseudo regs.  */
55552284Sobrien
556169689Skan  if (!insn_data[icode].operand[1].predicate (xop0, mode0)
557169689Skan      && mode0 != VOIDmode)
558169689Skan    xop0 = copy_to_mode_reg (mode0, xop0);
55952284Sobrien
560169689Skan  if (!insn_data[icode].operand[2].predicate (xop1, mode1)
561169689Skan      && mode1 != VOIDmode)
562169689Skan    xop1 = copy_to_mode_reg (mode1, xop1);
56352284Sobrien
564169689Skan  if (!insn_data[icode].operand[3].predicate (xop2, mode2)
565169689Skan      && mode2 != VOIDmode)
566169689Skan    xop2 = copy_to_mode_reg (mode2, xop2);
567169689Skan
568169689Skan  pat = GEN_FCN (icode) (temp, xop0, xop1, xop2);
569169689Skan
570169689Skan  emit_insn (pat);
571169689Skan  return temp;
572169689Skan}
573169689Skan
574169689Skan
575169689Skan/* Like expand_binop, but return a constant rtx if the result can be
576169689Skan   calculated at compile time.  The arguments and return value are
577169689Skan   otherwise the same as for expand_binop.  */
578169689Skan
579169689Skanstatic rtx
580169689Skansimplify_expand_binop (enum machine_mode mode, optab binoptab,
581169689Skan		       rtx op0, rtx op1, rtx target, int unsignedp,
582169689Skan		       enum optab_methods methods)
583169689Skan{
584169689Skan  if (CONSTANT_P (op0) && CONSTANT_P (op1))
58552284Sobrien    {
586169689Skan      rtx x = simplify_binary_operation (binoptab->code, mode, op0, op1);
58752284Sobrien
588169689Skan      if (x)
589169689Skan	return x;
590169689Skan    }
59152284Sobrien
592169689Skan  return expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods);
593169689Skan}
59452284Sobrien
595169689Skan/* Like simplify_expand_binop, but always put the result in TARGET.
596169689Skan   Return true if the expansion succeeded.  */
59752284Sobrien
598169689Skanbool
599169689Skanforce_expand_binop (enum machine_mode mode, optab binoptab,
600169689Skan		    rtx op0, rtx op1, rtx target, int unsignedp,
601169689Skan		    enum optab_methods methods)
602169689Skan{
603169689Skan  rtx x = simplify_expand_binop (mode, binoptab, op0, op1,
604169689Skan				 target, unsignedp, methods);
605169689Skan  if (x == 0)
606169689Skan    return false;
607169689Skan  if (x != target)
608169689Skan    emit_move_insn (target, x);
609169689Skan  return true;
610169689Skan}
61152284Sobrien
612169689Skan/* Generate insns for VEC_LSHIFT_EXPR, VEC_RSHIFT_EXPR.  */
613169689Skan
614169689Skanrtx
615169689Skanexpand_vec_shift_expr (tree vec_shift_expr, rtx target)
616169689Skan{
617169689Skan  enum insn_code icode;
618169689Skan  rtx rtx_op1, rtx_op2;
619169689Skan  enum machine_mode mode1;
620169689Skan  enum machine_mode mode2;
621169689Skan  enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_shift_expr));
622169689Skan  tree vec_oprnd = TREE_OPERAND (vec_shift_expr, 0);
623169689Skan  tree shift_oprnd = TREE_OPERAND (vec_shift_expr, 1);
624169689Skan  optab shift_optab;
625169689Skan  rtx pat;
626169689Skan
627169689Skan  switch (TREE_CODE (vec_shift_expr))
628169689Skan    {
629169689Skan      case VEC_RSHIFT_EXPR:
630169689Skan	shift_optab = vec_shr_optab;
631169689Skan	break;
632169689Skan      case VEC_LSHIFT_EXPR:
633169689Skan	shift_optab = vec_shl_optab;
634169689Skan	break;
635169689Skan      default:
636169689Skan	gcc_unreachable ();
63752284Sobrien    }
63852284Sobrien
639169689Skan  icode = (int) shift_optab->handlers[(int) mode].insn_code;
640169689Skan  gcc_assert (icode != CODE_FOR_nothing);
64152284Sobrien
642169689Skan  mode1 = insn_data[icode].operand[1].mode;
643169689Skan  mode2 = insn_data[icode].operand[2].mode;
64452284Sobrien
645169689Skan  rtx_op1 = expand_expr (vec_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL);
646169689Skan  if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode1)
647169689Skan      && mode1 != VOIDmode)
648169689Skan    rtx_op1 = force_reg (mode1, rtx_op1);
64952284Sobrien
650169689Skan  rtx_op2 = expand_expr (shift_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL);
651169689Skan  if (!(*insn_data[icode].operand[2].predicate) (rtx_op2, mode2)
652169689Skan      && mode2 != VOIDmode)
653169689Skan    rtx_op2 = force_reg (mode2, rtx_op2);
65452284Sobrien
655169689Skan  if (!target
656169689Skan      || ! (*insn_data[icode].operand[0].predicate) (target, mode))
657169689Skan    target = gen_reg_rtx (mode);
65852284Sobrien
659169689Skan  /* Emit instruction */
660169689Skan  pat = GEN_FCN (icode) (target, rtx_op1, rtx_op2);
661169689Skan  gcc_assert (pat);
662169689Skan  emit_insn (pat);
66352284Sobrien
664169689Skan  return target;
665169689Skan}
666169689Skan
667169689Skan/* This subroutine of expand_doubleword_shift handles the cases in which
668169689Skan   the effective shift value is >= BITS_PER_WORD.  The arguments and return
669169689Skan   value are the same as for the parent routine, except that SUPERWORD_OP1
670169689Skan   is the shift count to use when shifting OUTOF_INPUT into INTO_TARGET.
671169689Skan   INTO_TARGET may be null if the caller has decided to calculate it.  */
672169689Skan
673169689Skanstatic bool
674169689Skanexpand_superword_shift (optab binoptab, rtx outof_input, rtx superword_op1,
675169689Skan			rtx outof_target, rtx into_target,
676169689Skan			int unsignedp, enum optab_methods methods)
677169689Skan{
678169689Skan  if (into_target != 0)
679169689Skan    if (!force_expand_binop (word_mode, binoptab, outof_input, superword_op1,
680169689Skan			     into_target, unsignedp, methods))
681169689Skan      return false;
682169689Skan
683169689Skan  if (outof_target != 0)
684169689Skan    {
685169689Skan      /* For a signed right shift, we must fill OUTOF_TARGET with copies
686169689Skan	 of the sign bit, otherwise we must fill it with zeros.  */
687169689Skan      if (binoptab != ashr_optab)
688169689Skan	emit_move_insn (outof_target, CONST0_RTX (word_mode));
689169689Skan      else
690169689Skan	if (!force_expand_binop (word_mode, binoptab,
691169689Skan				 outof_input, GEN_INT (BITS_PER_WORD - 1),
692169689Skan				 outof_target, unsignedp, methods))
693169689Skan	  return false;
69452284Sobrien    }
695169689Skan  return true;
696169689Skan}
69752284Sobrien
698169689Skan/* This subroutine of expand_doubleword_shift handles the cases in which
699169689Skan   the effective shift value is < BITS_PER_WORD.  The arguments and return
700169689Skan   value are the same as for the parent routine.  */
70152284Sobrien
702169689Skanstatic bool
703169689Skanexpand_subword_shift (enum machine_mode op1_mode, optab binoptab,
704169689Skan		      rtx outof_input, rtx into_input, rtx op1,
705169689Skan		      rtx outof_target, rtx into_target,
706169689Skan		      int unsignedp, enum optab_methods methods,
707169689Skan		      unsigned HOST_WIDE_INT shift_mask)
708169689Skan{
709169689Skan  optab reverse_unsigned_shift, unsigned_shift;
710169689Skan  rtx tmp, carries;
71152284Sobrien
712169689Skan  reverse_unsigned_shift = (binoptab == ashl_optab ? lshr_optab : ashl_optab);
713169689Skan  unsigned_shift = (binoptab == ashl_optab ? ashl_optab : lshr_optab);
71452284Sobrien
715169689Skan  /* The low OP1 bits of INTO_TARGET come from the high bits of OUTOF_INPUT.
716169689Skan     We therefore need to shift OUTOF_INPUT by (BITS_PER_WORD - OP1) bits in
717169689Skan     the opposite direction to BINOPTAB.  */
718169689Skan  if (CONSTANT_P (op1) || shift_mask >= BITS_PER_WORD)
719169689Skan    {
720169689Skan      carries = outof_input;
721169689Skan      tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
722169689Skan      tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
723169689Skan				   0, true, methods);
724169689Skan    }
72552284Sobrien  else
726169689Skan    {
727169689Skan      /* We must avoid shifting by BITS_PER_WORD bits since that is either
728169689Skan	 the same as a zero shift (if shift_mask == BITS_PER_WORD - 1) or
729169689Skan	 has unknown behavior.  Do a single shift first, then shift by the
730169689Skan	 remainder.  It's OK to use ~OP1 as the remainder if shift counts
731169689Skan	 are truncated to the mode size.  */
732169689Skan      carries = expand_binop (word_mode, reverse_unsigned_shift,
733169689Skan			      outof_input, const1_rtx, 0, unsignedp, methods);
734169689Skan      if (shift_mask == BITS_PER_WORD - 1)
735169689Skan	{
736169689Skan	  tmp = immed_double_const (-1, -1, op1_mode);
737169689Skan	  tmp = simplify_expand_binop (op1_mode, xor_optab, op1, tmp,
738169689Skan				       0, true, methods);
739169689Skan	}
740169689Skan      else
741169689Skan	{
742169689Skan	  tmp = immed_double_const (BITS_PER_WORD - 1, 0, op1_mode);
743169689Skan	  tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
744169689Skan				       0, true, methods);
745169689Skan	}
746169689Skan    }
747169689Skan  if (tmp == 0 || carries == 0)
748169689Skan    return false;
749169689Skan  carries = expand_binop (word_mode, reverse_unsigned_shift,
750169689Skan			  carries, tmp, 0, unsignedp, methods);
751169689Skan  if (carries == 0)
752169689Skan    return false;
75352284Sobrien
754169689Skan  /* Shift INTO_INPUT logically by OP1.  This is the last use of INTO_INPUT
755169689Skan     so the result can go directly into INTO_TARGET if convenient.  */
756169689Skan  tmp = expand_binop (word_mode, unsigned_shift, into_input, op1,
757169689Skan		      into_target, unsignedp, methods);
758169689Skan  if (tmp == 0)
759169689Skan    return false;
76052284Sobrien
761169689Skan  /* Now OR in the bits carried over from OUTOF_INPUT.  */
762169689Skan  if (!force_expand_binop (word_mode, ior_optab, tmp, carries,
763169689Skan			   into_target, unsignedp, methods))
764169689Skan    return false;
76552284Sobrien
766169689Skan  /* Use a standard word_mode shift for the out-of half.  */
767169689Skan  if (outof_target != 0)
768169689Skan    if (!force_expand_binop (word_mode, binoptab, outof_input, op1,
769169689Skan			     outof_target, unsignedp, methods))
770169689Skan      return false;
77152284Sobrien
772169689Skan  return true;
773169689Skan}
77452284Sobrien
77552284Sobrien
776169689Skan#ifdef HAVE_conditional_move
777169689Skan/* Try implementing expand_doubleword_shift using conditional moves.
778169689Skan   The shift is by < BITS_PER_WORD if (CMP_CODE CMP1 CMP2) is true,
779169689Skan   otherwise it is by >= BITS_PER_WORD.  SUBWORD_OP1 and SUPERWORD_OP1
780169689Skan   are the shift counts to use in the former and latter case.  All other
781169689Skan   arguments are the same as the parent routine.  */
782169689Skan
783169689Skanstatic bool
784169689Skanexpand_doubleword_shift_condmove (enum machine_mode op1_mode, optab binoptab,
785169689Skan				  enum rtx_code cmp_code, rtx cmp1, rtx cmp2,
786169689Skan				  rtx outof_input, rtx into_input,
787169689Skan				  rtx subword_op1, rtx superword_op1,
788169689Skan				  rtx outof_target, rtx into_target,
789169689Skan				  int unsignedp, enum optab_methods methods,
790169689Skan				  unsigned HOST_WIDE_INT shift_mask)
791169689Skan{
792169689Skan  rtx outof_superword, into_superword;
793169689Skan
794169689Skan  /* Put the superword version of the output into OUTOF_SUPERWORD and
795169689Skan     INTO_SUPERWORD.  */
796169689Skan  outof_superword = outof_target != 0 ? gen_reg_rtx (word_mode) : 0;
797169689Skan  if (outof_target != 0 && subword_op1 == superword_op1)
798169689Skan    {
799169689Skan      /* The value INTO_TARGET >> SUBWORD_OP1, which we later store in
800169689Skan	 OUTOF_TARGET, is the same as the value of INTO_SUPERWORD.  */
801169689Skan      into_superword = outof_target;
802169689Skan      if (!expand_superword_shift (binoptab, outof_input, superword_op1,
803169689Skan				   outof_superword, 0, unsignedp, methods))
804169689Skan	return false;
805169689Skan    }
80652284Sobrien  else
807169689Skan    {
808169689Skan      into_superword = gen_reg_rtx (word_mode);
809169689Skan      if (!expand_superword_shift (binoptab, outof_input, superword_op1,
810169689Skan				   outof_superword, into_superword,
811169689Skan				   unsignedp, methods))
812169689Skan	return false;
813169689Skan    }
81452284Sobrien
815169689Skan  /* Put the subword version directly in OUTOF_TARGET and INTO_TARGET.  */
816169689Skan  if (!expand_subword_shift (op1_mode, binoptab,
817169689Skan			     outof_input, into_input, subword_op1,
818169689Skan			     outof_target, into_target,
819169689Skan			     unsignedp, methods, shift_mask))
820169689Skan    return false;
82152284Sobrien
822169689Skan  /* Select between them.  Do the INTO half first because INTO_SUPERWORD
823169689Skan     might be the current value of OUTOF_TARGET.  */
824169689Skan  if (!emit_conditional_move (into_target, cmp_code, cmp1, cmp2, op1_mode,
825169689Skan			      into_target, into_superword, word_mode, false))
826169689Skan    return false;
82752284Sobrien
828169689Skan  if (outof_target != 0)
829169689Skan    if (!emit_conditional_move (outof_target, cmp_code, cmp1, cmp2, op1_mode,
830169689Skan				outof_target, outof_superword,
831169689Skan				word_mode, false))
832169689Skan      return false;
83352284Sobrien
834169689Skan  return true;
835169689Skan}
836169689Skan#endif
83752284Sobrien
838169689Skan/* Expand a doubleword shift (ashl, ashr or lshr) using word-mode shifts.
839169689Skan   OUTOF_INPUT and INTO_INPUT are the two word-sized halves of the first
840169689Skan   input operand; the shift moves bits in the direction OUTOF_INPUT->
841169689Skan   INTO_TARGET.  OUTOF_TARGET and INTO_TARGET are the equivalent words
842169689Skan   of the target.  OP1 is the shift count and OP1_MODE is its mode.
843169689Skan   If OP1 is constant, it will have been truncated as appropriate
844169689Skan   and is known to be nonzero.
84552284Sobrien
846169689Skan   If SHIFT_MASK is zero, the result of word shifts is undefined when the
847169689Skan   shift count is outside the range [0, BITS_PER_WORD).  This routine must
848169689Skan   avoid generating such shifts for OP1s in the range [0, BITS_PER_WORD * 2).
84952284Sobrien
850169689Skan   If SHIFT_MASK is nonzero, all word-mode shift counts are effectively
851169689Skan   masked by it and shifts in the range [BITS_PER_WORD, SHIFT_MASK) will
852169689Skan   fill with zeros or sign bits as appropriate.
85352284Sobrien
854169689Skan   If SHIFT_MASK is BITS_PER_WORD - 1, this routine will synthesize
855169689Skan   a doubleword shift whose equivalent mask is BITS_PER_WORD * 2 - 1.
856169689Skan   Doing this preserves semantics required by SHIFT_COUNT_TRUNCATED.
857169689Skan   In all other cases, shifts by values outside [0, BITS_PER_UNIT * 2)
858169689Skan   are undefined.
85952284Sobrien
860169689Skan   BINOPTAB, UNSIGNEDP and METHODS are as for expand_binop.  This function
861169689Skan   may not use INTO_INPUT after modifying INTO_TARGET, and similarly for
862169689Skan   OUTOF_INPUT and OUTOF_TARGET.  OUTOF_TARGET can be null if the parent
863169689Skan   function wants to calculate it itself.
86452284Sobrien
865169689Skan   Return true if the shift could be successfully synthesized.  */
86652284Sobrien
867169689Skanstatic bool
868169689Skanexpand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
869169689Skan			 rtx outof_input, rtx into_input, rtx op1,
870169689Skan			 rtx outof_target, rtx into_target,
871169689Skan			 int unsignedp, enum optab_methods methods,
872169689Skan			 unsigned HOST_WIDE_INT shift_mask)
873169689Skan{
874169689Skan  rtx superword_op1, tmp, cmp1, cmp2;
875169689Skan  rtx subword_label, done_label;
876169689Skan  enum rtx_code cmp_code;
877169689Skan
878169689Skan  /* See if word-mode shifts by BITS_PER_WORD...BITS_PER_WORD * 2 - 1 will
879169689Skan     fill the result with sign or zero bits as appropriate.  If so, the value
880169689Skan     of OUTOF_TARGET will always be (SHIFT OUTOF_INPUT OP1).   Recursively call
881169689Skan     this routine to calculate INTO_TARGET (which depends on both OUTOF_INPUT
882169689Skan     and INTO_INPUT), then emit code to set up OUTOF_TARGET.
883169689Skan
884169689Skan     This isn't worthwhile for constant shifts since the optimizers will
885169689Skan     cope better with in-range shift counts.  */
886169689Skan  if (shift_mask >= BITS_PER_WORD
887169689Skan      && outof_target != 0
888169689Skan      && !CONSTANT_P (op1))
889169689Skan    {
890169689Skan      if (!expand_doubleword_shift (op1_mode, binoptab,
891169689Skan				    outof_input, into_input, op1,
892169689Skan				    0, into_target,
893169689Skan				    unsignedp, methods, shift_mask))
894169689Skan	return false;
895169689Skan      if (!force_expand_binop (word_mode, binoptab, outof_input, op1,
896169689Skan			       outof_target, unsignedp, methods))
897169689Skan	return false;
898169689Skan      return true;
89952284Sobrien    }
900169689Skan
901169689Skan  /* Set CMP_CODE, CMP1 and CMP2 so that the rtx (CMP_CODE CMP1 CMP2)
902169689Skan     is true when the effective shift value is less than BITS_PER_WORD.
903169689Skan     Set SUPERWORD_OP1 to the shift count that should be used to shift
904169689Skan     OUTOF_INPUT into INTO_TARGET when the condition is false.  */
905169689Skan  tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
906169689Skan  if (!CONSTANT_P (op1) && shift_mask == BITS_PER_WORD - 1)
907169689Skan    {
908169689Skan      /* Set CMP1 to OP1 & BITS_PER_WORD.  The result is zero iff OP1
909169689Skan	 is a subword shift count.  */
910169689Skan      cmp1 = simplify_expand_binop (op1_mode, and_optab, op1, tmp,
911169689Skan				    0, true, methods);
912169689Skan      cmp2 = CONST0_RTX (op1_mode);
913169689Skan      cmp_code = EQ;
914169689Skan      superword_op1 = op1;
915169689Skan    }
91652284Sobrien  else
91752284Sobrien    {
918169689Skan      /* Set CMP1 to OP1 - BITS_PER_WORD.  */
919169689Skan      cmp1 = simplify_expand_binop (op1_mode, sub_optab, op1, tmp,
920169689Skan				    0, true, methods);
921169689Skan      cmp2 = CONST0_RTX (op1_mode);
922169689Skan      cmp_code = LT;
923169689Skan      superword_op1 = cmp1;
924169689Skan    }
925169689Skan  if (cmp1 == 0)
926169689Skan    return false;
92752284Sobrien
928169689Skan  /* If we can compute the condition at compile time, pick the
929169689Skan     appropriate subroutine.  */
930169689Skan  tmp = simplify_relational_operation (cmp_code, SImode, op1_mode, cmp1, cmp2);
931169689Skan  if (tmp != 0 && GET_CODE (tmp) == CONST_INT)
932169689Skan    {
933169689Skan      if (tmp == const0_rtx)
934169689Skan	return expand_superword_shift (binoptab, outof_input, superword_op1,
935169689Skan				       outof_target, into_target,
936169689Skan				       unsignedp, methods);
937169689Skan      else
938169689Skan	return expand_subword_shift (op1_mode, binoptab,
939169689Skan				     outof_input, into_input, op1,
940169689Skan				     outof_target, into_target,
941169689Skan				     unsignedp, methods, shift_mask);
942169689Skan    }
94352284Sobrien
944169689Skan#ifdef HAVE_conditional_move
945169689Skan  /* Try using conditional moves to generate straight-line code.  */
946169689Skan  {
947169689Skan    rtx start = get_last_insn ();
948169689Skan    if (expand_doubleword_shift_condmove (op1_mode, binoptab,
949169689Skan					  cmp_code, cmp1, cmp2,
950169689Skan					  outof_input, into_input,
951169689Skan					  op1, superword_op1,
952169689Skan					  outof_target, into_target,
953169689Skan					  unsignedp, methods, shift_mask))
954169689Skan      return true;
955169689Skan    delete_insns_since (start);
956169689Skan  }
957169689Skan#endif
95852284Sobrien
959169689Skan  /* As a last resort, use branches to select the correct alternative.  */
960169689Skan  subword_label = gen_label_rtx ();
961169689Skan  done_label = gen_label_rtx ();
96252284Sobrien
963169689Skan  NO_DEFER_POP;
964169689Skan  do_compare_rtx_and_jump (cmp1, cmp2, cmp_code, false, op1_mode,
965169689Skan			   0, 0, subword_label);
966169689Skan  OK_DEFER_POP;
96752284Sobrien
968169689Skan  if (!expand_superword_shift (binoptab, outof_input, superword_op1,
969169689Skan			       outof_target, into_target,
970169689Skan			       unsignedp, methods))
971169689Skan    return false;
97252284Sobrien
973169689Skan  emit_jump_insn (gen_jump (done_label));
974169689Skan  emit_barrier ();
975169689Skan  emit_label (subword_label);
97652284Sobrien
977169689Skan  if (!expand_subword_shift (op1_mode, binoptab,
978169689Skan			     outof_input, into_input, op1,
979169689Skan			     outof_target, into_target,
980169689Skan			     unsignedp, methods, shift_mask))
981169689Skan    return false;
982169689Skan
983169689Skan  emit_label (done_label);
984169689Skan  return true;
985169689Skan}
986169689Skan
987169689Skan/* Subroutine of expand_binop.  Perform a double word multiplication of
988169689Skan   operands OP0 and OP1 both of mode MODE, which is exactly twice as wide
989169689Skan   as the target's word_mode.  This function return NULL_RTX if anything
990169689Skan   goes wrong, in which case it may have already emitted instructions
991169689Skan   which need to be deleted.
992169689Skan
993169689Skan   If we want to multiply two two-word values and have normal and widening
994169689Skan   multiplies of single-word values, we can do this with three smaller
995169689Skan   multiplications.  Note that we do not make a REG_NO_CONFLICT block here
996169689Skan   because we are not operating on one word at a time.
997169689Skan
998169689Skan   The multiplication proceeds as follows:
999169689Skan			         _______________________
1000169689Skan			        [__op0_high_|__op0_low__]
1001169689Skan			         _______________________
1002169689Skan        *			[__op1_high_|__op1_low__]
1003169689Skan        _______________________________________________
1004169689Skan			         _______________________
1005169689Skan    (1)				[__op0_low__*__op1_low__]
1006169689Skan		     _______________________
1007169689Skan    (2a)	    [__op0_low__*__op1_high_]
1008169689Skan		     _______________________
1009169689Skan    (2b)	    [__op0_high_*__op1_low__]
1010169689Skan         _______________________
1011169689Skan    (3) [__op0_high_*__op1_high_]
1012169689Skan
1013169689Skan
1014169689Skan  This gives a 4-word result.  Since we are only interested in the
1015169689Skan  lower 2 words, partial result (3) and the upper words of (2a) and
1016169689Skan  (2b) don't need to be calculated.  Hence (2a) and (2b) can be
1017169689Skan  calculated using non-widening multiplication.
1018169689Skan
1019169689Skan  (1), however, needs to be calculated with an unsigned widening
1020169689Skan  multiplication.  If this operation is not directly supported we
1021169689Skan  try using a signed widening multiplication and adjust the result.
1022169689Skan  This adjustment works as follows:
1023169689Skan
1024169689Skan      If both operands are positive then no adjustment is needed.
1025169689Skan
1026169689Skan      If the operands have different signs, for example op0_low < 0 and
1027169689Skan      op1_low >= 0, the instruction treats the most significant bit of
1028169689Skan      op0_low as a sign bit instead of a bit with significance
1029169689Skan      2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low
1030169689Skan      with 2**BITS_PER_WORD - op0_low, and two's complements the
1031169689Skan      result.  Conclusion: We need to add op1_low * 2**BITS_PER_WORD to
1032169689Skan      the result.
1033169689Skan
1034169689Skan      Similarly, if both operands are negative, we need to add
1035169689Skan      (op0_low + op1_low) * 2**BITS_PER_WORD.
1036169689Skan
1037169689Skan      We use a trick to adjust quickly.  We logically shift op0_low right
1038169689Skan      (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to
1039169689Skan      op0_high (op1_high) before it is used to calculate 2b (2a).  If no
1040169689Skan      logical shift exists, we do an arithmetic right shift and subtract
1041169689Skan      the 0 or -1.  */
1042169689Skan
1043169689Skanstatic rtx
1044169689Skanexpand_doubleword_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
1045169689Skan		       bool umulp, enum optab_methods methods)
1046169689Skan{
1047169689Skan  int low = (WORDS_BIG_ENDIAN ? 1 : 0);
1048169689Skan  int high = (WORDS_BIG_ENDIAN ? 0 : 1);
1049169689Skan  rtx wordm1 = umulp ? NULL_RTX : GEN_INT (BITS_PER_WORD - 1);
1050169689Skan  rtx product, adjust, product_high, temp;
1051169689Skan
1052169689Skan  rtx op0_high = operand_subword_force (op0, high, mode);
1053169689Skan  rtx op0_low = operand_subword_force (op0, low, mode);
1054169689Skan  rtx op1_high = operand_subword_force (op1, high, mode);
1055169689Skan  rtx op1_low = operand_subword_force (op1, low, mode);
1056169689Skan
1057169689Skan  /* If we're using an unsigned multiply to directly compute the product
1058169689Skan     of the low-order words of the operands and perform any required
1059169689Skan     adjustments of the operands, we begin by trying two more multiplications
1060169689Skan     and then computing the appropriate sum.
1061169689Skan
1062169689Skan     We have checked above that the required addition is provided.
1063169689Skan     Full-word addition will normally always succeed, especially if
1064169689Skan     it is provided at all, so we don't worry about its failure.  The
1065169689Skan     multiplication may well fail, however, so we do handle that.  */
1066169689Skan
1067169689Skan  if (!umulp)
1068169689Skan    {
1069169689Skan      /* ??? This could be done with emit_store_flag where available.  */
1070169689Skan      temp = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
1071169689Skan			   NULL_RTX, 1, methods);
1072169689Skan      if (temp)
1073169689Skan	op0_high = expand_binop (word_mode, add_optab, op0_high, temp,
1074169689Skan				 NULL_RTX, 0, OPTAB_DIRECT);
1075169689Skan      else
1076169689Skan	{
1077169689Skan	  temp = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
1078169689Skan			       NULL_RTX, 0, methods);
1079169689Skan	  if (!temp)
1080169689Skan	    return NULL_RTX;
1081169689Skan	  op0_high = expand_binop (word_mode, sub_optab, op0_high, temp,
1082169689Skan				   NULL_RTX, 0, OPTAB_DIRECT);
1083169689Skan	}
1084169689Skan
1085169689Skan      if (!op0_high)
1086169689Skan	return NULL_RTX;
108752284Sobrien    }
108852284Sobrien
1089169689Skan  adjust = expand_binop (word_mode, smul_optab, op0_high, op1_low,
1090169689Skan			 NULL_RTX, 0, OPTAB_DIRECT);
1091169689Skan  if (!adjust)
1092169689Skan    return NULL_RTX;
109352284Sobrien
1094169689Skan  /* OP0_HIGH should now be dead.  */
109552284Sobrien
1096169689Skan  if (!umulp)
1097169689Skan    {
1098169689Skan      /* ??? This could be done with emit_store_flag where available.  */
1099169689Skan      temp = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
1100169689Skan			   NULL_RTX, 1, methods);
1101169689Skan      if (temp)
1102169689Skan	op1_high = expand_binop (word_mode, add_optab, op1_high, temp,
1103169689Skan				 NULL_RTX, 0, OPTAB_DIRECT);
1104169689Skan      else
1105169689Skan	{
1106169689Skan	  temp = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
1107169689Skan			       NULL_RTX, 0, methods);
1108169689Skan	  if (!temp)
1109169689Skan	    return NULL_RTX;
1110169689Skan	  op1_high = expand_binop (word_mode, sub_optab, op1_high, temp,
1111169689Skan				   NULL_RTX, 0, OPTAB_DIRECT);
1112169689Skan	}
111352284Sobrien
1114169689Skan      if (!op1_high)
1115169689Skan	return NULL_RTX;
1116169689Skan    }
111752284Sobrien
1118169689Skan  temp = expand_binop (word_mode, smul_optab, op1_high, op0_low,
1119169689Skan		       NULL_RTX, 0, OPTAB_DIRECT);
1120169689Skan  if (!temp)
1121169689Skan    return NULL_RTX;
112252284Sobrien
1123169689Skan  /* OP1_HIGH should now be dead.  */
112452284Sobrien
1125169689Skan  adjust = expand_binop (word_mode, add_optab, adjust, temp,
1126169689Skan			 adjust, 0, OPTAB_DIRECT);
112752284Sobrien
1128169689Skan  if (target && !REG_P (target))
1129169689Skan    target = NULL_RTX;
1130169689Skan
1131169689Skan  if (umulp)
1132169689Skan    product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,
1133169689Skan			    target, 1, OPTAB_DIRECT);
1134169689Skan  else
1135169689Skan    product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
1136169689Skan			    target, 1, OPTAB_DIRECT);
1137169689Skan
1138169689Skan  if (!product)
1139169689Skan    return NULL_RTX;
1140169689Skan
1141169689Skan  product_high = operand_subword (product, high, 1, mode);
1142169689Skan  adjust = expand_binop (word_mode, add_optab, product_high, adjust,
1143169689Skan			 REG_P (product_high) ? product_high : adjust,
1144169689Skan			 0, OPTAB_DIRECT);
1145169689Skan  emit_move_insn (product_high, adjust);
1146169689Skan  return product;
114752284Sobrien}
114852284Sobrien
114990075Sobrien/* Wrapper around expand_binop which takes an rtx code to specify
115090075Sobrien   the operation to perform, not an optab pointer.  All other
115190075Sobrien   arguments are the same.  */
115290075Sobrienrtx
1153132718Skanexpand_simple_binop (enum machine_mode mode, enum rtx_code code, rtx op0,
1154132718Skan		     rtx op1, rtx target, int unsignedp,
1155132718Skan		     enum optab_methods methods)
115690075Sobrien{
1157117395Skan  optab binop = code_to_optab[(int) code];
1158169689Skan  gcc_assert (binop);
115990075Sobrien
116090075Sobrien  return expand_binop (mode, binop, op0, op1, target, unsignedp, methods);
116190075Sobrien}
116290075Sobrien
1163169689Skan/* Return whether OP0 and OP1 should be swapped when expanding a commutative
1164169689Skan   binop.  Order them according to commutative_operand_precedence and, if
1165169689Skan   possible, try to put TARGET or a pseudo first.  */
1166169689Skanstatic bool
1167169689Skanswap_commutative_operands_with_target (rtx target, rtx op0, rtx op1)
1168169689Skan{
1169169689Skan  int op0_prec = commutative_operand_precedence (op0);
1170169689Skan  int op1_prec = commutative_operand_precedence (op1);
1171169689Skan
1172169689Skan  if (op0_prec < op1_prec)
1173169689Skan    return true;
1174169689Skan
1175169689Skan  if (op0_prec > op1_prec)
1176169689Skan    return false;
1177169689Skan
1178169689Skan  /* With equal precedence, both orders are ok, but it is better if the
1179169689Skan     first operand is TARGET, or if both TARGET and OP0 are pseudos.  */
1180169689Skan  if (target == 0 || REG_P (target))
1181169689Skan    return (REG_P (op1) && !REG_P (op0)) || target == op1;
1182169689Skan  else
1183169689Skan    return rtx_equal_p (op1, target);
1184169689Skan}
1185169689Skan
1186169689Skan
118718334Speter/* Generate code to perform an operation specified by BINOPTAB
118818334Speter   on operands OP0 and OP1, with result having machine-mode MODE.
118918334Speter
119018334Speter   UNSIGNEDP is for the case where we have to widen the operands
119118334Speter   to perform the operation.  It says to use zero-extension.
119218334Speter
119318334Speter   If TARGET is nonzero, the value
119418334Speter   is generated there, if it is convenient to do so.
119518334Speter   In all cases an rtx is returned for the locus of the value;
119618334Speter   this may or may not be TARGET.  */
119718334Speter
119818334Speterrtx
1199132718Skanexpand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
1200132718Skan	      rtx target, int unsignedp, enum optab_methods methods)
120118334Speter{
120218334Speter  enum optab_methods next_methods
120318334Speter    = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
120418334Speter       ? OPTAB_WIDEN : methods);
120518334Speter  enum mode_class class;
120618334Speter  enum machine_mode wider_mode;
120790075Sobrien  rtx temp;
120818334Speter  int commutative_op = 0;
1209117395Skan  int shift_op = (binoptab->code == ASHIFT
121018334Speter		  || binoptab->code == ASHIFTRT
121118334Speter		  || binoptab->code == LSHIFTRT
121218334Speter		  || binoptab->code == ROTATE
121318334Speter		  || binoptab->code == ROTATERT);
121418334Speter  rtx entry_last = get_last_insn ();
121518334Speter  rtx last;
1216169689Skan  bool first_pass_p = true;
121718334Speter
121818334Speter  class = GET_MODE_CLASS (mode);
121918334Speter
122018334Speter  /* If subtracting an integer constant, convert this into an addition of
122118334Speter     the negated constant.  */
122218334Speter
122318334Speter  if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT)
122418334Speter    {
122518334Speter      op1 = negate_rtx (mode, op1);
122618334Speter      binoptab = add_optab;
122718334Speter    }
122818334Speter
1229169689Skan  /* If we are inside an appropriately-short loop and we are optimizing,
1230169689Skan     force expensive constants into a register.  */
1231169689Skan  if (CONSTANT_P (op0) && optimize
123290075Sobrien      && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
1233169689Skan    {
1234169689Skan      if (GET_MODE (op0) != VOIDmode)
1235169689Skan	op0 = convert_modes (mode, VOIDmode, op0, unsignedp);
1236169689Skan      op0 = force_reg (mode, op0);
1237169689Skan    }
123818334Speter
1239169689Skan  if (CONSTANT_P (op1) && optimize
124090075Sobrien      && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
1241169689Skan    {
1242169689Skan      if (GET_MODE (op1) != VOIDmode)
1243169689Skan	op1 = convert_modes (mode, VOIDmode, op1, unsignedp);
1244169689Skan      op1 = force_reg (mode, op1);
1245169689Skan    }
124618334Speter
124718334Speter  /* Record where to delete back to if we backtrack.  */
124818334Speter  last = get_last_insn ();
124918334Speter
125018334Speter  /* If operation is commutative,
125118334Speter     try to make the first operand a register.
125218334Speter     Even better, try to make it the same as the target.
125318334Speter     Also try to make the last operand a constant.  */
1254169689Skan  if (GET_RTX_CLASS (binoptab->code) == RTX_COMM_ARITH
125518334Speter      || binoptab == smul_widen_optab
125618334Speter      || binoptab == umul_widen_optab
125718334Speter      || binoptab == smul_highpart_optab
125818334Speter      || binoptab == umul_highpart_optab)
125918334Speter    {
126018334Speter      commutative_op = 1;
126118334Speter
1262169689Skan      if (swap_commutative_operands_with_target (target, op0, op1))
126318334Speter	{
126418334Speter	  temp = op1;
126518334Speter	  op1 = op0;
126618334Speter	  op0 = temp;
126718334Speter	}
126818334Speter    }
126918334Speter
1270169689Skan retry:
1271169689Skan
127218334Speter  /* If we can do it with a three-operand insn, do so.  */
127318334Speter
127418334Speter  if (methods != OPTAB_MUST_WIDEN
127518334Speter      && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
127618334Speter    {
127718334Speter      int icode = (int) binoptab->handlers[(int) mode].insn_code;
127890075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
127990075Sobrien      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
128018334Speter      rtx pat;
128118334Speter      rtx xop0 = op0, xop1 = op1;
128218334Speter
128318334Speter      if (target)
128418334Speter	temp = target;
128518334Speter      else
128618334Speter	temp = gen_reg_rtx (mode);
128718334Speter
128818334Speter      /* If it is a commutative operator and the modes would match
128950397Sobrien	 if we would swap the operands, we can save the conversions.  */
129018334Speter      if (commutative_op)
129118334Speter	{
129218334Speter	  if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
129318334Speter	      && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
129418334Speter	    {
129590075Sobrien	      rtx tmp;
129618334Speter
129718334Speter	      tmp = op0; op0 = op1; op1 = tmp;
129818334Speter	      tmp = xop0; xop0 = xop1; xop1 = tmp;
129918334Speter	    }
130018334Speter	}
130118334Speter
130218334Speter      /* In case the insn wants input operands in modes different from
1303103445Skan	 those of the actual operands, convert the operands.  It would
1304103445Skan	 seem that we don't need to convert CONST_INTs, but we do, so
1305110611Skan	 that they're properly zero-extended, sign-extended or truncated
1306110611Skan	 for their mode.  */
130718334Speter
1308117395Skan      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
130990075Sobrien	xop0 = convert_modes (mode0,
131090075Sobrien			      GET_MODE (op0) != VOIDmode
131190075Sobrien			      ? GET_MODE (op0)
1312103445Skan			      : mode,
131390075Sobrien			      xop0, unsignedp);
131418334Speter
1315117395Skan      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
131690075Sobrien	xop1 = convert_modes (mode1,
131790075Sobrien			      GET_MODE (op1) != VOIDmode
131890075Sobrien			      ? GET_MODE (op1)
1319110611Skan			      : mode,
132090075Sobrien			      xop1, unsignedp);
132118334Speter
132218334Speter      /* Now, if insn's predicates don't allow our operands, put them into
132318334Speter	 pseudo regs.  */
132418334Speter
1325169689Skan      if (!insn_data[icode].operand[1].predicate (xop0, mode0)
132618334Speter	  && mode0 != VOIDmode)
132718334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
132818334Speter
1329169689Skan      if (!insn_data[icode].operand[2].predicate (xop1, mode1)
133018334Speter	  && mode1 != VOIDmode)
133118334Speter	xop1 = copy_to_mode_reg (mode1, xop1);
133218334Speter
1333169689Skan      if (!insn_data[icode].operand[0].predicate (temp, mode))
133418334Speter	temp = gen_reg_rtx (mode);
133518334Speter
133618334Speter      pat = GEN_FCN (icode) (temp, xop0, xop1);
133718334Speter      if (pat)
133818334Speter	{
1339117395Skan	  /* If PAT is composed of more than one insn, try to add an appropriate
134018334Speter	     REG_EQUAL note to it.  If we can't because TEMP conflicts with an
134118334Speter	     operand, call ourselves again, this time without a target.  */
1342117395Skan	  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
134318334Speter	      && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
134418334Speter	    {
134518334Speter	      delete_insns_since (last);
134618334Speter	      return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
134718334Speter				   unsignedp, methods);
134818334Speter	    }
134918334Speter
135018334Speter	  emit_insn (pat);
135118334Speter	  return temp;
135218334Speter	}
135318334Speter      else
135418334Speter	delete_insns_since (last);
135518334Speter    }
135618334Speter
1357169689Skan  /* If we were trying to rotate by a constant value, and that didn't
1358169689Skan     work, try rotating the other direction before falling back to
1359169689Skan     shifts and bitwise-or.  */
1360169689Skan  if (first_pass_p
1361169689Skan      && (binoptab == rotl_optab || binoptab == rotr_optab)
1362169689Skan      && class == MODE_INT
1363169689Skan      && GET_CODE (op1) == CONST_INT
1364169689Skan      && INTVAL (op1) > 0
1365169689Skan      && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
1366169689Skan    {
1367169689Skan      first_pass_p = false;
1368169689Skan      op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1));
1369169689Skan      binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab;
1370169689Skan      goto retry;
1371169689Skan    }
1372169689Skan
137318334Speter  /* If this is a multiply, see if we can do a widening operation that
137418334Speter     takes operands of this mode and makes a wider mode.  */
137518334Speter
1376169689Skan  if (binoptab == smul_optab
1377169689Skan      && GET_MODE_WIDER_MODE (mode) != VOIDmode
137818334Speter      && (((unsignedp ? umul_widen_optab : smul_widen_optab)
137918334Speter	   ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code)
138018334Speter	  != CODE_FOR_nothing))
138118334Speter    {
138218334Speter      temp = expand_binop (GET_MODE_WIDER_MODE (mode),
138318334Speter			   unsignedp ? umul_widen_optab : smul_widen_optab,
138418334Speter			   op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);
138518334Speter
138618334Speter      if (temp != 0)
138718334Speter	{
1388169689Skan	  if (GET_MODE_CLASS (mode) == MODE_INT
1389169689Skan	      && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
1390169689Skan                                        GET_MODE_BITSIZE (GET_MODE (temp))))
139118334Speter	    return gen_lowpart (mode, temp);
139218334Speter	  else
139318334Speter	    return convert_to_mode (mode, temp, unsignedp);
139418334Speter	}
139518334Speter    }
139618334Speter
139718334Speter  /* Look for a wider mode of the same class for which we think we
139818334Speter     can open-code the operation.  Check for a widening multiply at the
139918334Speter     wider mode as well.  */
140018334Speter
1401169689Skan  if (CLASS_HAS_WIDER_MODES_P (class)
140218334Speter      && methods != OPTAB_DIRECT && methods != OPTAB_LIB)
1403169689Skan    for (wider_mode = GET_MODE_WIDER_MODE (mode);
1404169689Skan	 wider_mode != VOIDmode;
140518334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
140618334Speter      {
140718334Speter	if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
140818334Speter	    || (binoptab == smul_optab
140918334Speter		&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
141018334Speter		&& (((unsignedp ? umul_widen_optab : smul_widen_optab)
141118334Speter		     ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code)
141218334Speter		    != CODE_FOR_nothing)))
141318334Speter	  {
141418334Speter	    rtx xop0 = op0, xop1 = op1;
141518334Speter	    int no_extend = 0;
141618334Speter
141718334Speter	    /* For certain integer operations, we need not actually extend
141818334Speter	       the narrow operands, as long as we will truncate
141990075Sobrien	       the results to the same narrowness.  */
142018334Speter
142118334Speter	    if ((binoptab == ior_optab || binoptab == and_optab
142218334Speter		 || binoptab == xor_optab
142318334Speter		 || binoptab == add_optab || binoptab == sub_optab
142418334Speter		 || binoptab == smul_optab || binoptab == ashl_optab)
142518334Speter		&& class == MODE_INT)
142618334Speter	      no_extend = 1;
142718334Speter
142818334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend);
142918334Speter
143018334Speter	    /* The second operand of a shift must always be extended.  */
143118334Speter	    xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
143218334Speter				  no_extend && binoptab != ashl_optab);
143318334Speter
143418334Speter	    temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
143518334Speter				 unsignedp, OPTAB_DIRECT);
143618334Speter	    if (temp)
143718334Speter	      {
1438169689Skan		if (class != MODE_INT
1439169689Skan                    || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
1440169689Skan                                               GET_MODE_BITSIZE (wider_mode)))
144118334Speter		  {
144218334Speter		    if (target == 0)
144318334Speter		      target = gen_reg_rtx (mode);
144418334Speter		    convert_move (target, temp, 0);
144518334Speter		    return target;
144618334Speter		  }
144718334Speter		else
144818334Speter		  return gen_lowpart (mode, temp);
144918334Speter	      }
145018334Speter	    else
145118334Speter	      delete_insns_since (last);
145218334Speter	  }
145318334Speter      }
145418334Speter
145518334Speter  /* These can be done a word at a time.  */
145618334Speter  if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
145718334Speter      && class == MODE_INT
145818334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
145918334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
146018334Speter    {
146118334Speter      int i;
146218334Speter      rtx insns;
146318334Speter      rtx equiv_value;
146418334Speter
146518334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
146618334Speter	 won't be accurate, so use a new target.  */
146718334Speter      if (target == 0 || target == op0 || target == op1)
146818334Speter	target = gen_reg_rtx (mode);
146918334Speter
147018334Speter      start_sequence ();
147118334Speter
147218334Speter      /* Do the actual arithmetic.  */
147318334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
147418334Speter	{
147518334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
147618334Speter	  rtx x = expand_binop (word_mode, binoptab,
147718334Speter				operand_subword_force (op0, i, mode),
147818334Speter				operand_subword_force (op1, i, mode),
147918334Speter				target_piece, unsignedp, next_methods);
148018334Speter
148118334Speter	  if (x == 0)
148218334Speter	    break;
148318334Speter
148418334Speter	  if (target_piece != x)
148518334Speter	    emit_move_insn (target_piece, x);
148618334Speter	}
148718334Speter
148818334Speter      insns = get_insns ();
148918334Speter      end_sequence ();
149018334Speter
149118334Speter      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
149218334Speter	{
149318334Speter	  if (binoptab->code != UNKNOWN)
149418334Speter	    equiv_value
149550397Sobrien	      = gen_rtx_fmt_ee (binoptab->code, mode,
149650397Sobrien				copy_rtx (op0), copy_rtx (op1));
149718334Speter	  else
149818334Speter	    equiv_value = 0;
149918334Speter
150018334Speter	  emit_no_conflict_block (insns, target, op0, op1, equiv_value);
150118334Speter	  return target;
150218334Speter	}
150318334Speter    }
150418334Speter
150518334Speter  /* Synthesize double word shifts from single word shifts.  */
150618334Speter  if ((binoptab == lshr_optab || binoptab == ashl_optab
150718334Speter       || binoptab == ashr_optab)
150818334Speter      && class == MODE_INT
1509169689Skan      && (GET_CODE (op1) == CONST_INT || !optimize_size)
151018334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
151118334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
151218334Speter      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
151318334Speter      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
151418334Speter    {
1515169689Skan      unsigned HOST_WIDE_INT shift_mask, double_shift_mask;
1516169689Skan      enum machine_mode op1_mode;
151718334Speter
1518169689Skan      double_shift_mask = targetm.shift_truncation_mask (mode);
1519169689Skan      shift_mask = targetm.shift_truncation_mask (word_mode);
1520169689Skan      op1_mode = GET_MODE (op1) != VOIDmode ? GET_MODE (op1) : word_mode;
152118334Speter
1522169689Skan      /* Apply the truncation to constant shifts.  */
1523169689Skan      if (double_shift_mask > 0 && GET_CODE (op1) == CONST_INT)
1524169689Skan	op1 = GEN_INT (INTVAL (op1) & double_shift_mask);
152518334Speter
1526169689Skan      if (op1 == CONST0_RTX (op1_mode))
1527169689Skan	return op0;
152818334Speter
1529169689Skan      /* Make sure that this is a combination that expand_doubleword_shift
1530169689Skan	 can handle.  See the comments there for details.  */
1531169689Skan      if (double_shift_mask == 0
1532169689Skan	  || (shift_mask == BITS_PER_WORD - 1
1533169689Skan	      && double_shift_mask == BITS_PER_WORD * 2 - 1))
153418334Speter	{
1535169689Skan	  rtx insns, equiv_value;
1536169689Skan	  rtx into_target, outof_target;
1537169689Skan	  rtx into_input, outof_input;
1538169689Skan	  int left_shift, outof_word;
153918334Speter
1540169689Skan	  /* If TARGET is the same as one of the operands, the REG_EQUAL note
1541169689Skan	     won't be accurate, so use a new target.  */
1542169689Skan	  if (target == 0 || target == op0 || target == op1)
1543169689Skan	    target = gen_reg_rtx (mode);
154418334Speter
1545169689Skan	  start_sequence ();
154618334Speter
1547169689Skan	  /* OUTOF_* is the word we are shifting bits away from, and
1548169689Skan	     INTO_* is the word that we are shifting bits towards, thus
1549169689Skan	     they differ depending on the direction of the shift and
1550169689Skan	     WORDS_BIG_ENDIAN.  */
155118334Speter
1552169689Skan	  left_shift = binoptab == ashl_optab;
1553169689Skan	  outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
155418334Speter
1555169689Skan	  outof_target = operand_subword (target, outof_word, 1, mode);
1556169689Skan	  into_target = operand_subword (target, 1 - outof_word, 1, mode);
155718334Speter
1558169689Skan	  outof_input = operand_subword_force (op0, outof_word, mode);
1559169689Skan	  into_input = operand_subword_force (op0, 1 - outof_word, mode);
156018334Speter
1561169689Skan	  if (expand_doubleword_shift (op1_mode, binoptab,
1562169689Skan				       outof_input, into_input, op1,
1563169689Skan				       outof_target, into_target,
1564169689Skan				       unsignedp, next_methods, shift_mask))
1565169689Skan	    {
1566169689Skan	      insns = get_insns ();
1567169689Skan	      end_sequence ();
156818334Speter
1569169689Skan	      equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
1570169689Skan	      emit_no_conflict_block (insns, target, op0, op1, equiv_value);
1571169689Skan	      return target;
1572169689Skan	    }
1573169689Skan	  end_sequence ();
157418334Speter	}
157518334Speter    }
157618334Speter
157718334Speter  /* Synthesize double word rotates from single word shifts.  */
157818334Speter  if ((binoptab == rotl_optab || binoptab == rotr_optab)
157918334Speter      && class == MODE_INT
158018334Speter      && GET_CODE (op1) == CONST_INT
158118334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
158218334Speter      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
158318334Speter      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
158418334Speter    {
1585161651Skan      rtx insns;
158618334Speter      rtx into_target, outof_target;
158718334Speter      rtx into_input, outof_input;
158818334Speter      rtx inter;
158918334Speter      int shift_count, left_shift, outof_word;
159018334Speter
159118334Speter      /* If TARGET is the same as one of the operands, the REG_EQUAL note
1592169689Skan	 won't be accurate, so use a new target. Do this also if target is not
1593169689Skan	 a REG, first because having a register instead may open optimization
1594169689Skan	 opportunities, and second because if target and op0 happen to be MEMs
1595169689Skan	 designating the same location, we would risk clobbering it too early
1596169689Skan	 in the code sequence we generate below.  */
1597169689Skan      if (target == 0 || target == op0 || target == op1 || ! REG_P (target))
159818334Speter	target = gen_reg_rtx (mode);
159918334Speter
160018334Speter      start_sequence ();
160118334Speter
160218334Speter      shift_count = INTVAL (op1);
160318334Speter
160418334Speter      /* OUTOF_* is the word we are shifting bits away from, and
160518334Speter	 INTO_* is the word that we are shifting bits towards, thus
160618334Speter	 they differ depending on the direction of the shift and
160718334Speter	 WORDS_BIG_ENDIAN.  */
160818334Speter
160918334Speter      left_shift = (binoptab == rotl_optab);
161018334Speter      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
161118334Speter
161218334Speter      outof_target = operand_subword (target, outof_word, 1, mode);
161318334Speter      into_target = operand_subword (target, 1 - outof_word, 1, mode);
161418334Speter
161518334Speter      outof_input = operand_subword_force (op0, outof_word, mode);
161618334Speter      into_input = operand_subword_force (op0, 1 - outof_word, mode);
161718334Speter
161818334Speter      if (shift_count == BITS_PER_WORD)
161918334Speter	{
162018334Speter	  /* This is just a word swap.  */
162118334Speter	  emit_move_insn (outof_target, into_input);
162218334Speter	  emit_move_insn (into_target, outof_input);
162318334Speter	  inter = const0_rtx;
162418334Speter	}
162518334Speter      else
162618334Speter	{
162718334Speter	  rtx into_temp1, into_temp2, outof_temp1, outof_temp2;
162818334Speter	  rtx first_shift_count, second_shift_count;
162918334Speter	  optab reverse_unsigned_shift, unsigned_shift;
163018334Speter
163118334Speter	  reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
163218334Speter				    ? lshr_optab : ashl_optab);
163318334Speter
163418334Speter	  unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
163518334Speter			    ? ashl_optab : lshr_optab);
163618334Speter
163718334Speter	  if (shift_count > BITS_PER_WORD)
163818334Speter	    {
163918334Speter	      first_shift_count = GEN_INT (shift_count - BITS_PER_WORD);
1640117395Skan	      second_shift_count = GEN_INT (2 * BITS_PER_WORD - shift_count);
164118334Speter	    }
164218334Speter	  else
164318334Speter	    {
164418334Speter	      first_shift_count = GEN_INT (BITS_PER_WORD - shift_count);
164518334Speter	      second_shift_count = GEN_INT (shift_count);
164618334Speter	    }
164718334Speter
164818334Speter	  into_temp1 = expand_binop (word_mode, unsigned_shift,
164918334Speter				     outof_input, first_shift_count,
165018334Speter				     NULL_RTX, unsignedp, next_methods);
165118334Speter	  into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
165218334Speter				     into_input, second_shift_count,
1653117395Skan				     NULL_RTX, unsignedp, next_methods);
165418334Speter
165518334Speter	  if (into_temp1 != 0 && into_temp2 != 0)
165618334Speter	    inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2,
165718334Speter				  into_target, unsignedp, next_methods);
165818334Speter	  else
165918334Speter	    inter = 0;
166018334Speter
166118334Speter	  if (inter != 0 && inter != into_target)
166218334Speter	    emit_move_insn (into_target, inter);
166318334Speter
166418334Speter	  outof_temp1 = expand_binop (word_mode, unsigned_shift,
166518334Speter				      into_input, first_shift_count,
166618334Speter				      NULL_RTX, unsignedp, next_methods);
166718334Speter	  outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
166818334Speter				      outof_input, second_shift_count,
1669117395Skan				      NULL_RTX, unsignedp, next_methods);
167018334Speter
167118334Speter	  if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)
167218334Speter	    inter = expand_binop (word_mode, ior_optab,
167318334Speter				  outof_temp1, outof_temp2,
167418334Speter				  outof_target, unsignedp, next_methods);
167518334Speter
167618334Speter	  if (inter != 0 && inter != outof_target)
167718334Speter	    emit_move_insn (outof_target, inter);
167818334Speter	}
167918334Speter
168018334Speter      insns = get_insns ();
168118334Speter      end_sequence ();
168218334Speter
168318334Speter      if (inter != 0)
168418334Speter	{
1685169689Skan	  /* One may be tempted to wrap the insns in a REG_NO_CONFLICT
1686169689Skan	     block to help the register allocator a bit.  But a multi-word
1687169689Skan	     rotate will need all the input bits when setting the output
1688169689Skan	     bits, so there clearly is a conflict between the input and
1689169689Skan	     output registers.  So we can't use a no-conflict block here.  */
1690161651Skan	  emit_insn (insns);
169118334Speter	  return target;
169218334Speter	}
169318334Speter    }
169418334Speter
169518334Speter  /* These can be done a word at a time by propagating carries.  */
169618334Speter  if ((binoptab == add_optab || binoptab == sub_optab)
169718334Speter      && class == MODE_INT
169818334Speter      && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD
169918334Speter      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
170018334Speter    {
1701117395Skan      unsigned int i;
170218334Speter      optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
1703117395Skan      const unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
170452284Sobrien      rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
1705102780Skan      rtx xop0, xop1, xtarget;
170618334Speter
170718334Speter      /* We can handle either a 1 or -1 value for the carry.  If STORE_FLAG
170818334Speter	 value is one of those, use it.  Otherwise, use 1 since it is the
170918334Speter	 one easiest to get.  */
171018334Speter#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
171118334Speter      int normalizep = STORE_FLAG_VALUE;
171218334Speter#else
171318334Speter      int normalizep = 1;
171418334Speter#endif
171518334Speter
171618334Speter      /* Prepare the operands.  */
171718334Speter      xop0 = force_reg (mode, op0);
171818334Speter      xop1 = force_reg (mode, op1);
171918334Speter
1720102780Skan      xtarget = gen_reg_rtx (mode);
172118334Speter
1722169689Skan      if (target == 0 || !REG_P (target))
1723102780Skan	target = xtarget;
1724102780Skan
172518334Speter      /* Indicate for flow that the entire target reg is being set.  */
1726169689Skan      if (REG_P (target))
1727102780Skan	emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget));
172818334Speter
172918334Speter      /* Do the actual arithmetic.  */
173018334Speter      for (i = 0; i < nwords; i++)
173118334Speter	{
173218334Speter	  int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
1733102780Skan	  rtx target_piece = operand_subword (xtarget, index, 1, mode);
173418334Speter	  rtx op0_piece = operand_subword_force (xop0, index, mode);
173518334Speter	  rtx op1_piece = operand_subword_force (xop1, index, mode);
173618334Speter	  rtx x;
173718334Speter
173818334Speter	  /* Main add/subtract of the input operands.  */
173918334Speter	  x = expand_binop (word_mode, binoptab,
174018334Speter			    op0_piece, op1_piece,
174118334Speter			    target_piece, unsignedp, next_methods);
174218334Speter	  if (x == 0)
174318334Speter	    break;
174418334Speter
174518334Speter	  if (i + 1 < nwords)
174618334Speter	    {
174718334Speter	      /* Store carry from main add/subtract.  */
174818334Speter	      carry_out = gen_reg_rtx (word_mode);
174950397Sobrien	      carry_out = emit_store_flag_force (carry_out,
175050397Sobrien						 (binoptab == add_optab
175190075Sobrien						  ? LT : GT),
175250397Sobrien						 x, op0_piece,
175350397Sobrien						 word_mode, 1, normalizep);
175418334Speter	    }
175518334Speter
175618334Speter	  if (i > 0)
175718334Speter	    {
175890075Sobrien	      rtx newx;
1759132718Skan
176018334Speter	      /* Add/subtract previous carry to main result.  */
176190075Sobrien	      newx = expand_binop (word_mode,
176290075Sobrien				   normalizep == 1 ? binoptab : otheroptab,
176390075Sobrien				   x, carry_in,
176490075Sobrien				   NULL_RTX, 1, next_methods);
176518334Speter
176618334Speter	      if (i + 1 < nwords)
176718334Speter		{
176818334Speter		  /* Get out carry from adding/subtracting carry in.  */
176990075Sobrien		  rtx carry_tmp = gen_reg_rtx (word_mode);
177050397Sobrien		  carry_tmp = emit_store_flag_force (carry_tmp,
177190075Sobrien						     (binoptab == add_optab
177290075Sobrien						      ? LT : GT),
177390075Sobrien						     newx, x,
177450397Sobrien						     word_mode, 1, normalizep);
177518334Speter
177618334Speter		  /* Logical-ior the two poss. carry together.  */
177718334Speter		  carry_out = expand_binop (word_mode, ior_optab,
177818334Speter					    carry_out, carry_tmp,
177918334Speter					    carry_out, 0, next_methods);
178018334Speter		  if (carry_out == 0)
178118334Speter		    break;
178218334Speter		}
178390075Sobrien	      emit_move_insn (target_piece, newx);
178418334Speter	    }
1785169689Skan	  else
1786169689Skan	    {
1787169689Skan	      if (x != target_piece)
1788169689Skan		emit_move_insn (target_piece, x);
1789169689Skan	    }
179018334Speter
179118334Speter	  carry_in = carry_out;
1792132718Skan	}
179318334Speter
1794117395Skan      if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
179518334Speter	{
1796132718Skan	  if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
1797132718Skan	      || ! rtx_equal_p (target, xtarget))
179850397Sobrien	    {
1799102780Skan	      rtx temp = emit_move_insn (target, xtarget);
180018334Speter
180152284Sobrien	      set_unique_reg_note (temp,
1802132718Skan				   REG_EQUAL,
180352284Sobrien				   gen_rtx_fmt_ee (binoptab->code, mode,
180452284Sobrien						   copy_rtx (xop0),
180552284Sobrien						   copy_rtx (xop1)));
180650397Sobrien	    }
1807117395Skan	  else
1808117395Skan	    target = xtarget;
180990075Sobrien
181018334Speter	  return target;
181118334Speter	}
181290075Sobrien
181318334Speter      else
181418334Speter	delete_insns_since (last);
181518334Speter    }
181618334Speter
1817169689Skan  /* Attempt to synthesize double word multiplies using a sequence of word
1818169689Skan     mode multiplications.  We first attempt to generate a sequence using a
1819169689Skan     more efficient unsigned widening multiply, and if that fails we then
1820169689Skan     try using a signed widening multiply.  */
182118334Speter
182218334Speter  if (binoptab == smul_optab
182318334Speter      && class == MODE_INT
182418334Speter      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
182518334Speter      && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
1826169689Skan      && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
182718334Speter    {
1828169689Skan      rtx product = NULL_RTX;
182918334Speter
1830169689Skan      if (umul_widen_optab->handlers[(int) mode].insn_code
1831169689Skan	  != CODE_FOR_nothing)
183218334Speter	{
1833169689Skan	  product = expand_doubleword_mult (mode, op0, op1, target,
1834169689Skan					    true, methods);
1835169689Skan	  if (!product)
183618334Speter	    delete_insns_since (last);
183718334Speter	}
183818334Speter
1839169689Skan      if (product == NULL_RTX
184018334Speter	  && smul_widen_optab->handlers[(int) mode].insn_code
1841169689Skan	     != CODE_FOR_nothing)
184218334Speter	{
1843169689Skan	  product = expand_doubleword_mult (mode, op0, op1, target,
1844169689Skan					    false, methods);
1845169689Skan	  if (!product)
1846169689Skan	    delete_insns_since (last);
184718334Speter	}
184818334Speter
1849169689Skan      if (product != NULL_RTX)
185018334Speter	{
1851169689Skan	  if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
185218334Speter	    {
1853169689Skan	      temp = emit_move_insn (target ? target : product, product);
1854169689Skan	      set_unique_reg_note (temp,
1855169689Skan				   REG_EQUAL,
1856169689Skan				   gen_rtx_fmt_ee (MULT, mode,
1857169689Skan						   copy_rtx (op0),
1858169689Skan						   copy_rtx (op1)));
185918334Speter	    }
1860169689Skan	  return product;
186118334Speter	}
186218334Speter    }
186318334Speter
186418334Speter  /* It can't be open-coded in this mode.
186518334Speter     Use a library call if one is available and caller says that's ok.  */
186618334Speter
186718334Speter  if (binoptab->handlers[(int) mode].libfunc
186818334Speter      && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
186918334Speter    {
187018334Speter      rtx insns;
187118334Speter      rtx op1x = op1;
187218334Speter      enum machine_mode op1_mode = mode;
187318334Speter      rtx value;
187418334Speter
187518334Speter      start_sequence ();
187618334Speter
187718334Speter      if (shift_op)
187818334Speter	{
187918334Speter	  op1_mode = word_mode;
188018334Speter	  /* Specify unsigned here,
188118334Speter	     since negative shift counts are meaningless.  */
188218334Speter	  op1x = convert_to_mode (word_mode, op1, 1);
188318334Speter	}
188418334Speter
188518334Speter      if (GET_MODE (op0) != VOIDmode
188618334Speter	  && GET_MODE (op0) != mode)
188718334Speter	op0 = convert_to_mode (mode, op0, unsignedp);
188818334Speter
188918334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
189018334Speter	 if the libcall is cse'd or moved.  */
189118334Speter      value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc,
189290075Sobrien				       NULL_RTX, LCT_CONST, mode, 2,
189318334Speter				       op0, mode, op1x, op1_mode);
189418334Speter
189518334Speter      insns = get_insns ();
189618334Speter      end_sequence ();
189718334Speter
189818334Speter      target = gen_reg_rtx (mode);
189918334Speter      emit_libcall_block (insns, target, value,
190050397Sobrien			  gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
190118334Speter
190218334Speter      return target;
190318334Speter    }
190418334Speter
190518334Speter  delete_insns_since (last);
190618334Speter
190718334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
190818334Speter
190918334Speter  if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN
191018334Speter	 || methods == OPTAB_MUST_WIDEN))
191118334Speter    {
191218334Speter      /* Caller says, don't even try.  */
191318334Speter      delete_insns_since (entry_last);
191418334Speter      return 0;
191518334Speter    }
191618334Speter
191718334Speter  /* Compute the value of METHODS to pass to recursive calls.
191818334Speter     Don't allow widening to be tried recursively.  */
191918334Speter
192018334Speter  methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT);
192118334Speter
192218334Speter  /* Look for a wider mode of the same class for which it appears we can do
192318334Speter     the operation.  */
192418334Speter
1925169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
192618334Speter    {
1927169689Skan      for (wider_mode = GET_MODE_WIDER_MODE (mode);
1928169689Skan	   wider_mode != VOIDmode;
192918334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
193018334Speter	{
193118334Speter	  if ((binoptab->handlers[(int) wider_mode].insn_code
193218334Speter	       != CODE_FOR_nothing)
193318334Speter	      || (methods == OPTAB_LIB
193418334Speter		  && binoptab->handlers[(int) wider_mode].libfunc))
193518334Speter	    {
193618334Speter	      rtx xop0 = op0, xop1 = op1;
193718334Speter	      int no_extend = 0;
193818334Speter
193918334Speter	      /* For certain integer operations, we need not actually extend
194018334Speter		 the narrow operands, as long as we will truncate
194118334Speter		 the results to the same narrowness.  */
194218334Speter
194318334Speter	      if ((binoptab == ior_optab || binoptab == and_optab
194418334Speter		   || binoptab == xor_optab
194518334Speter		   || binoptab == add_optab || binoptab == sub_optab
194618334Speter		   || binoptab == smul_optab || binoptab == ashl_optab)
194718334Speter		  && class == MODE_INT)
194818334Speter		no_extend = 1;
194918334Speter
195018334Speter	      xop0 = widen_operand (xop0, wider_mode, mode,
195118334Speter				    unsignedp, no_extend);
195218334Speter
195318334Speter	      /* The second operand of a shift must always be extended.  */
195418334Speter	      xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
195518334Speter				    no_extend && binoptab != ashl_optab);
195618334Speter
195718334Speter	      temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
195818334Speter				   unsignedp, methods);
195918334Speter	      if (temp)
196018334Speter		{
1961169689Skan		  if (class != MODE_INT
1962169689Skan		      || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
1963169689Skan						 GET_MODE_BITSIZE (wider_mode)))
196418334Speter		    {
196518334Speter		      if (target == 0)
196618334Speter			target = gen_reg_rtx (mode);
196718334Speter		      convert_move (target, temp, 0);
196818334Speter		      return target;
196918334Speter		    }
197018334Speter		  else
197118334Speter		    return gen_lowpart (mode, temp);
197218334Speter		}
197318334Speter	      else
197418334Speter		delete_insns_since (last);
197518334Speter	    }
197618334Speter	}
197718334Speter    }
197818334Speter
197918334Speter  delete_insns_since (entry_last);
198018334Speter  return 0;
198118334Speter}
198218334Speter
198318334Speter/* Expand a binary operator which has both signed and unsigned forms.
198418334Speter   UOPTAB is the optab for unsigned operations, and SOPTAB is for
198518334Speter   signed operations.
198618334Speter
198718334Speter   If we widen unsigned operands, we may use a signed wider operation instead
198818334Speter   of an unsigned wider operation, since the result would be the same.  */
198918334Speter
199018334Speterrtx
1991132718Skansign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab,
1992132718Skan		   rtx op0, rtx op1, rtx target, int unsignedp,
1993132718Skan		   enum optab_methods methods)
199418334Speter{
199590075Sobrien  rtx temp;
199618334Speter  optab direct_optab = unsignedp ? uoptab : soptab;
199718334Speter  struct optab wide_soptab;
199818334Speter
199918334Speter  /* Do it without widening, if possible.  */
200018334Speter  temp = expand_binop (mode, direct_optab, op0, op1, target,
200118334Speter		       unsignedp, OPTAB_DIRECT);
200218334Speter  if (temp || methods == OPTAB_DIRECT)
200318334Speter    return temp;
200418334Speter
200518334Speter  /* Try widening to a signed int.  Make a fake signed optab that
200618334Speter     hides any signed insn for direct use.  */
200718334Speter  wide_soptab = *soptab;
200818334Speter  wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing;
200918334Speter  wide_soptab.handlers[(int) mode].libfunc = 0;
201018334Speter
201118334Speter  temp = expand_binop (mode, &wide_soptab, op0, op1, target,
201218334Speter		       unsignedp, OPTAB_WIDEN);
201318334Speter
201418334Speter  /* For unsigned operands, try widening to an unsigned int.  */
201518334Speter  if (temp == 0 && unsignedp)
201618334Speter    temp = expand_binop (mode, uoptab, op0, op1, target,
201718334Speter			 unsignedp, OPTAB_WIDEN);
201818334Speter  if (temp || methods == OPTAB_WIDEN)
201918334Speter    return temp;
202018334Speter
202118334Speter  /* Use the right width lib call if that exists.  */
202218334Speter  temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB);
202318334Speter  if (temp || methods == OPTAB_LIB)
202418334Speter    return temp;
202518334Speter
202618334Speter  /* Must widen and use a lib call, use either signed or unsigned.  */
202718334Speter  temp = expand_binop (mode, &wide_soptab, op0, op1, target,
202818334Speter		       unsignedp, methods);
202918334Speter  if (temp != 0)
203018334Speter    return temp;
203118334Speter  if (unsignedp)
203218334Speter    return expand_binop (mode, uoptab, op0, op1, target,
203318334Speter			 unsignedp, methods);
203418334Speter  return 0;
203518334Speter}
203618334Speter
2037169689Skan/* Generate code to perform an operation specified by UNOPPTAB
2038169689Skan   on operand OP0, with two results to TARG0 and TARG1.
2039169689Skan   We assume that the order of the operands for the instruction
2040169689Skan   is TARG0, TARG1, OP0.
2041169689Skan
2042169689Skan   Either TARG0 or TARG1 may be zero, but what that means is that
2043169689Skan   the result is not actually wanted.  We will generate it into
2044169689Skan   a dummy pseudo-reg and discard it.  They may not both be zero.
2045169689Skan
2046169689Skan   Returns 1 if this operation can be performed; 0 if not.  */
2047169689Skan
2048169689Skanint
2049169689Skanexpand_twoval_unop (optab unoptab, rtx op0, rtx targ0, rtx targ1,
2050169689Skan		    int unsignedp)
2051169689Skan{
2052169689Skan  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
2053169689Skan  enum mode_class class;
2054169689Skan  enum machine_mode wider_mode;
2055169689Skan  rtx entry_last = get_last_insn ();
2056169689Skan  rtx last;
2057169689Skan
2058169689Skan  class = GET_MODE_CLASS (mode);
2059169689Skan
2060169689Skan  if (!targ0)
2061169689Skan    targ0 = gen_reg_rtx (mode);
2062169689Skan  if (!targ1)
2063169689Skan    targ1 = gen_reg_rtx (mode);
2064169689Skan
2065169689Skan  /* Record where to go back to if we fail.  */
2066169689Skan  last = get_last_insn ();
2067169689Skan
2068169689Skan  if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
2069169689Skan    {
2070169689Skan      int icode = (int) unoptab->handlers[(int) mode].insn_code;
2071169689Skan      enum machine_mode mode0 = insn_data[icode].operand[2].mode;
2072169689Skan      rtx pat;
2073169689Skan      rtx xop0 = op0;
2074169689Skan
2075169689Skan      if (GET_MODE (xop0) != VOIDmode
2076169689Skan	  && GET_MODE (xop0) != mode0)
2077169689Skan	xop0 = convert_to_mode (mode0, xop0, unsignedp);
2078169689Skan
2079169689Skan      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
2080169689Skan      if (!insn_data[icode].operand[2].predicate (xop0, mode0))
2081169689Skan	xop0 = copy_to_mode_reg (mode0, xop0);
2082169689Skan
2083169689Skan      /* We could handle this, but we should always be called with a pseudo
2084169689Skan	 for our targets and all insns should take them as outputs.  */
2085169689Skan      gcc_assert (insn_data[icode].operand[0].predicate (targ0, mode));
2086169689Skan      gcc_assert (insn_data[icode].operand[1].predicate (targ1, mode));
2087169689Skan
2088169689Skan      pat = GEN_FCN (icode) (targ0, targ1, xop0);
2089169689Skan      if (pat)
2090169689Skan	{
2091169689Skan	  emit_insn (pat);
2092169689Skan	  return 1;
2093169689Skan	}
2094169689Skan      else
2095169689Skan	delete_insns_since (last);
2096169689Skan    }
2097169689Skan
2098169689Skan  /* It can't be done in this mode.  Can we do it in a wider mode?  */
2099169689Skan
2100169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
2101169689Skan    {
2102169689Skan      for (wider_mode = GET_MODE_WIDER_MODE (mode);
2103169689Skan	   wider_mode != VOIDmode;
2104169689Skan	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
2105169689Skan	{
2106169689Skan	  if (unoptab->handlers[(int) wider_mode].insn_code
2107169689Skan	      != CODE_FOR_nothing)
2108169689Skan	    {
2109169689Skan	      rtx t0 = gen_reg_rtx (wider_mode);
2110169689Skan	      rtx t1 = gen_reg_rtx (wider_mode);
2111169689Skan	      rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp);
2112169689Skan
2113169689Skan	      if (expand_twoval_unop (unoptab, cop0, t0, t1, unsignedp))
2114169689Skan		{
2115169689Skan		  convert_move (targ0, t0, unsignedp);
2116169689Skan		  convert_move (targ1, t1, unsignedp);
2117169689Skan		  return 1;
2118169689Skan		}
2119169689Skan	      else
2120169689Skan		delete_insns_since (last);
2121169689Skan	    }
2122169689Skan	}
2123169689Skan    }
2124169689Skan
2125169689Skan  delete_insns_since (entry_last);
2126169689Skan  return 0;
2127169689Skan}
2128169689Skan
212918334Speter/* Generate code to perform an operation specified by BINOPTAB
213018334Speter   on operands OP0 and OP1, with two results to TARG1 and TARG2.
213118334Speter   We assume that the order of the operands for the instruction
213218334Speter   is TARG0, OP0, OP1, TARG1, which would fit a pattern like
213318334Speter   [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))].
213418334Speter
213518334Speter   Either TARG0 or TARG1 may be zero, but what that means is that
213650397Sobrien   the result is not actually wanted.  We will generate it into
213718334Speter   a dummy pseudo-reg and discard it.  They may not both be zero.
213818334Speter
213918334Speter   Returns 1 if this operation can be performed; 0 if not.  */
214018334Speter
214118334Speterint
2142132718Skanexpand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
2143132718Skan		     int unsignedp)
214418334Speter{
214518334Speter  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
214618334Speter  enum mode_class class;
214718334Speter  enum machine_mode wider_mode;
214818334Speter  rtx entry_last = get_last_insn ();
214918334Speter  rtx last;
215018334Speter
215118334Speter  class = GET_MODE_CLASS (mode);
215218334Speter
2153169689Skan  /* If we are inside an appropriately-short loop and we are optimizing,
2154169689Skan     force expensive constants into a register.  */
2155169689Skan  if (CONSTANT_P (op0) && optimize
215690075Sobrien      && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
215718334Speter    op0 = force_reg (mode, op0);
215818334Speter
2159169689Skan  if (CONSTANT_P (op1) && optimize
216090075Sobrien      && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
216118334Speter    op1 = force_reg (mode, op1);
216218334Speter
2163169689Skan  if (!targ0)
216418334Speter    targ0 = gen_reg_rtx (mode);
2165169689Skan  if (!targ1)
216618334Speter    targ1 = gen_reg_rtx (mode);
216718334Speter
216818334Speter  /* Record where to go back to if we fail.  */
216918334Speter  last = get_last_insn ();
217018334Speter
217118334Speter  if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
217218334Speter    {
217318334Speter      int icode = (int) binoptab->handlers[(int) mode].insn_code;
217490075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
217590075Sobrien      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
217618334Speter      rtx pat;
217718334Speter      rtx xop0 = op0, xop1 = op1;
217818334Speter
2179117395Skan      /* In case the insn wants input operands in modes different from
2180117395Skan	 those of the actual operands, convert the operands.  It would
2181117395Skan	 seem that we don't need to convert CONST_INTs, but we do, so
2182117395Skan	 that they're properly zero-extended, sign-extended or truncated
2183117395Skan	 for their mode.  */
218418334Speter
2185117395Skan      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
2186117395Skan	xop0 = convert_modes (mode0,
2187117395Skan			      GET_MODE (op0) != VOIDmode
2188117395Skan			      ? GET_MODE (op0)
2189117395Skan			      : mode,
2190117395Skan			      xop0, unsignedp);
219118334Speter
2192117395Skan      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
2193117395Skan	xop1 = convert_modes (mode1,
2194117395Skan			      GET_MODE (op1) != VOIDmode
2195117395Skan			      ? GET_MODE (op1)
2196117395Skan			      : mode,
2197117395Skan			      xop1, unsignedp);
2198117395Skan
219918334Speter      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
2200169689Skan      if (!insn_data[icode].operand[1].predicate (xop0, mode0))
220118334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
220218334Speter
2203169689Skan      if (!insn_data[icode].operand[2].predicate (xop1, mode1))
220418334Speter	xop1 = copy_to_mode_reg (mode1, xop1);
220518334Speter
220618334Speter      /* We could handle this, but we should always be called with a pseudo
220718334Speter	 for our targets and all insns should take them as outputs.  */
2208169689Skan      gcc_assert (insn_data[icode].operand[0].predicate (targ0, mode));
2209169689Skan      gcc_assert (insn_data[icode].operand[3].predicate (targ1, mode));
2210132718Skan
221118334Speter      pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
221218334Speter      if (pat)
221318334Speter	{
221418334Speter	  emit_insn (pat);
221518334Speter	  return 1;
221618334Speter	}
221718334Speter      else
221818334Speter	delete_insns_since (last);
221918334Speter    }
222018334Speter
222118334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
222218334Speter
2223169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
222418334Speter    {
2225169689Skan      for (wider_mode = GET_MODE_WIDER_MODE (mode);
2226169689Skan	   wider_mode != VOIDmode;
222718334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
222818334Speter	{
222918334Speter	  if (binoptab->handlers[(int) wider_mode].insn_code
223018334Speter	      != CODE_FOR_nothing)
223118334Speter	    {
223290075Sobrien	      rtx t0 = gen_reg_rtx (wider_mode);
223390075Sobrien	      rtx t1 = gen_reg_rtx (wider_mode);
223490075Sobrien	      rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp);
223590075Sobrien	      rtx cop1 = convert_modes (wider_mode, mode, op1, unsignedp);
223618334Speter
223790075Sobrien	      if (expand_twoval_binop (binoptab, cop0, cop1,
223818334Speter				       t0, t1, unsignedp))
223918334Speter		{
224018334Speter		  convert_move (targ0, t0, unsignedp);
224118334Speter		  convert_move (targ1, t1, unsignedp);
224218334Speter		  return 1;
224318334Speter		}
224418334Speter	      else
224518334Speter		delete_insns_since (last);
224618334Speter	    }
224718334Speter	}
224818334Speter    }
224918334Speter
225018334Speter  delete_insns_since (entry_last);
225118334Speter  return 0;
225218334Speter}
2253169689Skan
2254169689Skan/* Expand the two-valued library call indicated by BINOPTAB, but
2255169689Skan   preserve only one of the values.  If TARG0 is non-NULL, the first
2256169689Skan   value is placed into TARG0; otherwise the second value is placed
2257169689Skan   into TARG1.  Exactly one of TARG0 and TARG1 must be non-NULL.  The
2258169689Skan   value stored into TARG0 or TARG1 is equivalent to (CODE OP0 OP1).
2259169689Skan   This routine assumes that the value returned by the library call is
2260169689Skan   as if the return value was of an integral mode twice as wide as the
2261169689Skan   mode of OP0.  Returns 1 if the call was successful.  */
2262169689Skan
2263169689Skanbool
2264169689Skanexpand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1,
2265169689Skan			     rtx targ0, rtx targ1, enum rtx_code code)
2266169689Skan{
2267169689Skan  enum machine_mode mode;
2268169689Skan  enum machine_mode libval_mode;
2269169689Skan  rtx libval;
2270169689Skan  rtx insns;
2271169689Skan
2272169689Skan  /* Exactly one of TARG0 or TARG1 should be non-NULL.  */
2273169689Skan  gcc_assert (!targ0 != !targ1);
2274169689Skan
2275169689Skan  mode = GET_MODE (op0);
2276169689Skan  if (!binoptab->handlers[(int) mode].libfunc)
2277169689Skan    return false;
2278169689Skan
2279169689Skan  /* The value returned by the library function will have twice as
2280169689Skan     many bits as the nominal MODE.  */
2281169689Skan  libval_mode = smallest_mode_for_size (2 * GET_MODE_BITSIZE (mode),
2282169689Skan					MODE_INT);
2283169689Skan  start_sequence ();
2284169689Skan  libval = emit_library_call_value (binoptab->handlers[(int) mode].libfunc,
2285169689Skan				    NULL_RTX, LCT_CONST,
2286169689Skan				    libval_mode, 2,
2287169689Skan				    op0, mode,
2288169689Skan				    op1, mode);
2289169689Skan  /* Get the part of VAL containing the value that we want.  */
2290169689Skan  libval = simplify_gen_subreg (mode, libval, libval_mode,
2291169689Skan				targ0 ? 0 : GET_MODE_SIZE (mode));
2292169689Skan  insns = get_insns ();
2293169689Skan  end_sequence ();
2294169689Skan  /* Move the into the desired location.  */
2295169689Skan  emit_libcall_block (insns, targ0 ? targ0 : targ1, libval,
2296169689Skan		      gen_rtx_fmt_ee (code, mode, op0, op1));
2297169689Skan
2298169689Skan  return true;
2299169689Skan}
2300169689Skan
230118334Speter
230290075Sobrien/* Wrapper around expand_unop which takes an rtx code to specify
230390075Sobrien   the operation to perform, not an optab pointer.  All other
230490075Sobrien   arguments are the same.  */
230590075Sobrienrtx
2306132718Skanexpand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0,
2307132718Skan		    rtx target, int unsignedp)
230890075Sobrien{
2309117395Skan  optab unop = code_to_optab[(int) code];
2310169689Skan  gcc_assert (unop);
231190075Sobrien
231290075Sobrien  return expand_unop (mode, unop, op0, target, unsignedp);
231390075Sobrien}
231490075Sobrien
2315132718Skan/* Try calculating
2316132718Skan	(clz:narrow x)
2317132718Skan   as
2318132718Skan	(clz:wide (zero_extend:wide x)) - ((width wide) - (width narrow)).  */
2319132718Skanstatic rtx
2320132718Skanwiden_clz (enum machine_mode mode, rtx op0, rtx target)
2321132718Skan{
2322132718Skan  enum mode_class class = GET_MODE_CLASS (mode);
2323169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
2324132718Skan    {
2325132718Skan      enum machine_mode wider_mode;
2326169689Skan      for (wider_mode = GET_MODE_WIDER_MODE (mode);
2327169689Skan	   wider_mode != VOIDmode;
2328132718Skan	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
2329132718Skan	{
2330132718Skan	  if (clz_optab->handlers[(int) wider_mode].insn_code
2331132718Skan	      != CODE_FOR_nothing)
2332132718Skan	    {
2333132718Skan	      rtx xop0, temp, last;
2334132718Skan
2335132718Skan	      last = get_last_insn ();
2336132718Skan
2337132718Skan	      if (target == 0)
2338132718Skan		target = gen_reg_rtx (mode);
2339132718Skan	      xop0 = widen_operand (op0, wider_mode, mode, true, false);
2340132718Skan	      temp = expand_unop (wider_mode, clz_optab, xop0, NULL_RTX, true);
2341132718Skan	      if (temp != 0)
2342132718Skan		temp = expand_binop (wider_mode, sub_optab, temp,
2343132718Skan				     GEN_INT (GET_MODE_BITSIZE (wider_mode)
2344132718Skan					      - GET_MODE_BITSIZE (mode)),
2345132718Skan				     target, true, OPTAB_DIRECT);
2346132718Skan	      if (temp == 0)
2347132718Skan		delete_insns_since (last);
2348132718Skan
2349132718Skan	      return temp;
2350132718Skan	    }
2351132718Skan	}
2352132718Skan    }
2353132718Skan  return 0;
2354132718Skan}
2355132718Skan
2356132718Skan/* Try calculating (parity x) as (and (popcount x) 1), where
2357132718Skan   popcount can also be done in a wider mode.  */
2358132718Skanstatic rtx
2359132718Skanexpand_parity (enum machine_mode mode, rtx op0, rtx target)
2360132718Skan{
2361132718Skan  enum mode_class class = GET_MODE_CLASS (mode);
2362169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
2363132718Skan    {
2364132718Skan      enum machine_mode wider_mode;
2365132718Skan      for (wider_mode = mode; wider_mode != VOIDmode;
2366132718Skan	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
2367132718Skan	{
2368132718Skan	  if (popcount_optab->handlers[(int) wider_mode].insn_code
2369132718Skan	      != CODE_FOR_nothing)
2370132718Skan	    {
2371132718Skan	      rtx xop0, temp, last;
2372132718Skan
2373132718Skan	      last = get_last_insn ();
2374132718Skan
2375132718Skan	      if (target == 0)
2376132718Skan		target = gen_reg_rtx (mode);
2377132718Skan	      xop0 = widen_operand (op0, wider_mode, mode, true, false);
2378132718Skan	      temp = expand_unop (wider_mode, popcount_optab, xop0, NULL_RTX,
2379132718Skan				  true);
2380132718Skan	      if (temp != 0)
2381169689Skan		temp = expand_binop (wider_mode, and_optab, temp, const1_rtx,
2382132718Skan				     target, true, OPTAB_DIRECT);
2383132718Skan	      if (temp == 0)
2384132718Skan		delete_insns_since (last);
2385132718Skan
2386132718Skan	      return temp;
2387132718Skan	    }
2388132718Skan	}
2389132718Skan    }
2390132718Skan  return 0;
2391132718Skan}
2392132718Skan
2393169689Skan/* Extract the OMODE lowpart from VAL, which has IMODE.  Under certain
2394169689Skan   conditions, VAL may already be a SUBREG against which we cannot generate
2395169689Skan   a further SUBREG.  In this case, we expect forcing the value into a
2396169689Skan   register will work around the situation.  */
2397169689Skan
2398169689Skanstatic rtx
2399169689Skanlowpart_subreg_maybe_copy (enum machine_mode omode, rtx val,
2400169689Skan			   enum machine_mode imode)
2401169689Skan{
2402169689Skan  rtx ret;
2403169689Skan  ret = lowpart_subreg (omode, val, imode);
2404169689Skan  if (ret == NULL)
2405169689Skan    {
2406169689Skan      val = force_reg (imode, val);
2407169689Skan      ret = lowpart_subreg (omode, val, imode);
2408169689Skan      gcc_assert (ret != NULL);
2409169689Skan    }
2410169689Skan  return ret;
2411169689Skan}
2412169689Skan
2413169689Skan/* Expand a floating point absolute value or negation operation via a
2414169689Skan   logical operation on the sign bit.  */
2415169689Skan
2416169689Skanstatic rtx
2417169689Skanexpand_absneg_bit (enum rtx_code code, enum machine_mode mode,
2418169689Skan		   rtx op0, rtx target)
2419169689Skan{
2420169689Skan  const struct real_format *fmt;
2421169689Skan  int bitpos, word, nwords, i;
2422169689Skan  enum machine_mode imode;
2423169689Skan  HOST_WIDE_INT hi, lo;
2424169689Skan  rtx temp, insns;
2425169689Skan
2426169689Skan  /* The format has to have a simple sign bit.  */
2427169689Skan  fmt = REAL_MODE_FORMAT (mode);
2428169689Skan  if (fmt == NULL)
2429169689Skan    return NULL_RTX;
2430169689Skan
2431169689Skan  bitpos = fmt->signbit_rw;
2432169689Skan  if (bitpos < 0)
2433169689Skan    return NULL_RTX;
2434169689Skan
2435169689Skan  /* Don't create negative zeros if the format doesn't support them.  */
2436169689Skan  if (code == NEG && !fmt->has_signed_zero)
2437169689Skan    return NULL_RTX;
2438169689Skan
2439169689Skan  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2440169689Skan    {
2441169689Skan      imode = int_mode_for_mode (mode);
2442169689Skan      if (imode == BLKmode)
2443169689Skan	return NULL_RTX;
2444169689Skan      word = 0;
2445169689Skan      nwords = 1;
2446169689Skan    }
2447169689Skan  else
2448169689Skan    {
2449169689Skan      imode = word_mode;
2450169689Skan
2451169689Skan      if (FLOAT_WORDS_BIG_ENDIAN)
2452169689Skan	word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD;
2453169689Skan      else
2454169689Skan	word = bitpos / BITS_PER_WORD;
2455169689Skan      bitpos = bitpos % BITS_PER_WORD;
2456169689Skan      nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
2457169689Skan    }
2458169689Skan
2459169689Skan  if (bitpos < HOST_BITS_PER_WIDE_INT)
2460169689Skan    {
2461169689Skan      hi = 0;
2462169689Skan      lo = (HOST_WIDE_INT) 1 << bitpos;
2463169689Skan    }
2464169689Skan  else
2465169689Skan    {
2466169689Skan      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
2467169689Skan      lo = 0;
2468169689Skan    }
2469169689Skan  if (code == ABS)
2470169689Skan    lo = ~lo, hi = ~hi;
2471169689Skan
2472169689Skan  if (target == 0 || target == op0)
2473169689Skan    target = gen_reg_rtx (mode);
2474169689Skan
2475169689Skan  if (nwords > 1)
2476169689Skan    {
2477169689Skan      start_sequence ();
2478169689Skan
2479169689Skan      for (i = 0; i < nwords; ++i)
2480169689Skan	{
2481169689Skan	  rtx targ_piece = operand_subword (target, i, 1, mode);
2482169689Skan	  rtx op0_piece = operand_subword_force (op0, i, mode);
2483169689Skan
2484169689Skan	  if (i == word)
2485169689Skan	    {
2486169689Skan	      temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
2487169689Skan				   op0_piece,
2488169689Skan				   immed_double_const (lo, hi, imode),
2489169689Skan				   targ_piece, 1, OPTAB_LIB_WIDEN);
2490169689Skan	      if (temp != targ_piece)
2491169689Skan		emit_move_insn (targ_piece, temp);
2492169689Skan	    }
2493169689Skan	  else
2494169689Skan	    emit_move_insn (targ_piece, op0_piece);
2495169689Skan	}
2496169689Skan
2497169689Skan      insns = get_insns ();
2498169689Skan      end_sequence ();
2499169689Skan
2500169689Skan      temp = gen_rtx_fmt_e (code, mode, copy_rtx (op0));
2501169689Skan      emit_no_conflict_block (insns, target, op0, NULL_RTX, temp);
2502169689Skan    }
2503169689Skan  else
2504169689Skan    {
2505169689Skan      temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
2506169689Skan			   gen_lowpart (imode, op0),
2507169689Skan			   immed_double_const (lo, hi, imode),
2508169689Skan		           gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
2509169689Skan      target = lowpart_subreg_maybe_copy (mode, temp, imode);
2510169689Skan
2511169689Skan      set_unique_reg_note (get_last_insn (), REG_EQUAL,
2512169689Skan			   gen_rtx_fmt_e (code, mode, copy_rtx (op0)));
2513169689Skan    }
2514169689Skan
2515169689Skan  return target;
2516169689Skan}
2517169689Skan
251818334Speter/* Generate code to perform an operation specified by UNOPTAB
251918334Speter   on operand OP0, with result having machine-mode MODE.
252018334Speter
252118334Speter   UNSIGNEDP is for the case where we have to widen the operands
252218334Speter   to perform the operation.  It says to use zero-extension.
252318334Speter
252418334Speter   If TARGET is nonzero, the value
252518334Speter   is generated there, if it is convenient to do so.
252618334Speter   In all cases an rtx is returned for the locus of the value;
252718334Speter   this may or may not be TARGET.  */
252818334Speter
252918334Speterrtx
2530132718Skanexpand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
2531132718Skan	     int unsignedp)
253218334Speter{
253318334Speter  enum mode_class class;
253418334Speter  enum machine_mode wider_mode;
253590075Sobrien  rtx temp;
253618334Speter  rtx last = get_last_insn ();
253718334Speter  rtx pat;
253818334Speter
253918334Speter  class = GET_MODE_CLASS (mode);
254018334Speter
254118334Speter  if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
254218334Speter    {
254318334Speter      int icode = (int) unoptab->handlers[(int) mode].insn_code;
254490075Sobrien      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
254518334Speter      rtx xop0 = op0;
254618334Speter
254718334Speter      if (target)
254818334Speter	temp = target;
254918334Speter      else
255018334Speter	temp = gen_reg_rtx (mode);
255118334Speter
255218334Speter      if (GET_MODE (xop0) != VOIDmode
255318334Speter	  && GET_MODE (xop0) != mode0)
255418334Speter	xop0 = convert_to_mode (mode0, xop0, unsignedp);
255518334Speter
255618334Speter      /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
255718334Speter
2558169689Skan      if (!insn_data[icode].operand[1].predicate (xop0, mode0))
255918334Speter	xop0 = copy_to_mode_reg (mode0, xop0);
256018334Speter
2561169689Skan      if (!insn_data[icode].operand[0].predicate (temp, mode))
256218334Speter	temp = gen_reg_rtx (mode);
256318334Speter
256418334Speter      pat = GEN_FCN (icode) (temp, xop0);
256518334Speter      if (pat)
256618334Speter	{
2567117395Skan	  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
256818334Speter	      && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX))
256918334Speter	    {
257018334Speter	      delete_insns_since (last);
257118334Speter	      return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp);
257218334Speter	    }
257318334Speter
257418334Speter	  emit_insn (pat);
2575132718Skan
257618334Speter	  return temp;
257718334Speter	}
257818334Speter      else
257918334Speter	delete_insns_since (last);
258018334Speter    }
258118334Speter
258218334Speter  /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
258318334Speter
2584132718Skan  /* Widening clz needs special treatment.  */
2585132718Skan  if (unoptab == clz_optab)
2586132718Skan    {
2587132718Skan      temp = widen_clz (mode, op0, target);
2588132718Skan      if (temp)
2589132718Skan	return temp;
2590132718Skan      else
2591132718Skan	goto try_libcall;
2592132718Skan    }
2593132718Skan
2594259563Spfg  /* We can't widen a bswap.  */
2595259563Spfg  if (unoptab == bswap_optab)
2596259563Spfg    goto try_libcall;
2597259563Spfg
2598169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
2599169689Skan    for (wider_mode = GET_MODE_WIDER_MODE (mode);
2600169689Skan	 wider_mode != VOIDmode;
260118334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
260218334Speter      {
260318334Speter	if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
260418334Speter	  {
260518334Speter	    rtx xop0 = op0;
260618334Speter
260718334Speter	    /* For certain operations, we need not actually extend
260818334Speter	       the narrow operand, as long as we will truncate the
260918334Speter	       results to the same narrowness.  */
261018334Speter
261118334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
261218334Speter				  (unoptab == neg_optab
261318334Speter				   || unoptab == one_cmpl_optab)
261418334Speter				  && class == MODE_INT);
2615132718Skan
261618334Speter	    temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
261718334Speter				unsignedp);
261818334Speter
261918334Speter	    if (temp)
262018334Speter	      {
2621169689Skan		if (class != MODE_INT
2622169689Skan		    || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
2623169689Skan					       GET_MODE_BITSIZE (wider_mode)))
262418334Speter		  {
262518334Speter		    if (target == 0)
262618334Speter		      target = gen_reg_rtx (mode);
262718334Speter		    convert_move (target, temp, 0);
262818334Speter		    return target;
262918334Speter		  }
263018334Speter		else
263118334Speter		  return gen_lowpart (mode, temp);
263218334Speter	      }
263318334Speter	    else
263418334Speter	      delete_insns_since (last);
263518334Speter	  }
263618334Speter      }
263718334Speter
263818334Speter  /* These can be done a word at a time.  */
263918334Speter  if (unoptab == one_cmpl_optab
264018334Speter      && class == MODE_INT
264118334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
264218334Speter      && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
264318334Speter    {
264418334Speter      int i;
264518334Speter      rtx insns;
264618334Speter
264718334Speter      if (target == 0 || target == op0)
264818334Speter	target = gen_reg_rtx (mode);
264918334Speter
265018334Speter      start_sequence ();
265118334Speter
265218334Speter      /* Do the actual arithmetic.  */
265318334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
265418334Speter	{
265518334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
265618334Speter	  rtx x = expand_unop (word_mode, unoptab,
265718334Speter			       operand_subword_force (op0, i, mode),
265818334Speter			       target_piece, unsignedp);
265990075Sobrien
266018334Speter	  if (target_piece != x)
266118334Speter	    emit_move_insn (target_piece, x);
266218334Speter	}
266318334Speter
266418334Speter      insns = get_insns ();
266518334Speter      end_sequence ();
266618334Speter
266718334Speter      emit_no_conflict_block (insns, target, op0, NULL_RTX,
266850397Sobrien			      gen_rtx_fmt_e (unoptab->code, mode,
266950397Sobrien					     copy_rtx (op0)));
267018334Speter      return target;
267118334Speter    }
267218334Speter
2673169689Skan  if (unoptab->code == NEG)
267418334Speter    {
2675169689Skan      /* Try negating floating point values by flipping the sign bit.  */
2676169689Skan      if (SCALAR_FLOAT_MODE_P (mode))
2677169689Skan	{
2678169689Skan	  temp = expand_absneg_bit (NEG, mode, op0, target);
2679169689Skan	  if (temp)
2680169689Skan	    return temp;
2681169689Skan	}
268218334Speter
2683169689Skan      /* If there is no negation pattern, and we have no negative zero,
2684169689Skan	 try subtracting from zero.  */
2685169689Skan      if (!HONOR_SIGNED_ZEROS (mode))
2686132718Skan	{
2687169689Skan	  temp = expand_binop (mode, (unoptab == negv_optab
2688169689Skan				      ? subv_optab : sub_optab),
2689169689Skan			       CONST0_RTX (mode), op0, target,
2690169689Skan			       unsignedp, OPTAB_DIRECT);
2691169689Skan	  if (temp)
2692169689Skan	    return temp;
2693169689Skan	}
2694132718Skan    }
2695132718Skan
2696132718Skan  /* Try calculating parity (x) as popcount (x) % 2.  */
2697132718Skan  if (unoptab == parity_optab)
2698132718Skan    {
2699132718Skan      temp = expand_parity (mode, op0, target);
2700132718Skan      if (temp)
2701132718Skan	return temp;
2702132718Skan    }
2703132718Skan
2704132718Skan try_libcall:
270518334Speter  /* Now try a library call in this mode.  */
270618334Speter  if (unoptab->handlers[(int) mode].libfunc)
270718334Speter    {
270818334Speter      rtx insns;
270918334Speter      rtx value;
2710132718Skan      enum machine_mode outmode = mode;
271118334Speter
2712132718Skan      /* All of these functions return small values.  Thus we choose to
2713132718Skan	 have them return something that isn't a double-word.  */
2714132718Skan      if (unoptab == ffs_optab || unoptab == clz_optab || unoptab == ctz_optab
2715132718Skan	  || unoptab == popcount_optab || unoptab == parity_optab)
2716132718Skan	outmode
2717132718Skan	    = GET_MODE (hard_libcall_value (TYPE_MODE (integer_type_node)));
2718132718Skan
271918334Speter      start_sequence ();
272018334Speter
272118334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
272218334Speter	 if the libcall is cse'd or moved.  */
272318334Speter      value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
2724132718Skan				       NULL_RTX, LCT_CONST, outmode,
2725132718Skan				       1, op0, mode);
272618334Speter      insns = get_insns ();
272718334Speter      end_sequence ();
272818334Speter
2729132718Skan      target = gen_reg_rtx (outmode);
273018334Speter      emit_libcall_block (insns, target, value,
2731169689Skan			  gen_rtx_fmt_e (unoptab->code, outmode, op0));
273218334Speter
273318334Speter      return target;
273418334Speter    }
273518334Speter
273618334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
273718334Speter
2738169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
273918334Speter    {
2740169689Skan      for (wider_mode = GET_MODE_WIDER_MODE (mode);
2741169689Skan	   wider_mode != VOIDmode;
274218334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
274318334Speter	{
274418334Speter	  if ((unoptab->handlers[(int) wider_mode].insn_code
274518334Speter	       != CODE_FOR_nothing)
274618334Speter	      || unoptab->handlers[(int) wider_mode].libfunc)
274718334Speter	    {
274818334Speter	      rtx xop0 = op0;
274918334Speter
275018334Speter	      /* For certain operations, we need not actually extend
275118334Speter		 the narrow operand, as long as we will truncate the
275218334Speter		 results to the same narrowness.  */
275318334Speter
275418334Speter	      xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
275518334Speter				    (unoptab == neg_optab
275618334Speter				     || unoptab == one_cmpl_optab)
275718334Speter				    && class == MODE_INT);
2758132718Skan
275918334Speter	      temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
276018334Speter				  unsignedp);
276118334Speter
2762132718Skan	      /* If we are generating clz using wider mode, adjust the
2763132718Skan		 result.  */
2764132718Skan	      if (unoptab == clz_optab && temp != 0)
2765132718Skan		temp = expand_binop (wider_mode, sub_optab, temp,
2766132718Skan				     GEN_INT (GET_MODE_BITSIZE (wider_mode)
2767132718Skan					      - GET_MODE_BITSIZE (mode)),
2768132718Skan				     target, true, OPTAB_DIRECT);
2769132718Skan
277018334Speter	      if (temp)
277118334Speter		{
277218334Speter		  if (class != MODE_INT)
277318334Speter		    {
277418334Speter		      if (target == 0)
277518334Speter			target = gen_reg_rtx (mode);
277618334Speter		      convert_move (target, temp, 0);
277718334Speter		      return target;
277818334Speter		    }
277918334Speter		  else
278018334Speter		    return gen_lowpart (mode, temp);
278118334Speter		}
278218334Speter	      else
278318334Speter		delete_insns_since (last);
278418334Speter	    }
278518334Speter	}
278618334Speter    }
278718334Speter
2788169689Skan  /* One final attempt at implementing negation via subtraction,
2789169689Skan     this time allowing widening of the operand.  */
2790169689Skan  if (unoptab->code == NEG && !HONOR_SIGNED_ZEROS (mode))
2791132718Skan    {
279218334Speter      rtx temp;
279390075Sobrien      temp = expand_binop (mode,
279490075Sobrien                           unoptab == negv_optab ? subv_optab : sub_optab,
279590075Sobrien                           CONST0_RTX (mode), op0,
279690075Sobrien                           target, unsignedp, OPTAB_LIB_WIDEN);
279718334Speter      if (temp)
2798169689Skan        return temp;
279918334Speter    }
2800132718Skan
280118334Speter  return 0;
280218334Speter}
280318334Speter
280418334Speter/* Emit code to compute the absolute value of OP0, with result to
280518334Speter   TARGET if convenient.  (TARGET may be 0.)  The return value says
280618334Speter   where the result actually is to be found.
280718334Speter
280818334Speter   MODE is the mode of the operand; the mode of the result is
280918334Speter   different but can be deduced from MODE.
281018334Speter
281152284Sobrien */
281218334Speter
281318334Speterrtx
2814132718Skanexpand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
2815132718Skan		   int result_unsignedp)
281618334Speter{
2817132718Skan  rtx temp;
281818334Speter
281990075Sobrien  if (! flag_trapv)
282090075Sobrien    result_unsignedp = 1;
282190075Sobrien
282218334Speter  /* First try to do it with a special abs instruction.  */
282390075Sobrien  temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab,
282490075Sobrien                      op0, target, 0);
282518334Speter  if (temp != 0)
282618334Speter    return temp;
282718334Speter
2828132718Skan  /* For floating point modes, try clearing the sign bit.  */
2829169689Skan  if (SCALAR_FLOAT_MODE_P (mode))
2830132718Skan    {
2831169689Skan      temp = expand_absneg_bit (ABS, mode, op0, target);
2832169689Skan      if (temp)
2833169689Skan	return temp;
2834132718Skan    }
2835132718Skan
283690075Sobrien  /* If we have a MAX insn, we can do this as MAX (x, -x).  */
2837169689Skan  if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
2838169689Skan      && !HONOR_SIGNED_ZEROS (mode))
283990075Sobrien    {
284090075Sobrien      rtx last = get_last_insn ();
284190075Sobrien
284290075Sobrien      temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0);
284390075Sobrien      if (temp != 0)
284490075Sobrien	temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
284590075Sobrien			     OPTAB_WIDEN);
284690075Sobrien
284790075Sobrien      if (temp != 0)
284890075Sobrien	return temp;
284990075Sobrien
285090075Sobrien      delete_insns_since (last);
285190075Sobrien    }
285290075Sobrien
285318334Speter  /* If this machine has expensive jumps, we can do integer absolute
285418334Speter     value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
285518334Speter     where W is the width of MODE.  */
285618334Speter
285718334Speter  if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
285818334Speter    {
285918334Speter      rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
286018334Speter				   size_int (GET_MODE_BITSIZE (mode) - 1),
286118334Speter				   NULL_RTX, 0);
286218334Speter
286318334Speter      temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
286418334Speter			   OPTAB_LIB_WIDEN);
286518334Speter      if (temp != 0)
286690075Sobrien	temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab,
286790075Sobrien                             temp, extended, target, 0, OPTAB_LIB_WIDEN);
286818334Speter
286918334Speter      if (temp != 0)
287018334Speter	return temp;
287118334Speter    }
287218334Speter
2873132718Skan  return NULL_RTX;
2874132718Skan}
2875132718Skan
2876132718Skanrtx
2877132718Skanexpand_abs (enum machine_mode mode, rtx op0, rtx target,
2878132718Skan	    int result_unsignedp, int safe)
2879132718Skan{
2880132718Skan  rtx temp, op1;
2881132718Skan
2882132718Skan  if (! flag_trapv)
2883132718Skan    result_unsignedp = 1;
2884132718Skan
2885132718Skan  temp = expand_abs_nojump (mode, op0, target, result_unsignedp);
2886132718Skan  if (temp != 0)
2887132718Skan    return temp;
2888132718Skan
288918334Speter  /* If that does not win, use conditional jump and negate.  */
289050397Sobrien
289150397Sobrien  /* It is safe to use the target if it is the same
289250397Sobrien     as the source if this is also a pseudo register */
2893169689Skan  if (op0 == target && REG_P (op0)
289450397Sobrien      && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
289550397Sobrien    safe = 1;
289650397Sobrien
289718334Speter  op1 = gen_label_rtx ();
289818334Speter  if (target == 0 || ! safe
289918334Speter      || GET_MODE (target) != mode
2900169689Skan      || (MEM_P (target) && MEM_VOLATILE_P (target))
2901169689Skan      || (REG_P (target)
290218334Speter	  && REGNO (target) < FIRST_PSEUDO_REGISTER))
290318334Speter    target = gen_reg_rtx (mode);
290418334Speter
290518334Speter  emit_move_insn (target, op0);
290618334Speter  NO_DEFER_POP;
290718334Speter
2908169689Skan  do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
2909169689Skan			   NULL_RTX, NULL_RTX, op1);
291018334Speter
291190075Sobrien  op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
291290075Sobrien                     target, target, 0);
291318334Speter  if (op0 != target)
291418334Speter    emit_move_insn (target, op0);
291518334Speter  emit_label (op1);
291618334Speter  OK_DEFER_POP;
291718334Speter  return target;
291818334Speter}
291918334Speter
2920169689Skan/* A subroutine of expand_copysign, perform the copysign operation using the
2921169689Skan   abs and neg primitives advertised to exist on the target.  The assumption
2922169689Skan   is that we have a split register file, and leaving op0 in fp registers,
2923169689Skan   and not playing with subregs so much, will help the register allocator.  */
292418334Speter
2925169689Skanstatic rtx
2926169689Skanexpand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
2927169689Skan		        int bitpos, bool op0_is_abs)
292818334Speter{
2929169689Skan  enum machine_mode imode;
2930169689Skan  HOST_WIDE_INT hi, lo;
2931169689Skan  int word;
2932169689Skan  rtx label;
293318334Speter
2934169689Skan  if (target == op1)
2935169689Skan    target = NULL_RTX;
293618334Speter
2937169689Skan  if (!op0_is_abs)
2938169689Skan    {
2939169689Skan      op0 = expand_unop (mode, abs_optab, op0, target, 0);
2940169689Skan      if (op0 == NULL)
2941169689Skan	return NULL_RTX;
2942169689Skan      target = op0;
2943169689Skan    }
2944169689Skan  else
2945169689Skan    {
2946169689Skan      if (target == NULL_RTX)
2947169689Skan        target = copy_to_reg (op0);
2948169689Skan      else
2949169689Skan	emit_move_insn (target, op0);
2950169689Skan    }
295118334Speter
2952169689Skan  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2953169689Skan    {
2954169689Skan      imode = int_mode_for_mode (mode);
2955169689Skan      if (imode == BLKmode)
2956169689Skan	return NULL_RTX;
2957169689Skan      op1 = gen_lowpart (imode, op1);
2958169689Skan    }
2959169689Skan  else
2960169689Skan    {
2961169689Skan      imode = word_mode;
2962169689Skan      if (FLOAT_WORDS_BIG_ENDIAN)
2963169689Skan	word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD;
2964169689Skan      else
2965169689Skan	word = bitpos / BITS_PER_WORD;
2966169689Skan      bitpos = bitpos % BITS_PER_WORD;
2967169689Skan      op1 = operand_subword_force (op1, word, mode);
2968169689Skan    }
296918334Speter
2970169689Skan  if (bitpos < HOST_BITS_PER_WIDE_INT)
297118334Speter    {
2972169689Skan      hi = 0;
2973169689Skan      lo = (HOST_WIDE_INT) 1 << bitpos;
297418334Speter    }
2975169689Skan  else
2976169689Skan    {
2977169689Skan      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
2978169689Skan      lo = 0;
2979169689Skan    }
298018334Speter
2981169689Skan  op1 = expand_binop (imode, and_optab, op1,
2982169689Skan		      immed_double_const (lo, hi, imode),
2983169689Skan		      NULL_RTX, 1, OPTAB_LIB_WIDEN);
298418334Speter
2985169689Skan  label = gen_label_rtx ();
2986169689Skan  emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, imode, 1, label);
298718334Speter
2988169689Skan  if (GET_CODE (op0) == CONST_DOUBLE)
2989169689Skan    op0 = simplify_unary_operation (NEG, mode, op0, mode);
2990169689Skan  else
2991169689Skan    op0 = expand_unop (mode, neg_optab, op0, target, 0);
2992169689Skan  if (op0 != target)
2993169689Skan    emit_move_insn (target, op0);
299490075Sobrien
2995169689Skan  emit_label (label);
299618334Speter
2997169689Skan  return target;
2998169689Skan}
299918334Speter
300018334Speter
3001169689Skan/* A subroutine of expand_copysign, perform the entire copysign operation
3002169689Skan   with integer bitmasks.  BITPOS is the position of the sign bit; OP0_IS_ABS
3003169689Skan   is true if op0 is known to have its sign bit clear.  */
300418334Speter
3005169689Skanstatic rtx
3006169689Skanexpand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
3007169689Skan		     int bitpos, bool op0_is_abs)
3008169689Skan{
3009169689Skan  enum machine_mode imode;
3010169689Skan  HOST_WIDE_INT hi, lo;
3011169689Skan  int word, nwords, i;
3012169689Skan  rtx temp, insns;
301318334Speter
3014169689Skan  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
3015169689Skan    {
3016169689Skan      imode = int_mode_for_mode (mode);
3017169689Skan      if (imode == BLKmode)
3018169689Skan	return NULL_RTX;
3019169689Skan      word = 0;
3020169689Skan      nwords = 1;
3021169689Skan    }
3022169689Skan  else
3023169689Skan    {
3024169689Skan      imode = word_mode;
302518334Speter
3026169689Skan      if (FLOAT_WORDS_BIG_ENDIAN)
3027169689Skan	word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD;
302818334Speter      else
3029169689Skan	word = bitpos / BITS_PER_WORD;
3030169689Skan      bitpos = bitpos % BITS_PER_WORD;
3031169689Skan      nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
303218334Speter    }
303318334Speter
3034169689Skan  if (bitpos < HOST_BITS_PER_WIDE_INT)
3035169689Skan    {
3036169689Skan      hi = 0;
3037169689Skan      lo = (HOST_WIDE_INT) 1 << bitpos;
3038169689Skan    }
3039169689Skan  else
3040169689Skan    {
3041169689Skan      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
3042169689Skan      lo = 0;
3043169689Skan    }
304418334Speter
3045169689Skan  if (target == 0 || target == op0 || target == op1)
3046169689Skan    target = gen_reg_rtx (mode);
3047169689Skan
3048169689Skan  if (nwords > 1)
304918334Speter    {
3050169689Skan      start_sequence ();
3051169689Skan
3052169689Skan      for (i = 0; i < nwords; ++i)
305318334Speter	{
3054169689Skan	  rtx targ_piece = operand_subword (target, i, 1, mode);
3055169689Skan	  rtx op0_piece = operand_subword_force (op0, i, mode);
305618334Speter
3057169689Skan	  if (i == word)
3058169689Skan	    {
3059169689Skan	      if (!op0_is_abs)
3060169689Skan		op0_piece = expand_binop (imode, and_optab, op0_piece,
3061169689Skan					  immed_double_const (~lo, ~hi, imode),
3062169689Skan					  NULL_RTX, 1, OPTAB_LIB_WIDEN);
306318334Speter
3064169689Skan	      op1 = expand_binop (imode, and_optab,
3065169689Skan				  operand_subword_force (op1, i, mode),
3066169689Skan				  immed_double_const (lo, hi, imode),
3067169689Skan				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
3068169689Skan
3069169689Skan	      temp = expand_binop (imode, ior_optab, op0_piece, op1,
3070169689Skan				   targ_piece, 1, OPTAB_LIB_WIDEN);
3071169689Skan	      if (temp != targ_piece)
3072169689Skan		emit_move_insn (targ_piece, temp);
307318334Speter	    }
307418334Speter	  else
3075169689Skan	    emit_move_insn (targ_piece, op0_piece);
307618334Speter	}
3077169689Skan
3078169689Skan      insns = get_insns ();
3079169689Skan      end_sequence ();
3080169689Skan
3081169689Skan      emit_no_conflict_block (insns, target, op0, op1, NULL_RTX);
308218334Speter    }
3083169689Skan  else
308418334Speter    {
3085169689Skan      op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
3086169689Skan		          immed_double_const (lo, hi, imode),
3087169689Skan		          NULL_RTX, 1, OPTAB_LIB_WIDEN);
308818334Speter
3089169689Skan      op0 = gen_lowpart (imode, op0);
3090169689Skan      if (!op0_is_abs)
3091169689Skan	op0 = expand_binop (imode, and_optab, op0,
3092169689Skan			    immed_double_const (~lo, ~hi, imode),
3093169689Skan			    NULL_RTX, 1, OPTAB_LIB_WIDEN);
309418334Speter
3095169689Skan      temp = expand_binop (imode, ior_optab, op0, op1,
3096169689Skan			   gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
3097169689Skan      target = lowpart_subreg_maybe_copy (mode, temp, imode);
3098169689Skan    }
309918334Speter
3100169689Skan  return target;
3101169689Skan}
310218334Speter
3103169689Skan/* Expand the C99 copysign operation.  OP0 and OP1 must be the same
3104169689Skan   scalar floating point mode.  Return NULL if we do not know how to
3105169689Skan   expand the operation inline.  */
310618334Speter
3107169689Skanrtx
3108169689Skanexpand_copysign (rtx op0, rtx op1, rtx target)
3109169689Skan{
3110169689Skan  enum machine_mode mode = GET_MODE (op0);
3111169689Skan  const struct real_format *fmt;
3112169689Skan  bool op0_is_abs;
3113169689Skan  rtx temp;
311418334Speter
3115169689Skan  gcc_assert (SCALAR_FLOAT_MODE_P (mode));
3116169689Skan  gcc_assert (GET_MODE (op1) == mode);
311718334Speter
3118169689Skan  /* First try to do it with a special instruction.  */
3119169689Skan  temp = expand_binop (mode, copysign_optab, op0, op1,
3120169689Skan		       target, 0, OPTAB_DIRECT);
3121169689Skan  if (temp)
3122169689Skan    return temp;
312318334Speter
3124169689Skan  fmt = REAL_MODE_FORMAT (mode);
3125169689Skan  if (fmt == NULL || !fmt->has_signed_zero)
3126169689Skan    return NULL_RTX;
312718334Speter
3128169689Skan  op0_is_abs = false;
3129169689Skan  if (GET_CODE (op0) == CONST_DOUBLE)
3130169689Skan    {
3131169689Skan      if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0)))
3132169689Skan	op0 = simplify_unary_operation (ABS, mode, op0, mode);
3133169689Skan      op0_is_abs = true;
313418334Speter    }
313518334Speter
3136169689Skan  if (fmt->signbit_ro >= 0
3137169689Skan      && (GET_CODE (op0) == CONST_DOUBLE
3138169689Skan	  || (neg_optab->handlers[mode].insn_code != CODE_FOR_nothing
3139169689Skan	      && abs_optab->handlers[mode].insn_code != CODE_FOR_nothing)))
314018334Speter    {
3141169689Skan      temp = expand_copysign_absneg (mode, op0, op1, target,
3142169689Skan				     fmt->signbit_ro, op0_is_abs);
3143169689Skan      if (temp)
3144169689Skan	return temp;
314518334Speter    }
314618334Speter
3147169689Skan  if (fmt->signbit_rw < 0)
3148169689Skan    return NULL_RTX;
3149169689Skan  return expand_copysign_bit (mode, op0, op1, target,
3150169689Skan			      fmt->signbit_rw, op0_is_abs);
315118334Speter}
315218334Speter
315318334Speter/* Generate an instruction whose insn-code is INSN_CODE,
315418334Speter   with two operands: an output TARGET and an input OP0.
315518334Speter   TARGET *must* be nonzero, and the output is always stored there.
315618334Speter   CODE is an rtx code such that (CODE OP0) is an rtx that describes
315718334Speter   the value that is stored into TARGET.  */
315818334Speter
315918334Spetervoid
3160132718Skanemit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code)
316118334Speter{
316290075Sobrien  rtx temp;
316390075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
316418334Speter  rtx pat;
316518334Speter
3166169689Skan  temp = target;
316718334Speter
316818334Speter  /* Now, if insn does not accept our operands, put them into pseudos.  */
316918334Speter
3170169689Skan  if (!insn_data[icode].operand[1].predicate (op0, mode0))
317118334Speter    op0 = copy_to_mode_reg (mode0, op0);
317218334Speter
3173169689Skan  if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp)))
317418334Speter    temp = gen_reg_rtx (GET_MODE (temp));
317518334Speter
317618334Speter  pat = GEN_FCN (icode) (temp, op0);
317718334Speter
3178117395Skan  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN)
317918334Speter    add_equal_note (pat, temp, code, op0, NULL_RTX);
3180132718Skan
318118334Speter  emit_insn (pat);
318218334Speter
318318334Speter  if (temp != target)
318418334Speter    emit_move_insn (target, temp);
318518334Speter}
318618334Speter
3187169689Skanstruct no_conflict_data
3188169689Skan{
3189169689Skan  rtx target, first, insn;
3190169689Skan  bool must_stay;
3191169689Skan};
3192169689Skan
3193169689Skan/* Called via note_stores by emit_no_conflict_block and emit_libcall_block.
3194169689Skan   Set P->must_stay if the currently examined clobber / store has to stay
3195169689Skan   in the list of insns that constitute the actual no_conflict block /
3196169689Skan   libcall block.  */
3197169689Skanstatic void
3198169689Skanno_conflict_move_test (rtx dest, rtx set, void *p0)
3199169689Skan{
3200169689Skan  struct no_conflict_data *p= p0;
3201169689Skan
3202169689Skan  /* If this inns directly contributes to setting the target, it must stay.  */
3203169689Skan  if (reg_overlap_mentioned_p (p->target, dest))
3204169689Skan    p->must_stay = true;
3205169689Skan  /* If we haven't committed to keeping any other insns in the list yet,
3206169689Skan     there is nothing more to check.  */
3207169689Skan  else if (p->insn == p->first)
3208169689Skan    return;
3209169689Skan  /* If this insn sets / clobbers a register that feeds one of the insns
3210169689Skan     already in the list, this insn has to stay too.  */
3211169689Skan  else if (reg_overlap_mentioned_p (dest, PATTERN (p->first))
3212169689Skan	   || (CALL_P (p->first) && (find_reg_fusage (p->first, USE, dest)))
3213169689Skan	   || reg_used_between_p (dest, p->first, p->insn)
3214169689Skan	   /* Likewise if this insn depends on a register set by a previous
3215169689Skan	      insn in the list, or if it sets a result (presumably a hard
3216169689Skan	      register) that is set or clobbered by a previous insn.
3217169689Skan	      N.B. the modified_*_p (SET_DEST...) tests applied to a MEM
3218169689Skan	      SET_DEST perform the former check on the address, and the latter
3219169689Skan	      check on the MEM.  */
3220169689Skan	   || (GET_CODE (set) == SET
3221169689Skan	       && (modified_in_p (SET_SRC (set), p->first)
3222169689Skan		   || modified_in_p (SET_DEST (set), p->first)
3223169689Skan		   || modified_between_p (SET_SRC (set), p->first, p->insn)
3224169689Skan		   || modified_between_p (SET_DEST (set), p->first, p->insn))))
3225169689Skan    p->must_stay = true;
3226169689Skan}
3227169689Skan
3228169689Skan/* Encapsulate the block starting at FIRST and ending with LAST, which is
3229169689Skan   logically equivalent to EQUIV, so it gets manipulated as a unit if it
3230169689Skan   is possible to do so.  */
3231169689Skan
3232169689Skanstatic void
3233169689Skanmaybe_encapsulate_block (rtx first, rtx last, rtx equiv)
3234169689Skan{
3235169689Skan  if (!flag_non_call_exceptions || !may_trap_p (equiv))
3236169689Skan    {
3237169689Skan      /* We can't attach the REG_LIBCALL and REG_RETVAL notes when the
3238169689Skan	 encapsulated region would not be in one basic block, i.e. when
3239169689Skan	 there is a control_flow_insn_p insn between FIRST and LAST.  */
3240169689Skan      bool attach_libcall_retval_notes = true;
3241169689Skan      rtx insn, next = NEXT_INSN (last);
3242169689Skan
3243169689Skan      for (insn = first; insn != next; insn = NEXT_INSN (insn))
3244169689Skan	if (control_flow_insn_p (insn))
3245169689Skan	  {
3246169689Skan	    attach_libcall_retval_notes = false;
3247169689Skan	    break;
3248169689Skan	  }
3249169689Skan
3250169689Skan      if (attach_libcall_retval_notes)
3251169689Skan	{
3252169689Skan	  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
3253169689Skan						 REG_NOTES (first));
3254169689Skan	  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
3255169689Skan						REG_NOTES (last));
3256169689Skan	}
3257169689Skan    }
3258169689Skan}
3259169689Skan
326018334Speter/* Emit code to perform a series of operations on a multi-word quantity, one
326118334Speter   word at a time.
326218334Speter
326318334Speter   Such a block is preceded by a CLOBBER of the output, consists of multiple
326418334Speter   insns, each setting one word of the output, and followed by a SET copying
326518334Speter   the output to itself.
326618334Speter
326718334Speter   Each of the insns setting words of the output receives a REG_NO_CONFLICT
326818334Speter   note indicating that it doesn't conflict with the (also multi-word)
326918334Speter   inputs.  The entire block is surrounded by REG_LIBCALL and REG_RETVAL
327018334Speter   notes.
327118334Speter
327218334Speter   INSNS is a block of code generated to perform the operation, not including
327318334Speter   the CLOBBER and final copy.  All insns that compute intermediate values
3274132718Skan   are first emitted, followed by the block as described above.
327518334Speter
327618334Speter   TARGET, OP0, and OP1 are the output and inputs of the operations,
327718334Speter   respectively.  OP1 may be zero for a unary operation.
327818334Speter
3279117395Skan   EQUIV, if nonzero, is an expression to be placed into a REG_EQUAL note
328018334Speter   on the last insn.
328118334Speter
328218334Speter   If TARGET is not a register, INSNS is simply emitted with no special
328318334Speter   processing.  Likewise if anything in INSNS is not an INSN or if
328418334Speter   there is a libcall block inside INSNS.
328518334Speter
328618334Speter   The final insn emitted is returned.  */
328718334Speter
328818334Speterrtx
3289132718Skanemit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
329018334Speter{
329118334Speter  rtx prev, next, first, last, insn;
329218334Speter
3293169689Skan  if (!REG_P (target) || reload_in_progress)
3294117395Skan    return emit_insn (insns);
329518334Speter  else
329618334Speter    for (insn = insns; insn; insn = NEXT_INSN (insn))
3297169689Skan      if (!NONJUMP_INSN_P (insn)
329818334Speter	  || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
3299117395Skan	return emit_insn (insns);
330018334Speter
330118334Speter  /* First emit all insns that do not store into words of the output and remove
330218334Speter     these from the list.  */
330318334Speter  for (insn = insns; insn; insn = next)
330418334Speter    {
3305169689Skan      rtx note;
3306169689Skan      struct no_conflict_data data;
330718334Speter
330818334Speter      next = NEXT_INSN (insn);
330918334Speter
3310132718Skan      /* Some ports (cris) create a libcall regions at their own.  We must
331196263Sobrien	 avoid any potential nesting of LIBCALLs.  */
331296263Sobrien      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
331396263Sobrien	remove_note (insn, note);
331496263Sobrien      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
331596263Sobrien	remove_note (insn, note);
331696263Sobrien
3317169689Skan      data.target = target;
3318169689Skan      data.first = insns;
3319169689Skan      data.insn = insn;
3320169689Skan      data.must_stay = 0;
3321169689Skan      note_stores (PATTERN (insn), no_conflict_move_test, &data);
3322169689Skan      if (! data.must_stay)
332318334Speter	{
332418334Speter	  if (PREV_INSN (insn))
332518334Speter	    NEXT_INSN (PREV_INSN (insn)) = next;
332618334Speter	  else
332718334Speter	    insns = next;
332818334Speter
332918334Speter	  if (next)
333018334Speter	    PREV_INSN (next) = PREV_INSN (insn);
333118334Speter
333218334Speter	  add_insn (insn);
333318334Speter	}
333418334Speter    }
333518334Speter
333618334Speter  prev = get_last_insn ();
333718334Speter
333818334Speter  /* Now write the CLOBBER of the output, followed by the setting of each
333918334Speter     of the words, followed by the final copy.  */
334018334Speter  if (target != op0 && target != op1)
334150397Sobrien    emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
334218334Speter
334318334Speter  for (insn = insns; insn; insn = next)
334418334Speter    {
334518334Speter      next = NEXT_INSN (insn);
334618334Speter      add_insn (insn);
334718334Speter
3348169689Skan      if (op1 && REG_P (op1))
334950397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
335050397Sobrien					      REG_NOTES (insn));
335118334Speter
3352169689Skan      if (op0 && REG_P (op0))
335350397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
335450397Sobrien					      REG_NOTES (insn));
335518334Speter    }
335618334Speter
335718334Speter  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
335818334Speter      != CODE_FOR_nothing)
335918334Speter    {
336018334Speter      last = emit_move_insn (target, target);
336118334Speter      if (equiv)
336252284Sobrien	set_unique_reg_note (last, REG_EQUAL, equiv);
336318334Speter    }
336418334Speter  else
336590075Sobrien    {
336690075Sobrien      last = get_last_insn ();
336718334Speter
336890075Sobrien      /* Remove any existing REG_EQUAL note from "last", or else it will
336990075Sobrien	 be mistaken for a note referring to the full contents of the
337090075Sobrien	 alleged libcall value when found together with the REG_RETVAL
337190075Sobrien	 note added below.  An existing note can come from an insn
337290075Sobrien	 expansion at "last".  */
337390075Sobrien      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
337490075Sobrien    }
337590075Sobrien
337618334Speter  if (prev == 0)
337718334Speter    first = get_insns ();
337818334Speter  else
337918334Speter    first = NEXT_INSN (prev);
338018334Speter
3381169689Skan  maybe_encapsulate_block (first, last, equiv);
338218334Speter
338318334Speter  return last;
338418334Speter}
338518334Speter
338618334Speter/* Emit code to make a call to a constant function or a library call.
338718334Speter
338818334Speter   INSNS is a list containing all insns emitted in the call.
338918334Speter   These insns leave the result in RESULT.  Our block is to copy RESULT
339018334Speter   to TARGET, which is logically equivalent to EQUIV.
339118334Speter
339218334Speter   We first emit any insns that set a pseudo on the assumption that these are
339318334Speter   loading constants into registers; doing so allows them to be safely cse'ed
339418334Speter   between blocks.  Then we emit all the other insns in the block, followed by
339518334Speter   an insn to move RESULT to TARGET.  This last insn will have a REQ_EQUAL
339618334Speter   note with an operand of EQUIV.
339718334Speter
339818334Speter   Moving assignments to pseudos outside of the block is done to improve
339918334Speter   the generated code, but is not required to generate correct code,
340018334Speter   hence being unable to move an assignment is not grounds for not making
340118334Speter   a libcall block.  There are two reasons why it is safe to leave these
340218334Speter   insns inside the block: First, we know that these pseudos cannot be
340318334Speter   used in generated RTL outside the block since they are created for
340418334Speter   temporary purposes within the block.  Second, CSE will not record the
340518334Speter   values of anything set inside a libcall block, so we know they must
340618334Speter   be dead at the end of the block.
340718334Speter
340818334Speter   Except for the first group of insns (the ones setting pseudos), the
340918334Speter   block is delimited by REG_RETVAL and REG_LIBCALL notes.  */
341018334Speter
341118334Spetervoid
3412132718Skanemit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
341318334Speter{
341470635Sobrien  rtx final_dest = target;
341518334Speter  rtx prev, next, first, last, insn;
341618334Speter
341770635Sobrien  /* If this is a reg with REG_USERVAR_P set, then it could possibly turn
341870635Sobrien     into a MEM later.  Protect the libcall block from this change.  */
341970635Sobrien  if (! REG_P (target) || REG_USERVAR_P (target))
342070635Sobrien    target = gen_reg_rtx (GET_MODE (target));
3421132718Skan
342290075Sobrien  /* If we're using non-call exceptions, a libcall corresponding to an
342390075Sobrien     operation that may trap may also trap.  */
342490075Sobrien  if (flag_non_call_exceptions && may_trap_p (equiv))
342590075Sobrien    {
342690075Sobrien      for (insn = insns; insn; insn = NEXT_INSN (insn))
3427169689Skan	if (CALL_P (insn))
342890075Sobrien	  {
342990075Sobrien	    rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
3430132718Skan
343190075Sobrien	    if (note != 0 && INTVAL (XEXP (note, 0)) <= 0)
343290075Sobrien	      remove_note (insn, note);
343390075Sobrien	  }
343490075Sobrien    }
343590075Sobrien  else
343652284Sobrien  /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION
343790075Sobrien     reg note to indicate that this call cannot throw or execute a nonlocal
343890075Sobrien     goto (unless there is already a REG_EH_REGION note, in which case
343990075Sobrien     we update it).  */
344090075Sobrien    for (insn = insns; insn; insn = NEXT_INSN (insn))
3441169689Skan      if (CALL_P (insn))
344290075Sobrien	{
344390075Sobrien	  rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
3444132718Skan
344590075Sobrien	  if (note != 0)
3446169689Skan	    XEXP (note, 0) = constm1_rtx;
344790075Sobrien	  else
3448169689Skan	    REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx,
344990075Sobrien						  REG_NOTES (insn));
345090075Sobrien	}
345152284Sobrien
345218334Speter  /* First emit all insns that set pseudos.  Remove them from the list as
345318334Speter     we go.  Avoid insns that set pseudos which were referenced in previous
345418334Speter     insns.  These can be generated by move_by_pieces, for example,
345518334Speter     to update an address.  Similarly, avoid insns that reference things
345618334Speter     set in previous insns.  */
345718334Speter
345818334Speter  for (insn = insns; insn; insn = next)
345918334Speter    {
346018334Speter      rtx set = single_set (insn);
346196263Sobrien      rtx note;
346218334Speter
3463132718Skan      /* Some ports (cris) create a libcall regions at their own.  We must
346496263Sobrien	 avoid any potential nesting of LIBCALLs.  */
346596263Sobrien      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
346696263Sobrien	remove_note (insn, note);
346796263Sobrien      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
346896263Sobrien	remove_note (insn, note);
346996263Sobrien
347018334Speter      next = NEXT_INSN (insn);
347118334Speter
3472169689Skan      if (set != 0 && REG_P (SET_DEST (set))
3473169689Skan	  && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
347418334Speter	{
3475169689Skan	  struct no_conflict_data data;
347618334Speter
3477169689Skan	  data.target = const0_rtx;
3478169689Skan	  data.first = insns;
3479169689Skan	  data.insn = insn;
3480169689Skan	  data.must_stay = 0;
3481169689Skan	  note_stores (PATTERN (insn), no_conflict_move_test, &data);
3482169689Skan	  if (! data.must_stay)
3483169689Skan	    {
3484169689Skan	      if (PREV_INSN (insn))
3485169689Skan		NEXT_INSN (PREV_INSN (insn)) = next;
3486169689Skan	      else
3487169689Skan		insns = next;
348818334Speter
3489169689Skan	      if (next)
3490169689Skan		PREV_INSN (next) = PREV_INSN (insn);
3491169689Skan
3492169689Skan	      add_insn (insn);
3493169689Skan	    }
349418334Speter	}
3495132718Skan
3496132718Skan      /* Some ports use a loop to copy large arguments onto the stack.
3497132718Skan	 Don't move anything outside such a loop.  */
3498169689Skan      if (LABEL_P (insn))
3499132718Skan	break;
350018334Speter    }
350118334Speter
350218334Speter  prev = get_last_insn ();
350318334Speter
350418334Speter  /* Write the remaining insns followed by the final copy.  */
350518334Speter
350618334Speter  for (insn = insns; insn; insn = next)
350718334Speter    {
350818334Speter      next = NEXT_INSN (insn);
350918334Speter
351018334Speter      add_insn (insn);
351118334Speter    }
351218334Speter
351318334Speter  last = emit_move_insn (target, result);
351450397Sobrien  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
351550397Sobrien      != CODE_FOR_nothing)
351652284Sobrien    set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
351790075Sobrien  else
351890075Sobrien    {
351990075Sobrien      /* Remove any existing REG_EQUAL note from "last", or else it will
352090075Sobrien	 be mistaken for a note referring to the full contents of the
352190075Sobrien	 libcall value when found together with the REG_RETVAL note added
352290075Sobrien	 below.  An existing note can come from an insn expansion at
352390075Sobrien	 "last".  */
352490075Sobrien      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
352590075Sobrien    }
352618334Speter
352770635Sobrien  if (final_dest != target)
352870635Sobrien    emit_move_insn (final_dest, target);
352970635Sobrien
353018334Speter  if (prev == 0)
353118334Speter    first = get_insns ();
353218334Speter  else
353318334Speter    first = NEXT_INSN (prev);
353418334Speter
3535169689Skan  maybe_encapsulate_block (first, last, equiv);
353618334Speter}
353718334Speter
353890075Sobrien/* Nonzero if we can perform a comparison of mode MODE straightforwardly.
353990075Sobrien   PURPOSE describes how this comparison will be used.  CODE is the rtx
354090075Sobrien   comparison code we will be using.
354118334Speter
354290075Sobrien   ??? Actually, CODE is slightly weaker than that.  A target is still
3543132718Skan   required to implement all of the normal bcc operations, but not
354490075Sobrien   required to implement all (or any) of the unordered bcc operations.  */
3545132718Skan
354690075Sobrienint
3547132718Skancan_compare_p (enum rtx_code code, enum machine_mode mode,
3548132718Skan	       enum can_compare_purpose purpose)
354990075Sobrien{
355090075Sobrien  do
355190075Sobrien    {
3552117395Skan      if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
355390075Sobrien	{
355490075Sobrien	  if (purpose == ccp_jump)
3555117395Skan	    return bcc_gen_fctn[(int) code] != NULL;
355690075Sobrien	  else if (purpose == ccp_store_flag)
3557117395Skan	    return setcc_gen_code[(int) code] != CODE_FOR_nothing;
355890075Sobrien	  else
355990075Sobrien	    /* There's only one cmov entry point, and it's allowed to fail.  */
356090075Sobrien	    return 1;
356190075Sobrien	}
356290075Sobrien      if (purpose == ccp_jump
3563117395Skan	  && cbranch_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
356490075Sobrien	return 1;
356590075Sobrien      if (purpose == ccp_cmov
3566117395Skan	  && cmov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
356790075Sobrien	return 1;
356890075Sobrien      if (purpose == ccp_store_flag
3569117395Skan	  && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
357090075Sobrien	return 1;
357190075Sobrien      mode = GET_MODE_WIDER_MODE (mode);
357290075Sobrien    }
357390075Sobrien  while (mode != VOIDmode);
357490075Sobrien
357590075Sobrien  return 0;
357690075Sobrien}
357790075Sobrien
357890075Sobrien/* This function is called when we are going to emit a compare instruction that
357990075Sobrien   compares the values found in *PX and *PY, using the rtl operator COMPARISON.
358090075Sobrien
358190075Sobrien   *PMODE is the mode of the inputs (in case they are const_int).
358290075Sobrien   *PUNSIGNEDP nonzero says that the operands are unsigned;
358318334Speter   this matters if they need to be widened.
358418334Speter
358590075Sobrien   If they have mode BLKmode, then SIZE specifies the size of both operands.
358618334Speter
358790075Sobrien   This function performs all the setup necessary so that the caller only has
358890075Sobrien   to emit a single comparison insn.  This setup can involve doing a BLKmode
358990075Sobrien   comparison or emitting a library call to perform the comparison if no insn
359090075Sobrien   is available to handle it.
359190075Sobrien   The values which are passed in through pointers can be modified; the caller
3592169689Skan   should perform the comparison on the modified values.  Constant
3593169689Skan   comparisons must have already been folded.  */
359418334Speter
359590075Sobrienstatic void
3596132718Skanprepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
3597132718Skan		  enum machine_mode *pmode, int *punsignedp,
3598132718Skan		  enum can_compare_purpose purpose)
359918334Speter{
360090075Sobrien  enum machine_mode mode = *pmode;
360190075Sobrien  rtx x = *px, y = *py;
360290075Sobrien  int unsignedp = *punsignedp;
360318334Speter
3604169689Skan  /* If we are inside an appropriately-short loop and we are optimizing,
3605169689Skan     force expensive constants into a register.  */
3606169689Skan  if (CONSTANT_P (x) && optimize
360790075Sobrien      && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1))
360818334Speter    x = force_reg (mode, x);
360918334Speter
3610169689Skan  if (CONSTANT_P (y) && optimize
361190075Sobrien      && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1))
361218334Speter    y = force_reg (mode, y);
361318334Speter
361452284Sobrien#ifdef HAVE_cc0
3615169689Skan  /* Make sure if we have a canonical comparison.  The RTL
3616169689Skan     documentation states that canonical comparisons are required only
3617169689Skan     for targets which have cc0.  */
3618169689Skan  gcc_assert (!CONSTANT_P (x) || CONSTANT_P (y));
361952284Sobrien#endif
362052284Sobrien
362118334Speter  /* Don't let both operands fail to indicate the mode.  */
362218334Speter  if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode)
362318334Speter    x = force_reg (mode, x);
362418334Speter
362518334Speter  /* Handle all BLKmode compares.  */
362618334Speter
362718334Speter  if (mode == BLKmode)
362818334Speter    {
3629132718Skan      enum machine_mode cmp_mode, result_mode;
3630132718Skan      enum insn_code cmp_code;
3631132718Skan      tree length_type;
3632132718Skan      rtx libfunc;
363390075Sobrien      rtx result;
3634132718Skan      rtx opalign
363590075Sobrien	= GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
363690075Sobrien
3637169689Skan      gcc_assert (size);
3638132718Skan
3639132718Skan      /* Try to use a memory block compare insn - either cmpstr
3640132718Skan	 or cmpmem will do.  */
3641132718Skan      for (cmp_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
3642132718Skan	   cmp_mode != VOIDmode;
3643132718Skan	   cmp_mode = GET_MODE_WIDER_MODE (cmp_mode))
364418334Speter	{
3645132718Skan	  cmp_code = cmpmem_optab[cmp_mode];
3646132718Skan	  if (cmp_code == CODE_FOR_nothing)
3647132718Skan	    cmp_code = cmpstr_optab[cmp_mode];
3648132718Skan	  if (cmp_code == CODE_FOR_nothing)
3649169689Skan	    cmp_code = cmpstrn_optab[cmp_mode];
3650169689Skan	  if (cmp_code == CODE_FOR_nothing)
3651132718Skan	    continue;
3652132718Skan
3653132718Skan	  /* Must make sure the size fits the insn's mode.  */
3654132718Skan	  if ((GET_CODE (size) == CONST_INT
3655132718Skan	       && INTVAL (size) >= (1 << GET_MODE_BITSIZE (cmp_mode)))
3656132718Skan	      || (GET_MODE_BITSIZE (GET_MODE (size))
3657132718Skan		  > GET_MODE_BITSIZE (cmp_mode)))
3658132718Skan	    continue;
3659132718Skan
3660132718Skan	  result_mode = insn_data[cmp_code].operand[0].mode;
366190075Sobrien	  result = gen_reg_rtx (result_mode);
3662132718Skan	  size = convert_to_mode (cmp_mode, size, 1);
3663132718Skan	  emit_insn (GEN_FCN (cmp_code) (result, x, y, size, opalign));
3664132718Skan
3665132718Skan	  *px = result;
3666132718Skan	  *py = const0_rtx;
3667132718Skan	  *pmode = result_mode;
3668132718Skan	  return;
366918334Speter	}
3670132718Skan
3671169689Skan      /* Otherwise call a library function, memcmp.  */
3672132718Skan      libfunc = memcmp_libfunc;
3673132718Skan      length_type = sizetype;
3674132718Skan      result_mode = TYPE_MODE (integer_type_node);
3675132718Skan      cmp_mode = TYPE_MODE (length_type);
3676132718Skan      size = convert_to_mode (TYPE_MODE (length_type), size,
3677169689Skan			      TYPE_UNSIGNED (length_type));
367850397Sobrien
3679132718Skan      result = emit_library_call_value (libfunc, 0, LCT_PURE_MAKE_BLOCK,
3680132718Skan					result_mode, 3,
3681132718Skan					XEXP (x, 0), Pmode,
3682132718Skan					XEXP (y, 0), Pmode,
3683132718Skan					size, cmp_mode);
368490075Sobrien      *px = result;
368590075Sobrien      *py = const0_rtx;
368690075Sobrien      *pmode = result_mode;
368718334Speter      return;
368818334Speter    }
368918334Speter
3690132718Skan  /* Don't allow operands to the compare to trap, as that can put the
3691132718Skan     compare and branch in different basic blocks.  */
3692132718Skan  if (flag_non_call_exceptions)
3693132718Skan    {
3694132718Skan      if (may_trap_p (x))
3695132718Skan	x = force_reg (mode, x);
3696132718Skan      if (may_trap_p (y))
3697132718Skan	y = force_reg (mode, y);
3698132718Skan    }
3699132718Skan
370090075Sobrien  *px = x;
370190075Sobrien  *py = y;
370290075Sobrien  if (can_compare_p (*pcomparison, mode, purpose))
370390075Sobrien    return;
370418334Speter
370518334Speter  /* Handle a lib call just for the mode we are using.  */
370618334Speter
3707169689Skan  if (cmp_optab->handlers[(int) mode].libfunc && !SCALAR_FLOAT_MODE_P (mode))
370818334Speter    {
370918334Speter      rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
371050397Sobrien      rtx result;
371150397Sobrien
371218334Speter      /* If we want unsigned, and this mode has a distinct unsigned
371318334Speter	 comparison routine, use that.  */
371418334Speter      if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
371518334Speter	libfunc = ucmp_optab->handlers[(int) mode].libfunc;
371618334Speter
3717117395Skan      result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
3718117395Skan					word_mode, 2, x, mode, y, mode);
371918334Speter
3720169689Skan      /* There are two kinds of comparison routines. Biased routines
3721169689Skan	 return 0/1/2, and unbiased routines return -1/0/1. Other parts
3722169689Skan	 of gcc expect that the comparison operation is equivalent
3723169689Skan	 to the modified comparison. For signed comparisons compare the
3724169689Skan	 result against 1 in the biased case, and zero in the unbiased
3725169689Skan	 case. For unsigned comparisons always compare against 1 after
3726169689Skan	 biasing the unbiased result by adding 1. This gives us a way to
3727169689Skan	 represent LTU. */
372890075Sobrien      *px = result;
3729169689Skan      *pmode = word_mode;
373090075Sobrien      *py = const1_rtx;
3731169689Skan
3732169689Skan      if (!TARGET_LIB_INT_CMP_BIASED)
3733169689Skan	{
3734169689Skan	  if (*punsignedp)
3735169689Skan	    *px = plus_constant (result, 1);
3736169689Skan	  else
3737169689Skan	    *py = const0_rtx;
3738169689Skan	}
373918334Speter      return;
374018334Speter    }
374118334Speter
3742169689Skan  gcc_assert (SCALAR_FLOAT_MODE_P (mode));
3743169689Skan  prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
374418334Speter}
374518334Speter
374690075Sobrien/* Before emitting an insn with code ICODE, make sure that X, which is going
374790075Sobrien   to be used for operand OPNUM of the insn, is converted from mode MODE to
374890075Sobrien   WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and
374990075Sobrien   that it is accepted by the operand predicate.  Return the new value.  */
375090075Sobrien
3751169689Skanstatic rtx
3752132718Skanprepare_operand (int icode, rtx x, int opnum, enum machine_mode mode,
3753132718Skan		 enum machine_mode wider_mode, int unsignedp)
375490075Sobrien{
375590075Sobrien  if (mode != wider_mode)
375690075Sobrien    x = convert_modes (wider_mode, mode, x, unsignedp);
375790075Sobrien
3758169689Skan  if (!insn_data[icode].operand[opnum].predicate
375990075Sobrien      (x, insn_data[icode].operand[opnum].mode))
3760119256Skan    {
3761119256Skan      if (no_new_pseudos)
3762119256Skan	return NULL_RTX;
3763119256Skan      x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
3764119256Skan    }
3765119256Skan
376690075Sobrien  return x;
376790075Sobrien}
376890075Sobrien
376990075Sobrien/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
377090075Sobrien   we can do the comparison.
377190075Sobrien   The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
377290075Sobrien   be NULL_RTX which indicates that only a comparison is to be generated.  */
377390075Sobrien
377490075Sobrienstatic void
3775132718Skanemit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
3776132718Skan			  enum rtx_code comparison, int unsignedp, rtx label)
377790075Sobrien{
377890075Sobrien  rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
377990075Sobrien  enum mode_class class = GET_MODE_CLASS (mode);
378090075Sobrien  enum machine_mode wider_mode = mode;
378190075Sobrien
378290075Sobrien  /* Try combined insns first.  */
378390075Sobrien  do
378490075Sobrien    {
378590075Sobrien      enum insn_code icode;
378690075Sobrien      PUT_MODE (test, wider_mode);
378790075Sobrien
378890075Sobrien      if (label)
3789132718Skan	{
3790117395Skan	  icode = cbranch_optab->handlers[(int) wider_mode].insn_code;
3791132718Skan
379290075Sobrien	  if (icode != CODE_FOR_nothing
3793169689Skan	      && insn_data[icode].operand[0].predicate (test, wider_mode))
379490075Sobrien	    {
379590075Sobrien	      x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
379690075Sobrien	      y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
379790075Sobrien	      emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
379890075Sobrien	      return;
379990075Sobrien	    }
380090075Sobrien	}
380190075Sobrien
380290075Sobrien      /* Handle some compares against zero.  */
380390075Sobrien      icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
380490075Sobrien      if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
380590075Sobrien	{
380690075Sobrien	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
380790075Sobrien	  emit_insn (GEN_FCN (icode) (x));
380890075Sobrien	  if (label)
3809169689Skan	    emit_jump_insn (bcc_gen_fctn[(int) comparison] (label));
381090075Sobrien	  return;
381190075Sobrien	}
381290075Sobrien
381390075Sobrien      /* Handle compares for which there is a directly suitable insn.  */
381490075Sobrien
381590075Sobrien      icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code;
381690075Sobrien      if (icode != CODE_FOR_nothing)
381790075Sobrien	{
381890075Sobrien	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
381990075Sobrien	  y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp);
382090075Sobrien	  emit_insn (GEN_FCN (icode) (x, y));
382190075Sobrien	  if (label)
3822169689Skan	    emit_jump_insn (bcc_gen_fctn[(int) comparison] (label));
382390075Sobrien	  return;
382490075Sobrien	}
382590075Sobrien
3826169689Skan      if (!CLASS_HAS_WIDER_MODES_P (class))
382790075Sobrien	break;
382890075Sobrien
382990075Sobrien      wider_mode = GET_MODE_WIDER_MODE (wider_mode);
3830117395Skan    }
3831117395Skan  while (wider_mode != VOIDmode);
383290075Sobrien
3833169689Skan  gcc_unreachable ();
383490075Sobrien}
383590075Sobrien
383652284Sobrien/* Generate code to compare X with Y so that the condition codes are
383752284Sobrien   set and to jump to LABEL if the condition is true.  If X is a
383852284Sobrien   constant and Y is not a constant, then the comparison is swapped to
383952284Sobrien   ensure that the comparison RTL has the canonical form.
384052284Sobrien
384152284Sobrien   UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they
384252284Sobrien   need to be widened by emit_cmp_insn.  UNSIGNEDP is also used to select
384352284Sobrien   the proper branch condition code.
384452284Sobrien
384590075Sobrien   If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y.
384652284Sobrien
384752284Sobrien   MODE is the mode of the inputs (in case they are const_int).
384852284Sobrien
384952284Sobrien   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  It will
385052284Sobrien   be passed unchanged to emit_cmp_insn, then potentially converted into an
385152284Sobrien   unsigned variant based on UNSIGNEDP to select a proper jump instruction.  */
385252284Sobrien
385352284Sobrienvoid
3854132718Skanemit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
3855132718Skan			 enum machine_mode mode, int unsignedp, rtx label)
385652284Sobrien{
385790075Sobrien  rtx op0 = x, op1 = y;
385890075Sobrien
385990075Sobrien  /* Swap operands and condition to ensure canonical RTL.  */
386090075Sobrien  if (swap_commutative_operands_p (x, y))
386152284Sobrien    {
386290075Sobrien      /* If we're not emitting a branch, this means some caller
386390075Sobrien         is out of sync.  */
3864169689Skan      gcc_assert (label);
386590075Sobrien
386690075Sobrien      op0 = y, op1 = x;
386752284Sobrien      comparison = swap_condition (comparison);
386852284Sobrien    }
386952284Sobrien
387052284Sobrien#ifdef HAVE_cc0
3871169689Skan  /* If OP0 is still a constant, then both X and Y must be constants.
3872169689Skan     Force X into a register to create canonical RTL.  */
387352284Sobrien  if (CONSTANT_P (op0))
387452284Sobrien    op0 = force_reg (mode, op0);
387552284Sobrien#endif
387652284Sobrien
387752284Sobrien  if (unsignedp)
387852284Sobrien    comparison = unsigned_condition (comparison);
387990075Sobrien
388090075Sobrien  prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp,
388190075Sobrien		    ccp_jump);
388290075Sobrien  emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
388352284Sobrien}
388452284Sobrien
388590075Sobrien/* Like emit_cmp_and_jump_insns, but generate only the comparison.  */
388652284Sobrien
388790075Sobrienvoid
3888132718Skanemit_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
3889132718Skan	       enum machine_mode mode, int unsignedp)
389018334Speter{
389190075Sobrien  emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0);
389218334Speter}
389318334Speter
389418334Speter/* Emit a library call comparison between floating point X and Y.
389518334Speter   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
389618334Speter
389790075Sobrienstatic void
3898132718Skanprepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
3899132718Skan		       enum machine_mode *pmode, int *punsignedp)
390018334Speter{
390190075Sobrien  enum rtx_code comparison = *pcomparison;
3902132718Skan  enum rtx_code swapped = swap_condition (comparison);
3903169689Skan  enum rtx_code reversed = reverse_condition_maybe_unordered (comparison);
3904169689Skan  rtx x = *px;
3905169689Skan  rtx y = *py;
3906132718Skan  enum machine_mode orig_mode = GET_MODE (x);
3907132718Skan  enum machine_mode mode;
3908132718Skan  rtx value, target, insns, equiv;
390918334Speter  rtx libfunc = 0;
3910169689Skan  bool reversed_p = false;
391118334Speter
3912169689Skan  for (mode = orig_mode;
3913169689Skan       mode != VOIDmode;
3914169689Skan       mode = GET_MODE_WIDER_MODE (mode))
3915132718Skan    {
3916132718Skan      if ((libfunc = code_to_optab[comparison]->handlers[mode].libfunc))
391718334Speter	break;
391818334Speter
3919132718Skan      if ((libfunc = code_to_optab[swapped]->handlers[mode].libfunc))
3920132718Skan	{
3921132718Skan	  rtx tmp;
3922132718Skan	  tmp = x; x = y; y = tmp;
3923132718Skan	  comparison = swapped;
3924132718Skan	  break;
3925132718Skan	}
3926169689Skan
3927169689Skan      if ((libfunc = code_to_optab[reversed]->handlers[mode].libfunc)
3928169689Skan	  && FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, reversed))
3929169689Skan	{
3930169689Skan	  comparison = reversed;
3931169689Skan	  reversed_p = true;
3932169689Skan	  break;
3933169689Skan	}
3934132718Skan    }
393518334Speter
3936169689Skan  gcc_assert (mode != VOIDmode);
393718334Speter
3938132718Skan  if (mode != orig_mode)
3939132718Skan    {
3940132718Skan      x = convert_to_mode (mode, x, 0);
3941132718Skan      y = convert_to_mode (mode, y, 0);
3942132718Skan    }
394318334Speter
3944132718Skan  /* Attach a REG_EQUAL note describing the semantics of the libcall to
3945132718Skan     the RTL.  The allows the RTL optimizers to delete the libcall if the
3946132718Skan     condition can be determined at compile-time.  */
3947132718Skan  if (comparison == UNORDERED)
3948132718Skan    {
3949132718Skan      rtx temp = simplify_gen_relational (NE, word_mode, mode, x, x);
3950132718Skan      equiv = simplify_gen_relational (NE, word_mode, mode, y, y);
3951132718Skan      equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
3952132718Skan				    temp, const_true_rtx, equiv);
3953132718Skan    }
3954132718Skan  else
3955132718Skan    {
3956132718Skan      equiv = simplify_gen_relational (comparison, word_mode, mode, x, y);
3957132718Skan      if (! FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
3958132718Skan	{
3959132718Skan	  rtx true_rtx, false_rtx;
396018334Speter
3961132718Skan	  switch (comparison)
3962132718Skan	    {
3963132718Skan	    case EQ:
3964132718Skan	      true_rtx = const0_rtx;
3965132718Skan	      false_rtx = const_true_rtx;
3966132718Skan	      break;
396750397Sobrien
3968132718Skan	    case NE:
3969132718Skan	      true_rtx = const_true_rtx;
3970132718Skan	      false_rtx = const0_rtx;
3971132718Skan	      break;
397290075Sobrien
3973132718Skan	    case GT:
3974132718Skan	      true_rtx = const1_rtx;
3975132718Skan	      false_rtx = const0_rtx;
3976132718Skan	      break;
397718334Speter
3978132718Skan	    case GE:
3979132718Skan	      true_rtx = const0_rtx;
3980132718Skan	      false_rtx = constm1_rtx;
3981132718Skan	      break;
398218334Speter
3983132718Skan	    case LT:
3984132718Skan	      true_rtx = constm1_rtx;
3985132718Skan	      false_rtx = const0_rtx;
3986132718Skan	      break;
398718334Speter
3988132718Skan	    case LE:
3989132718Skan	      true_rtx = const0_rtx;
3990132718Skan	      false_rtx = const1_rtx;
3991132718Skan	      break;
399218334Speter
3993132718Skan	    default:
3994169689Skan	      gcc_unreachable ();
3995132718Skan	    }
3996132718Skan	  equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
3997132718Skan					equiv, true_rtx, false_rtx);
3998132718Skan	}
3999132718Skan    }
400018334Speter
4001132718Skan  start_sequence ();
4002132718Skan  value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
4003132718Skan				   word_mode, 2, x, mode, y, mode);
4004132718Skan  insns = get_insns ();
4005132718Skan  end_sequence ();
400650397Sobrien
4007132718Skan  target = gen_reg_rtx (word_mode);
4008132718Skan  emit_libcall_block (insns, target, value, equiv);
400990075Sobrien
4010132718Skan  if (comparison == UNORDERED
4011132718Skan      || FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
4012169689Skan    comparison = reversed_p ? EQ : NE;
401318334Speter
4014132718Skan  *px = target;
401590075Sobrien  *py = const0_rtx;
401690075Sobrien  *pmode = word_mode;
4017132718Skan  *pcomparison = comparison;
401890075Sobrien  *punsignedp = 0;
401918334Speter}
402018334Speter
402118334Speter/* Generate code to indirectly jump to a location given in the rtx LOC.  */
402218334Speter
402318334Spetervoid
4024132718Skanemit_indirect_jump (rtx loc)
402518334Speter{
4026169689Skan  if (!insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate
4027169689Skan      (loc, Pmode))
402818334Speter    loc = copy_to_mode_reg (Pmode, loc);
402918334Speter
403018334Speter  emit_jump_insn (gen_indirect_jump (loc));
403118334Speter  emit_barrier ();
403218334Speter}
403318334Speter
403418334Speter#ifdef HAVE_conditional_move
403518334Speter
403618334Speter/* Emit a conditional move instruction if the machine supports one for that
403718334Speter   condition and machine mode.
403818334Speter
403918334Speter   OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
404018334Speter   the mode to use should they be constants.  If it is VOIDmode, they cannot
404118334Speter   both be constants.
404218334Speter
404318334Speter   OP2 should be stored in TARGET if the comparison is true, otherwise OP3
404418334Speter   should be stored there.  MODE is the mode to use should they be constants.
404518334Speter   If it is VOIDmode, they cannot both be constants.
404618334Speter
404718334Speter   The result is either TARGET (perhaps modified) or NULL_RTX if the operation
404818334Speter   is not supported.  */
404918334Speter
405018334Speterrtx
4051132718Skanemit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
4052132718Skan		       enum machine_mode cmode, rtx op2, rtx op3,
4053132718Skan		       enum machine_mode mode, int unsignedp)
405418334Speter{
405518334Speter  rtx tem, subtarget, comparison, insn;
405618334Speter  enum insn_code icode;
405790075Sobrien  enum rtx_code reversed;
405818334Speter
405918334Speter  /* If one operand is constant, make it the second one.  Only do this
406018334Speter     if the other operand is not constant as well.  */
406118334Speter
406290075Sobrien  if (swap_commutative_operands_p (op0, op1))
406318334Speter    {
406418334Speter      tem = op0;
406518334Speter      op0 = op1;
406618334Speter      op1 = tem;
406718334Speter      code = swap_condition (code);
406818334Speter    }
406918334Speter
407090075Sobrien  /* get_condition will prefer to generate LT and GT even if the old
407190075Sobrien     comparison was against zero, so undo that canonicalization here since
407290075Sobrien     comparisons against zero are cheaper.  */
4073132718Skan  if (code == LT && op1 == const1_rtx)
407490075Sobrien    code = LE, op1 = const0_rtx;
4075132718Skan  else if (code == GT && op1 == constm1_rtx)
407690075Sobrien    code = GE, op1 = const0_rtx;
407790075Sobrien
407818334Speter  if (cmode == VOIDmode)
407918334Speter    cmode = GET_MODE (op0);
408018334Speter
408190075Sobrien  if (swap_commutative_operands_p (op2, op3)
408290075Sobrien      && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
408390075Sobrien          != UNKNOWN))
408418334Speter    {
408518334Speter      tem = op2;
408618334Speter      op2 = op3;
408718334Speter      op3 = tem;
408890075Sobrien      code = reversed;
408918334Speter    }
409018334Speter
409118334Speter  if (mode == VOIDmode)
409218334Speter    mode = GET_MODE (op2);
409318334Speter
409418334Speter  icode = movcc_gen_code[mode];
409518334Speter
409618334Speter  if (icode == CODE_FOR_nothing)
409718334Speter    return 0;
409818334Speter
4099169689Skan  if (!target)
410018334Speter    target = gen_reg_rtx (mode);
410118334Speter
410218334Speter  subtarget = target;
410318334Speter
410418334Speter  /* If the insn doesn't accept these operands, put them in pseudos.  */
410518334Speter
4106169689Skan  if (!insn_data[icode].operand[0].predicate
410790075Sobrien      (subtarget, insn_data[icode].operand[0].mode))
410890075Sobrien    subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
410918334Speter
4110169689Skan  if (!insn_data[icode].operand[2].predicate
411190075Sobrien      (op2, insn_data[icode].operand[2].mode))
411290075Sobrien    op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
411318334Speter
4114169689Skan  if (!insn_data[icode].operand[3].predicate
411590075Sobrien      (op3, insn_data[icode].operand[3].mode))
411690075Sobrien    op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
411718334Speter
411818334Speter  /* Everything should now be in the suitable form, so emit the compare insn
411918334Speter     and then the conditional move.  */
412018334Speter
4121132718Skan  comparison
412290075Sobrien    = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
412318334Speter
412418334Speter  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
412590075Sobrien  /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
412690075Sobrien     return NULL and let the caller figure out how best to deal with this
412790075Sobrien     situation.  */
412818334Speter  if (GET_CODE (comparison) != code)
412990075Sobrien    return NULL_RTX;
4130132718Skan
413118334Speter  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
413218334Speter
413318334Speter  /* If that failed, then give up.  */
413418334Speter  if (insn == 0)
413518334Speter    return 0;
413618334Speter
413718334Speter  emit_insn (insn);
413818334Speter
413918334Speter  if (subtarget != target)
414018334Speter    convert_move (target, subtarget, 0);
414118334Speter
414218334Speter  return target;
414318334Speter}
414418334Speter
4145117395Skan/* Return nonzero if a conditional move of mode MODE is supported.
414618334Speter
414718334Speter   This function is for combine so it can tell whether an insn that looks
414818334Speter   like a conditional move is actually supported by the hardware.  If we
414918334Speter   guess wrong we lose a bit on optimization, but that's it.  */
415018334Speter/* ??? sparc64 supports conditionally moving integers values based on fp
415118334Speter   comparisons, and vice versa.  How do we handle them?  */
415218334Speter
415318334Speterint
4154132718Skancan_conditionally_move_p (enum machine_mode mode)
415518334Speter{
415618334Speter  if (movcc_gen_code[mode] != CODE_FOR_nothing)
415718334Speter    return 1;
415818334Speter
415918334Speter  return 0;
416018334Speter}
416118334Speter
416218334Speter#endif /* HAVE_conditional_move */
4163132718Skan
4164132718Skan/* Emit a conditional addition instruction if the machine supports one for that
4165132718Skan   condition and machine mode.
4166132718Skan
4167132718Skan   OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
4168132718Skan   the mode to use should they be constants.  If it is VOIDmode, they cannot
4169132718Skan   both be constants.
4170132718Skan
4171132718Skan   OP2 should be stored in TARGET if the comparison is true, otherwise OP2+OP3
4172132718Skan   should be stored there.  MODE is the mode to use should they be constants.
4173132718Skan   If it is VOIDmode, they cannot both be constants.
4174132718Skan
4175132718Skan   The result is either TARGET (perhaps modified) or NULL_RTX if the operation
4176132718Skan   is not supported.  */
4177132718Skan
4178132718Skanrtx
4179132718Skanemit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
4180132718Skan		      enum machine_mode cmode, rtx op2, rtx op3,
4181132718Skan		      enum machine_mode mode, int unsignedp)
4182132718Skan{
4183132718Skan  rtx tem, subtarget, comparison, insn;
4184132718Skan  enum insn_code icode;
4185132718Skan  enum rtx_code reversed;
4186132718Skan
4187132718Skan  /* If one operand is constant, make it the second one.  Only do this
4188132718Skan     if the other operand is not constant as well.  */
4189132718Skan
4190132718Skan  if (swap_commutative_operands_p (op0, op1))
4191132718Skan    {
4192132718Skan      tem = op0;
4193132718Skan      op0 = op1;
4194132718Skan      op1 = tem;
4195132718Skan      code = swap_condition (code);
4196132718Skan    }
4197132718Skan
4198132718Skan  /* get_condition will prefer to generate LT and GT even if the old
4199132718Skan     comparison was against zero, so undo that canonicalization here since
4200132718Skan     comparisons against zero are cheaper.  */
4201132718Skan  if (code == LT && op1 == const1_rtx)
4202132718Skan    code = LE, op1 = const0_rtx;
4203132718Skan  else if (code == GT && op1 == constm1_rtx)
4204132718Skan    code = GE, op1 = const0_rtx;
4205132718Skan
4206132718Skan  if (cmode == VOIDmode)
4207132718Skan    cmode = GET_MODE (op0);
4208132718Skan
4209132718Skan  if (swap_commutative_operands_p (op2, op3)
4210132718Skan      && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
4211132718Skan          != UNKNOWN))
4212132718Skan    {
4213132718Skan      tem = op2;
4214132718Skan      op2 = op3;
4215132718Skan      op3 = tem;
4216132718Skan      code = reversed;
4217132718Skan    }
4218132718Skan
4219132718Skan  if (mode == VOIDmode)
4220132718Skan    mode = GET_MODE (op2);
4221132718Skan
4222132718Skan  icode = addcc_optab->handlers[(int) mode].insn_code;
4223132718Skan
4224132718Skan  if (icode == CODE_FOR_nothing)
4225132718Skan    return 0;
4226132718Skan
4227169689Skan  if (!target)
4228132718Skan    target = gen_reg_rtx (mode);
4229132718Skan
4230132718Skan  /* If the insn doesn't accept these operands, put them in pseudos.  */
4231132718Skan
4232169689Skan  if (!insn_data[icode].operand[0].predicate
4233169689Skan      (target, insn_data[icode].operand[0].mode))
4234132718Skan    subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
4235169689Skan  else
4236169689Skan    subtarget = target;
4237132718Skan
4238169689Skan  if (!insn_data[icode].operand[2].predicate
4239132718Skan      (op2, insn_data[icode].operand[2].mode))
4240132718Skan    op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
4241132718Skan
4242169689Skan  if (!insn_data[icode].operand[3].predicate
4243132718Skan      (op3, insn_data[icode].operand[3].mode))
4244132718Skan    op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
4245132718Skan
4246132718Skan  /* Everything should now be in the suitable form, so emit the compare insn
4247132718Skan     and then the conditional move.  */
4248132718Skan
4249132718Skan  comparison
4250132718Skan    = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
4251132718Skan
4252132718Skan  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
4253132718Skan  /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
4254132718Skan     return NULL and let the caller figure out how best to deal with this
4255132718Skan     situation.  */
4256132718Skan  if (GET_CODE (comparison) != code)
4257132718Skan    return NULL_RTX;
4258132718Skan
4259132718Skan  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
4260132718Skan
4261132718Skan  /* If that failed, then give up.  */
4262132718Skan  if (insn == 0)
4263132718Skan    return 0;
4264132718Skan
4265132718Skan  emit_insn (insn);
4266132718Skan
4267132718Skan  if (subtarget != target)
4268132718Skan    convert_move (target, subtarget, 0);
4269132718Skan
4270132718Skan  return target;
4271132718Skan}
427218334Speter
4273132718Skan/* These functions attempt to generate an insn body, rather than
4274132718Skan   emitting the insn, but if the gen function already emits them, we
4275169689Skan   make no attempt to turn them back into naked patterns.  */
427618334Speter
427718334Speter/* Generate and return an insn body to add Y to X.  */
427818334Speter
427918334Speterrtx
4280132718Skangen_add2_insn (rtx x, rtx y)
428118334Speter{
4282132718Skan  int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
428318334Speter
4284169689Skan  gcc_assert (insn_data[icode].operand[0].predicate
4285169689Skan	      (x, insn_data[icode].operand[0].mode));
4286169689Skan  gcc_assert (insn_data[icode].operand[1].predicate
4287169689Skan	      (x, insn_data[icode].operand[1].mode));
4288169689Skan  gcc_assert (insn_data[icode].operand[2].predicate
4289169689Skan	      (y, insn_data[icode].operand[2].mode));
429018334Speter
4291169689Skan  return GEN_FCN (icode) (x, x, y);
429218334Speter}
429318334Speter
429490075Sobrien/* Generate and return an insn body to add r1 and c,
429590075Sobrien   storing the result in r0.  */
429690075Sobrienrtx
4297132718Skangen_add3_insn (rtx r0, rtx r1, rtx c)
429890075Sobrien{
429990075Sobrien  int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
430090075Sobrien
4301117395Skan  if (icode == CODE_FOR_nothing
4302169689Skan      || !(insn_data[icode].operand[0].predicate
4303169689Skan	   (r0, insn_data[icode].operand[0].mode))
4304169689Skan      || !(insn_data[icode].operand[1].predicate
4305169689Skan	   (r1, insn_data[icode].operand[1].mode))
4306169689Skan      || !(insn_data[icode].operand[2].predicate
4307169689Skan	   (c, insn_data[icode].operand[2].mode)))
430890075Sobrien    return NULL_RTX;
430990075Sobrien
4310169689Skan  return GEN_FCN (icode) (r0, r1, c);
431190075Sobrien}
431290075Sobrien
431318334Speterint
4314132718Skanhave_add2_insn (rtx x, rtx y)
431518334Speter{
431690075Sobrien  int icode;
431790075Sobrien
4318169689Skan  gcc_assert (GET_MODE (x) != VOIDmode);
431990075Sobrien
4320132718Skan  icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
432190075Sobrien
432290075Sobrien  if (icode == CODE_FOR_nothing)
432390075Sobrien    return 0;
432490075Sobrien
4325169689Skan  if (!(insn_data[icode].operand[0].predicate
4326169689Skan	(x, insn_data[icode].operand[0].mode))
4327169689Skan      || !(insn_data[icode].operand[1].predicate
4328169689Skan	   (x, insn_data[icode].operand[1].mode))
4329169689Skan      || !(insn_data[icode].operand[2].predicate
4330169689Skan	   (y, insn_data[icode].operand[2].mode)))
433190075Sobrien    return 0;
433290075Sobrien
433390075Sobrien  return 1;
433418334Speter}
433518334Speter
433618334Speter/* Generate and return an insn body to subtract Y from X.  */
433718334Speter
433818334Speterrtx
4339132718Skangen_sub2_insn (rtx x, rtx y)
434018334Speter{
4341132718Skan  int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
434218334Speter
4343169689Skan  gcc_assert (insn_data[icode].operand[0].predicate
4344169689Skan	      (x, insn_data[icode].operand[0].mode));
4345169689Skan  gcc_assert (insn_data[icode].operand[1].predicate
4346169689Skan	      (x, insn_data[icode].operand[1].mode));
4347169689Skan  gcc_assert  (insn_data[icode].operand[2].predicate
4348169689Skan	       (y, insn_data[icode].operand[2].mode));
434918334Speter
4350169689Skan  return GEN_FCN (icode) (x, x, y);
435118334Speter}
435218334Speter
435390075Sobrien/* Generate and return an insn body to subtract r1 and c,
435490075Sobrien   storing the result in r0.  */
435590075Sobrienrtx
4356132718Skangen_sub3_insn (rtx r0, rtx r1, rtx c)
435790075Sobrien{
435890075Sobrien  int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code;
435990075Sobrien
4360117395Skan  if (icode == CODE_FOR_nothing
4361169689Skan      || !(insn_data[icode].operand[0].predicate
4362169689Skan	   (r0, insn_data[icode].operand[0].mode))
4363169689Skan      || !(insn_data[icode].operand[1].predicate
4364169689Skan	   (r1, insn_data[icode].operand[1].mode))
4365169689Skan      || !(insn_data[icode].operand[2].predicate
4366169689Skan	   (c, insn_data[icode].operand[2].mode)))
436790075Sobrien    return NULL_RTX;
436890075Sobrien
4369169689Skan  return GEN_FCN (icode) (r0, r1, c);
437090075Sobrien}
437190075Sobrien
437218334Speterint
4373132718Skanhave_sub2_insn (rtx x, rtx y)
437418334Speter{
437590075Sobrien  int icode;
437690075Sobrien
4377169689Skan  gcc_assert (GET_MODE (x) != VOIDmode);
437890075Sobrien
4379132718Skan  icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
438090075Sobrien
438190075Sobrien  if (icode == CODE_FOR_nothing)
438290075Sobrien    return 0;
438390075Sobrien
4384169689Skan  if (!(insn_data[icode].operand[0].predicate
4385169689Skan	(x, insn_data[icode].operand[0].mode))
4386169689Skan      || !(insn_data[icode].operand[1].predicate
4387169689Skan	   (x, insn_data[icode].operand[1].mode))
4388169689Skan      || !(insn_data[icode].operand[2].predicate
4389169689Skan	   (y, insn_data[icode].operand[2].mode)))
439090075Sobrien    return 0;
439190075Sobrien
439290075Sobrien  return 1;
439318334Speter}
439418334Speter
439518334Speter/* Generate the body of an instruction to copy Y into X.
4396117395Skan   It may be a list of insns, if one insn isn't enough.  */
439718334Speter
439818334Speterrtx
4399132718Skangen_move_insn (rtx x, rtx y)
440018334Speter{
440118334Speter  rtx seq;
440218334Speter
440318334Speter  start_sequence ();
440418334Speter  emit_move_insn_1 (x, y);
4405117395Skan  seq = get_insns ();
440618334Speter  end_sequence ();
440718334Speter  return seq;
440818334Speter}
440918334Speter
441018334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE.
441118334Speter   UNSIGNEDP specifies zero-extension instead of sign-extension.  If
441218334Speter   no such operation exists, CODE_FOR_nothing will be returned.  */
441318334Speter
441418334Speterenum insn_code
4415132718Skancan_extend_p (enum machine_mode to_mode, enum machine_mode from_mode,
4416132718Skan	      int unsignedp)
441718334Speter{
4418132718Skan  convert_optab tab;
441990075Sobrien#ifdef HAVE_ptr_extend
442090075Sobrien  if (unsignedp < 0)
442190075Sobrien    return CODE_FOR_ptr_extend;
442290075Sobrien#endif
4423132718Skan
4424132718Skan  tab = unsignedp ? zext_optab : sext_optab;
4425132718Skan  return tab->handlers[to_mode][from_mode].insn_code;
442618334Speter}
442718334Speter
442818334Speter/* Generate the body of an insn to extend Y (with mode MFROM)
442918334Speter   into X (with mode MTO).  Do zero-extension if UNSIGNEDP is nonzero.  */
443018334Speter
443118334Speterrtx
4432132718Skangen_extend_insn (rtx x, rtx y, enum machine_mode mto,
4433132718Skan		 enum machine_mode mfrom, int unsignedp)
443418334Speter{
4435132718Skan  enum insn_code icode = can_extend_p (mto, mfrom, unsignedp);
4436132718Skan  return GEN_FCN (icode) (x, y);
443718334Speter}
443818334Speter
443918334Speter/* can_fix_p and can_float_p say whether the target machine
444018334Speter   can directly convert a given fixed point type to
444118334Speter   a given floating point type, or vice versa.
444218334Speter   The returned value is the CODE_FOR_... value to use,
444318334Speter   or CODE_FOR_nothing if these modes cannot be directly converted.
444418334Speter
444518334Speter   *TRUNCP_PTR is set to 1 if it is necessary to output
444618334Speter   an explicit FTRUNC insn before the fix insn; otherwise 0.  */
444718334Speter
444818334Speterstatic enum insn_code
4449132718Skancan_fix_p (enum machine_mode fixmode, enum machine_mode fltmode,
4450132718Skan	   int unsignedp, int *truncp_ptr)
445118334Speter{
4452132718Skan  convert_optab tab;
4453132718Skan  enum insn_code icode;
445418334Speter
4455132718Skan  tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
4456132718Skan  icode = tab->handlers[fixmode][fltmode].insn_code;
4457132718Skan  if (icode != CODE_FOR_nothing)
445818334Speter    {
4459132718Skan      *truncp_ptr = 0;
4460132718Skan      return icode;
4461132718Skan    }
4462132718Skan
4463169689Skan  /* FIXME: This requires a port to define both FIX and FTRUNC pattern
4464169689Skan     for this to work. We need to rework the fix* and ftrunc* patterns
4465169689Skan     and documentation.  */
4466132718Skan  tab = unsignedp ? ufix_optab : sfix_optab;
4467132718Skan  icode = tab->handlers[fixmode][fltmode].insn_code;
4468132718Skan  if (icode != CODE_FOR_nothing
4469132718Skan      && ftrunc_optab->handlers[fltmode].insn_code != CODE_FOR_nothing)
4470132718Skan    {
447118334Speter      *truncp_ptr = 1;
4472132718Skan      return icode;
447318334Speter    }
4474132718Skan
4475132718Skan  *truncp_ptr = 0;
447618334Speter  return CODE_FOR_nothing;
447718334Speter}
447818334Speter
447918334Speterstatic enum insn_code
4480132718Skancan_float_p (enum machine_mode fltmode, enum machine_mode fixmode,
4481132718Skan	     int unsignedp)
448218334Speter{
4483132718Skan  convert_optab tab;
4484132718Skan
4485132718Skan  tab = unsignedp ? ufloat_optab : sfloat_optab;
4486132718Skan  return tab->handlers[fltmode][fixmode].insn_code;
448718334Speter}
448818334Speter
448918334Speter/* Generate code to convert FROM to floating point
449018334Speter   and store in TO.  FROM must be fixed point and not VOIDmode.
449118334Speter   UNSIGNEDP nonzero means regard FROM as unsigned.
449218334Speter   Normally this is done by correcting the final value
449318334Speter   if it is negative.  */
449418334Speter
449518334Spetervoid
4496132718Skanexpand_float (rtx to, rtx from, int unsignedp)
449718334Speter{
449818334Speter  enum insn_code icode;
449990075Sobrien  rtx target = to;
450018334Speter  enum machine_mode fmode, imode;
4501169689Skan  bool can_do_signed = false;
450218334Speter
450318334Speter  /* Crash now, because we won't be able to decide which mode to use.  */
4504169689Skan  gcc_assert (GET_MODE (from) != VOIDmode);
450518334Speter
450618334Speter  /* Look for an insn to do the conversion.  Do it in the specified
450718334Speter     modes if possible; otherwise convert either input, output or both to
450818334Speter     wider mode.  If the integer mode is wider than the mode of FROM,
450918334Speter     we can do the conversion signed even if the input is unsigned.  */
451018334Speter
4511117395Skan  for (fmode = GET_MODE (to); fmode != VOIDmode;
4512117395Skan       fmode = GET_MODE_WIDER_MODE (fmode))
4513117395Skan    for (imode = GET_MODE (from); imode != VOIDmode;
4514117395Skan	 imode = GET_MODE_WIDER_MODE (imode))
451518334Speter      {
451618334Speter	int doing_unsigned = unsignedp;
451718334Speter
451890075Sobrien	if (fmode != GET_MODE (to)
451990075Sobrien	    && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from)))
452090075Sobrien	  continue;
452190075Sobrien
452218334Speter	icode = can_float_p (fmode, imode, unsignedp);
4523169689Skan	if (icode == CODE_FOR_nothing && unsignedp)
4524169689Skan	  {
4525169689Skan	    enum insn_code scode = can_float_p (fmode, imode, 0);
4526169689Skan	    if (scode != CODE_FOR_nothing)
4527169689Skan	      can_do_signed = true;
4528169689Skan	    if (imode != GET_MODE (from))
4529169689Skan	      icode = scode, doing_unsigned = 0;
4530169689Skan	  }
453118334Speter
453218334Speter	if (icode != CODE_FOR_nothing)
453318334Speter	  {
453418334Speter	    if (imode != GET_MODE (from))
453518334Speter	      from = convert_to_mode (imode, from, unsignedp);
453618334Speter
453718334Speter	    if (fmode != GET_MODE (to))
453818334Speter	      target = gen_reg_rtx (fmode);
453918334Speter
454018334Speter	    emit_unop_insn (icode, target, from,
454118334Speter			    doing_unsigned ? UNSIGNED_FLOAT : FLOAT);
454218334Speter
454318334Speter	    if (target != to)
454418334Speter	      convert_move (to, target, 0);
454518334Speter	    return;
454618334Speter	  }
4547117395Skan      }
454818334Speter
4549169689Skan  /* Unsigned integer, and no way to convert directly.  For binary
4550169689Skan     floating point modes, convert as signed, then conditionally adjust
4551169689Skan     the result.  */
4552169689Skan  if (unsignedp && can_do_signed && !DECIMAL_FLOAT_MODE_P (GET_MODE (to)))
455318334Speter    {
455418334Speter      rtx label = gen_label_rtx ();
455518334Speter      rtx temp;
455618334Speter      REAL_VALUE_TYPE offset;
455718334Speter
455818334Speter      /* Look for a usable floating mode FMODE wider than the source and at
455918334Speter	 least as wide as the target.  Using FMODE will avoid rounding woes
456018334Speter	 with unsigned values greater than the signed maximum value.  */
456118334Speter
456218334Speter      for (fmode = GET_MODE (to);  fmode != VOIDmode;
456318334Speter	   fmode = GET_MODE_WIDER_MODE (fmode))
456418334Speter	if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
456518334Speter	    && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
456618334Speter	  break;
456718334Speter
456818334Speter      if (fmode == VOIDmode)
456918334Speter	{
457018334Speter	  /* There is no such mode.  Pretend the target is wide enough.  */
457118334Speter	  fmode = GET_MODE (to);
457218334Speter
457350397Sobrien	  /* Avoid double-rounding when TO is narrower than FROM.  */
457418334Speter	  if ((significand_size (fmode) + 1)
457518334Speter	      < GET_MODE_BITSIZE (GET_MODE (from)))
457618334Speter	    {
457718334Speter	      rtx temp1;
457818334Speter	      rtx neglabel = gen_label_rtx ();
457918334Speter
4580132718Skan	      /* Don't use TARGET if it isn't a register, is a hard register,
458118334Speter		 or is the wrong mode.  */
4582169689Skan	      if (!REG_P (target)
458318334Speter		  || REGNO (target) < FIRST_PSEUDO_REGISTER
458418334Speter		  || GET_MODE (target) != fmode)
458518334Speter		target = gen_reg_rtx (fmode);
458618334Speter
458718334Speter	      imode = GET_MODE (from);
458818334Speter	      do_pending_stack_adjust ();
458918334Speter
459018334Speter	      /* Test whether the sign bit is set.  */
459190075Sobrien	      emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode,
459290075Sobrien				       0, neglabel);
459318334Speter
459418334Speter	      /* The sign bit is not set.  Convert as signed.  */
459518334Speter	      expand_float (target, from, 0);
459618334Speter	      emit_jump_insn (gen_jump (label));
459718334Speter	      emit_barrier ();
459818334Speter
459918334Speter	      /* The sign bit is set.
460018334Speter		 Convert to a usable (positive signed) value by shifting right
460118334Speter		 one bit, while remembering if a nonzero bit was shifted
460218334Speter		 out; i.e., compute  (from & 1) | (from >> 1).  */
460318334Speter
460418334Speter	      emit_label (neglabel);
460518334Speter	      temp = expand_binop (imode, and_optab, from, const1_rtx,
460618334Speter				   NULL_RTX, 1, OPTAB_LIB_WIDEN);
460718334Speter	      temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
460818334Speter				    NULL_RTX, 1);
4609132718Skan	      temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
461018334Speter				   OPTAB_LIB_WIDEN);
461118334Speter	      expand_float (target, temp, 0);
461218334Speter
461318334Speter	      /* Multiply by 2 to undo the shift above.  */
461418334Speter	      temp = expand_binop (fmode, add_optab, target, target,
4615117395Skan				   target, 0, OPTAB_LIB_WIDEN);
461618334Speter	      if (temp != target)
461718334Speter		emit_move_insn (target, temp);
461818334Speter
461918334Speter	      do_pending_stack_adjust ();
462018334Speter	      emit_label (label);
462118334Speter	      goto done;
462218334Speter	    }
462318334Speter	}
462418334Speter
462518334Speter      /* If we are about to do some arithmetic to correct for an
462618334Speter	 unsigned operand, do it in a pseudo-register.  */
462718334Speter
462818334Speter      if (GET_MODE (to) != fmode
4629169689Skan	  || !REG_P (to) || REGNO (to) < FIRST_PSEUDO_REGISTER)
463018334Speter	target = gen_reg_rtx (fmode);
463118334Speter
463218334Speter      /* Convert as signed integer to floating.  */
463318334Speter      expand_float (target, from, 0);
463418334Speter
463518334Speter      /* If FROM is negative (and therefore TO is negative),
463618334Speter	 correct its value by 2**bitwidth.  */
463718334Speter
463818334Speter      do_pending_stack_adjust ();
463952284Sobrien      emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
464090075Sobrien			       0, label);
464118334Speter
4642132718Skan
4643117395Skan      real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from)));
464418334Speter      temp = expand_binop (fmode, add_optab, target,
464518334Speter			   CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
464618334Speter			   target, 0, OPTAB_LIB_WIDEN);
464718334Speter      if (temp != target)
464818334Speter	emit_move_insn (target, temp);
464918334Speter
465018334Speter      do_pending_stack_adjust ();
465118334Speter      emit_label (label);
465218334Speter      goto done;
465318334Speter    }
465418334Speter
4655132718Skan  /* No hardware instruction available; call a library routine.  */
465618334Speter    {
4657132718Skan      rtx libfunc;
465818334Speter      rtx insns;
465918334Speter      rtx value;
4660132718Skan      convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
466118334Speter
466218334Speter      if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
466318334Speter	from = convert_to_mode (SImode, from, unsignedp);
466418334Speter
4665132718Skan      libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
4666169689Skan      gcc_assert (libfunc);
466718334Speter
466818334Speter      start_sequence ();
466918334Speter
4670132718Skan      value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
467190075Sobrien				       GET_MODE (to), 1, from,
467290075Sobrien				       GET_MODE (from));
467318334Speter      insns = get_insns ();
467418334Speter      end_sequence ();
467518334Speter
467618334Speter      emit_libcall_block (insns, target, value,
467750397Sobrien			  gen_rtx_FLOAT (GET_MODE (to), from));
467818334Speter    }
467918334Speter
468018334Speter done:
468118334Speter
468218334Speter  /* Copy result to requested destination
468318334Speter     if we have been computing in a temp location.  */
468418334Speter
468518334Speter  if (target != to)
468618334Speter    {
468718334Speter      if (GET_MODE (target) == GET_MODE (to))
468818334Speter	emit_move_insn (to, target);
468918334Speter      else
469018334Speter	convert_move (to, target, 0);
469118334Speter    }
469218334Speter}
469318334Speter
4694169689Skan/* Generate code to convert FROM to fixed point and store in TO.  FROM
4695169689Skan   must be floating point.  */
469618334Speter
469718334Spetervoid
4698132718Skanexpand_fix (rtx to, rtx from, int unsignedp)
469918334Speter{
470018334Speter  enum insn_code icode;
470190075Sobrien  rtx target = to;
470218334Speter  enum machine_mode fmode, imode;
470318334Speter  int must_trunc = 0;
470418334Speter
470518334Speter  /* We first try to find a pair of modes, one real and one integer, at
470618334Speter     least as wide as FROM and TO, respectively, in which we can open-code
470718334Speter     this conversion.  If the integer mode is wider than the mode of TO,
470818334Speter     we can do the conversion either signed or unsigned.  */
470918334Speter
471090075Sobrien  for (fmode = GET_MODE (from); fmode != VOIDmode;
471190075Sobrien       fmode = GET_MODE_WIDER_MODE (fmode))
471290075Sobrien    for (imode = GET_MODE (to); imode != VOIDmode;
471390075Sobrien	 imode = GET_MODE_WIDER_MODE (imode))
471418334Speter      {
471518334Speter	int doing_unsigned = unsignedp;
471618334Speter
471718334Speter	icode = can_fix_p (imode, fmode, unsignedp, &must_trunc);
471818334Speter	if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp)
471918334Speter	  icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0;
472018334Speter
472118334Speter	if (icode != CODE_FOR_nothing)
472218334Speter	  {
472318334Speter	    if (fmode != GET_MODE (from))
472418334Speter	      from = convert_to_mode (fmode, from, 0);
472518334Speter
472618334Speter	    if (must_trunc)
4727169689Skan	      {
4728169689Skan		rtx temp = gen_reg_rtx (GET_MODE (from));
4729169689Skan		from = expand_unop (GET_MODE (from), ftrunc_optab, from,
4730169689Skan				    temp, 0);
4731169689Skan	      }
473218334Speter
473318334Speter	    if (imode != GET_MODE (to))
473418334Speter	      target = gen_reg_rtx (imode);
473518334Speter
473618334Speter	    emit_unop_insn (icode, target, from,
473718334Speter			    doing_unsigned ? UNSIGNED_FIX : FIX);
473818334Speter	    if (target != to)
473918334Speter	      convert_move (to, target, unsignedp);
474018334Speter	    return;
474118334Speter	  }
474218334Speter      }
474318334Speter
474418334Speter  /* For an unsigned conversion, there is one more way to do it.
474518334Speter     If we have a signed conversion, we generate code that compares
474618334Speter     the real value to the largest representable positive number.  If if
474718334Speter     is smaller, the conversion is done normally.  Otherwise, subtract
474818334Speter     one plus the highest signed number, convert, and add it back.
474918334Speter
475018334Speter     We only need to check all real modes, since we know we didn't find
4751132718Skan     anything with a wider integer mode.
475218334Speter
4753132718Skan     This code used to extend FP value into mode wider than the destination.
4754132718Skan     This is not needed.  Consider, for instance conversion from SFmode
4755132718Skan     into DImode.
4756132718Skan
4757169689Skan     The hot path through the code is dealing with inputs smaller than 2^63
4758132718Skan     and doing just the conversion, so there is no bits to lose.
4759132718Skan
4760132718Skan     In the other path we know the value is positive in the range 2^63..2^64-1
4761132718Skan     inclusive.  (as for other imput overflow happens and result is undefined)
4762132718Skan     So we know that the most important bit set in mantissa corresponds to
4763132718Skan     2^63.  The subtraction of 2^63 should not generate any rounding as it
4764132718Skan     simply clears out that bit.  The rest is trivial.  */
4765132718Skan
476618334Speter  if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
476718334Speter    for (fmode = GET_MODE (from); fmode != VOIDmode;
476818334Speter	 fmode = GET_MODE_WIDER_MODE (fmode))
4769132718Skan      if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
4770132718Skan					 &must_trunc))
477118334Speter	{
477218334Speter	  int bitsize;
477318334Speter	  REAL_VALUE_TYPE offset;
477418334Speter	  rtx limit, lab1, lab2, insn;
477518334Speter
477618334Speter	  bitsize = GET_MODE_BITSIZE (GET_MODE (to));
4777117395Skan	  real_2expN (&offset, bitsize - 1);
477818334Speter	  limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
477918334Speter	  lab1 = gen_label_rtx ();
478018334Speter	  lab2 = gen_label_rtx ();
478118334Speter
478218334Speter	  if (fmode != GET_MODE (from))
478318334Speter	    from = convert_to_mode (fmode, from, 0);
478418334Speter
478518334Speter	  /* See if we need to do the subtraction.  */
478618334Speter	  do_pending_stack_adjust ();
478752284Sobrien	  emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
478890075Sobrien				   0, lab1);
478918334Speter
479018334Speter	  /* If not, do the signed "fix" and branch around fixup code.  */
479118334Speter	  expand_fix (to, from, 0);
479218334Speter	  emit_jump_insn (gen_jump (lab2));
479318334Speter	  emit_barrier ();
479418334Speter
479518334Speter	  /* Otherwise, subtract 2**(N-1), convert to signed number,
479618334Speter	     then add 2**(N-1).  Do the addition using XOR since this
479718334Speter	     will often generate better code.  */
479818334Speter	  emit_label (lab1);
479918334Speter	  target = expand_binop (GET_MODE (from), sub_optab, from, limit,
480018334Speter				 NULL_RTX, 0, OPTAB_LIB_WIDEN);
480118334Speter	  expand_fix (to, target, 0);
480218334Speter	  target = expand_binop (GET_MODE (to), xor_optab, to,
4803117395Skan				 gen_int_mode
4804117395Skan				 ((HOST_WIDE_INT) 1 << (bitsize - 1),
4805117395Skan				  GET_MODE (to)),
480618334Speter				 to, 1, OPTAB_LIB_WIDEN);
480718334Speter
480818334Speter	  if (target != to)
480918334Speter	    emit_move_insn (to, target);
481018334Speter
481118334Speter	  emit_label (lab2);
481218334Speter
481350397Sobrien	  if (mov_optab->handlers[(int) GET_MODE (to)].insn_code
481450397Sobrien	      != CODE_FOR_nothing)
481550397Sobrien	    {
481650397Sobrien	      /* Make a place for a REG_NOTE and add it.  */
481750397Sobrien	      insn = emit_move_insn (to, to);
481852284Sobrien	      set_unique_reg_note (insn,
481952284Sobrien	                           REG_EQUAL,
482052284Sobrien				   gen_rtx_fmt_e (UNSIGNED_FIX,
482152284Sobrien						  GET_MODE (to),
482252284Sobrien						  copy_rtx (from)));
482350397Sobrien	    }
482490075Sobrien
482518334Speter	  return;
482618334Speter	}
482718334Speter
482818334Speter  /* We can't do it with an insn, so use a library call.  But first ensure
482918334Speter     that the mode of TO is at least as wide as SImode, since those are the
483018334Speter     only library calls we know about.  */
483118334Speter
483218334Speter  if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
483318334Speter    {
483418334Speter      target = gen_reg_rtx (SImode);
483518334Speter
483618334Speter      expand_fix (target, from, unsignedp);
483718334Speter    }
483818334Speter  else
483918334Speter    {
484018334Speter      rtx insns;
484118334Speter      rtx value;
4842132718Skan      rtx libfunc;
4843169689Skan
4844132718Skan      convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
4845132718Skan      libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
4846169689Skan      gcc_assert (libfunc);
484718334Speter
484818334Speter      start_sequence ();
484918334Speter
4850132718Skan      value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
485190075Sobrien				       GET_MODE (to), 1, from,
485290075Sobrien				       GET_MODE (from));
485318334Speter      insns = get_insns ();
485418334Speter      end_sequence ();
485518334Speter
485618334Speter      emit_libcall_block (insns, target, value,
485750397Sobrien			  gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
485850397Sobrien					 GET_MODE (to), from));
485918334Speter    }
4860132718Skan
486150397Sobrien  if (target != to)
486250397Sobrien    {
486350397Sobrien      if (GET_MODE (to) == GET_MODE (target))
486450397Sobrien        emit_move_insn (to, target);
486550397Sobrien      else
486650397Sobrien        convert_move (to, target, 0);
486750397Sobrien    }
486818334Speter}
486918334Speter
487090075Sobrien/* Report whether we have an instruction to perform the operation
487190075Sobrien   specified by CODE on operands of mode MODE.  */
487290075Sobrienint
4873132718Skanhave_insn_for (enum rtx_code code, enum machine_mode mode)
487418334Speter{
487590075Sobrien  return (code_to_optab[(int) code] != 0
487690075Sobrien	  && (code_to_optab[(int) code]->handlers[(int) mode].insn_code
487790075Sobrien	      != CODE_FOR_nothing));
487890075Sobrien}
487990075Sobrien
488090075Sobrien/* Create a blank optab.  */
488190075Sobrienstatic optab
4882132718Skannew_optab (void)
488390075Sobrien{
488418334Speter  int i;
4885132718Skan  optab op = ggc_alloc (sizeof (struct optab));
488618334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
488718334Speter    {
488818334Speter      op->handlers[i].insn_code = CODE_FOR_nothing;
488918334Speter      op->handlers[i].libfunc = 0;
489018334Speter    }
489118334Speter
489290075Sobrien  return op;
489390075Sobrien}
489418334Speter
4895132718Skanstatic convert_optab
4896132718Skannew_convert_optab (void)
4897132718Skan{
4898132718Skan  int i, j;
4899132718Skan  convert_optab op = ggc_alloc (sizeof (struct convert_optab));
4900132718Skan  for (i = 0; i < NUM_MACHINE_MODES; i++)
4901132718Skan    for (j = 0; j < NUM_MACHINE_MODES; j++)
4902132718Skan      {
4903132718Skan	op->handlers[i][j].insn_code = CODE_FOR_nothing;
4904132718Skan	op->handlers[i][j].libfunc = 0;
4905132718Skan      }
4906132718Skan  return op;
4907132718Skan}
4908132718Skan
490990075Sobrien/* Same, but fill in its code as CODE, and write it into the
491090075Sobrien   code_to_optab table.  */
491190075Sobrienstatic inline optab
4912132718Skaninit_optab (enum rtx_code code)
491390075Sobrien{
491490075Sobrien  optab op = new_optab ();
491590075Sobrien  op->code = code;
491690075Sobrien  code_to_optab[(int) code] = op;
491718334Speter  return op;
491818334Speter}
491918334Speter
492090075Sobrien/* Same, but fill in its code as CODE, and do _not_ write it into
492190075Sobrien   the code_to_optab table.  */
492290075Sobrienstatic inline optab
4923132718Skaninit_optabv (enum rtx_code code)
492490075Sobrien{
492590075Sobrien  optab op = new_optab ();
492690075Sobrien  op->code = code;
492790075Sobrien  return op;
492890075Sobrien}
492990075Sobrien
4930132718Skan/* Conversion optabs never go in the code_to_optab table.  */
4931132718Skanstatic inline convert_optab
4932132718Skaninit_convert_optab (enum rtx_code code)
4933132718Skan{
4934132718Skan  convert_optab op = new_convert_optab ();
4935132718Skan  op->code = code;
4936132718Skan  return op;
4937132718Skan}
4938132718Skan
493918334Speter/* Initialize the libfunc fields of an entire group of entries in some
494018334Speter   optab.  Each entry is set equal to a string consisting of a leading
494118334Speter   pair of underscores followed by a generic operation name followed by
4942132718Skan   a mode name (downshifted to lowercase) followed by a single character
494318334Speter   representing the number of operands for the given operation (which is
494418334Speter   usually one of the characters '2', '3', or '4').
494518334Speter
494618334Speter   OPTABLE is the table in which libfunc fields are to be initialized.
494718334Speter   FIRST_MODE is the first machine mode index in the given optab to
494818334Speter     initialize.
494918334Speter   LAST_MODE is the last machine mode index in the given optab to
495018334Speter     initialize.
495118334Speter   OPNAME is the generic (string) name of the operation.
495218334Speter   SUFFIX is the character which specifies the number of operands for
495318334Speter     the given generic operation.
495418334Speter*/
495518334Speter
495618334Speterstatic void
4957132718Skaninit_libfuncs (optab optable, int first_mode, int last_mode,
4958132718Skan	       const char *opname, int suffix)
495918334Speter{
496090075Sobrien  int mode;
496190075Sobrien  unsigned opname_len = strlen (opname);
496218334Speter
496318334Speter  for (mode = first_mode; (int) mode <= (int) last_mode;
496418334Speter       mode = (enum machine_mode) ((int) mode + 1))
496518334Speter    {
4966117395Skan      const char *mname = GET_MODE_NAME (mode);
496790075Sobrien      unsigned mname_len = strlen (mname);
496890075Sobrien      char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
496990075Sobrien      char *p;
497090075Sobrien      const char *q;
497118334Speter
497218334Speter      p = libfunc_name;
497318334Speter      *p++ = '_';
497418334Speter      *p++ = '_';
497518334Speter      for (q = opname; *q; )
497618334Speter	*p++ = *q++;
497718334Speter      for (q = mname; *q; q++)
497890075Sobrien	*p++ = TOLOWER (*q);
497918334Speter      *p++ = suffix;
498090075Sobrien      *p = '\0';
498190075Sobrien
498218334Speter      optable->handlers[(int) mode].libfunc
4983132718Skan	= init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name));
498418334Speter    }
498518334Speter}
498618334Speter
498718334Speter/* Initialize the libfunc fields of an entire group of entries in some
498818334Speter   optab which correspond to all integer mode operations.  The parameters
498918334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
499018334Speter   routine.  (See above).  */
499118334Speter
499218334Speterstatic void
4993132718Skaninit_integral_libfuncs (optab optable, const char *opname, int suffix)
499418334Speter{
4995132718Skan  int maxsize = 2*BITS_PER_WORD;
4996132718Skan  if (maxsize < LONG_LONG_TYPE_SIZE)
4997132718Skan    maxsize = LONG_LONG_TYPE_SIZE;
4998132718Skan  init_libfuncs (optable, word_mode,
4999132718Skan		 mode_for_size (maxsize, MODE_INT, 0),
5000132718Skan		 opname, suffix);
500118334Speter}
500218334Speter
500318334Speter/* Initialize the libfunc fields of an entire group of entries in some
500418334Speter   optab which correspond to all real mode operations.  The parameters
500518334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
500618334Speter   routine.  (See above).  */
500718334Speter
500818334Speterstatic void
5009132718Skaninit_floating_libfuncs (optab optable, const char *opname, int suffix)
501018334Speter{
5011132718Skan  init_libfuncs (optable, MIN_MODE_FLOAT, MAX_MODE_FLOAT, opname, suffix);
5012169689Skan  init_libfuncs (optable, MIN_MODE_DECIMAL_FLOAT, MAX_MODE_DECIMAL_FLOAT,
5013169689Skan		 opname, suffix);
501418334Speter}
501518334Speter
5016132718Skan/* Initialize the libfunc fields of an entire group of entries of an
5017132718Skan   inter-mode-class conversion optab.  The string formation rules are
5018132718Skan   similar to the ones for init_libfuncs, above, but instead of having
5019132718Skan   a mode name and an operand count these functions have two mode names
5020132718Skan   and no operand count.  */
5021132718Skanstatic void
5022132718Skaninit_interclass_conv_libfuncs (convert_optab tab, const char *opname,
5023132718Skan			       enum mode_class from_class,
5024132718Skan			       enum mode_class to_class)
5025132718Skan{
5026132718Skan  enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class);
5027132718Skan  enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class);
5028132718Skan  size_t opname_len = strlen (opname);
5029132718Skan  size_t max_mname_len = 0;
5030132718Skan
5031132718Skan  enum machine_mode fmode, tmode;
5032132718Skan  const char *fname, *tname;
5033132718Skan  const char *q;
5034132718Skan  char *libfunc_name, *suffix;
5035132718Skan  char *p;
5036132718Skan
5037132718Skan  for (fmode = first_from_mode;
5038132718Skan       fmode != VOIDmode;
5039132718Skan       fmode = GET_MODE_WIDER_MODE (fmode))
5040132718Skan    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode)));
5041132718Skan
5042132718Skan  for (tmode = first_to_mode;
5043132718Skan       tmode != VOIDmode;
5044132718Skan       tmode = GET_MODE_WIDER_MODE (tmode))
5045132718Skan    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode)));
5046132718Skan
5047132718Skan  libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
5048132718Skan  libfunc_name[0] = '_';
5049132718Skan  libfunc_name[1] = '_';
5050132718Skan  memcpy (&libfunc_name[2], opname, opname_len);
5051132718Skan  suffix = libfunc_name + opname_len + 2;
5052132718Skan
5053132718Skan  for (fmode = first_from_mode; fmode != VOIDmode;
5054132718Skan       fmode = GET_MODE_WIDER_MODE (fmode))
5055132718Skan    for (tmode = first_to_mode; tmode != VOIDmode;
5056132718Skan	 tmode = GET_MODE_WIDER_MODE (tmode))
5057132718Skan      {
5058132718Skan	fname = GET_MODE_NAME (fmode);
5059132718Skan	tname = GET_MODE_NAME (tmode);
5060132718Skan
5061132718Skan	p = suffix;
5062132718Skan	for (q = fname; *q; p++, q++)
5063132718Skan	  *p = TOLOWER (*q);
5064132718Skan	for (q = tname; *q; p++, q++)
5065132718Skan	  *p = TOLOWER (*q);
5066132718Skan
5067132718Skan	*p = '\0';
5068132718Skan
5069132718Skan	tab->handlers[tmode][fmode].libfunc
5070132718Skan	  = init_one_libfunc (ggc_alloc_string (libfunc_name,
5071132718Skan						p - libfunc_name));
5072132718Skan      }
5073132718Skan}
5074132718Skan
5075132718Skan/* Initialize the libfunc fields of an entire group of entries of an
5076132718Skan   intra-mode-class conversion optab.  The string formation rules are
5077132718Skan   similar to the ones for init_libfunc, above.  WIDENING says whether
5078132718Skan   the optab goes from narrow to wide modes or vice versa.  These functions
5079132718Skan   have two mode names _and_ an operand count.  */
5080132718Skanstatic void
5081132718Skaninit_intraclass_conv_libfuncs (convert_optab tab, const char *opname,
5082132718Skan			       enum mode_class class, bool widening)
5083132718Skan{
5084132718Skan  enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class);
5085132718Skan  size_t opname_len = strlen (opname);
5086132718Skan  size_t max_mname_len = 0;
5087132718Skan
5088132718Skan  enum machine_mode nmode, wmode;
5089132718Skan  const char *nname, *wname;
5090132718Skan  const char *q;
5091132718Skan  char *libfunc_name, *suffix;
5092132718Skan  char *p;
5093132718Skan
5094132718Skan  for (nmode = first_mode; nmode != VOIDmode;
5095132718Skan       nmode = GET_MODE_WIDER_MODE (nmode))
5096132718Skan    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode)));
5097132718Skan
5098132718Skan  libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
5099132718Skan  libfunc_name[0] = '_';
5100132718Skan  libfunc_name[1] = '_';
5101132718Skan  memcpy (&libfunc_name[2], opname, opname_len);
5102132718Skan  suffix = libfunc_name + opname_len + 2;
5103132718Skan
5104132718Skan  for (nmode = first_mode; nmode != VOIDmode;
5105132718Skan       nmode = GET_MODE_WIDER_MODE (nmode))
5106132718Skan    for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode;
5107132718Skan	 wmode = GET_MODE_WIDER_MODE (wmode))
5108132718Skan      {
5109132718Skan	nname = GET_MODE_NAME (nmode);
5110132718Skan	wname = GET_MODE_NAME (wmode);
5111132718Skan
5112132718Skan	p = suffix;
5113132718Skan	for (q = widening ? nname : wname; *q; p++, q++)
5114132718Skan	  *p = TOLOWER (*q);
5115132718Skan	for (q = widening ? wname : nname; *q; p++, q++)
5116132718Skan	  *p = TOLOWER (*q);
5117132718Skan
5118132718Skan	*p++ = '2';
5119132718Skan	*p = '\0';
5120132718Skan
5121132718Skan	tab->handlers[widening ? wmode : nmode]
5122132718Skan	             [widening ? nmode : wmode].libfunc
5123132718Skan	  = init_one_libfunc (ggc_alloc_string (libfunc_name,
5124132718Skan						p - libfunc_name));
5125132718Skan      }
5126132718Skan}
5127132718Skan
5128132718Skan
512990075Sobrienrtx
5130132718Skaninit_one_libfunc (const char *name)
513190075Sobrien{
5132132718Skan  rtx symbol;
5133132718Skan
5134117395Skan  /* Create a FUNCTION_DECL that can be passed to
5135117395Skan     targetm.encode_section_info.  */
513690075Sobrien  /* ??? We don't have any type information except for this is
513790075Sobrien     a function.  Pretend this is "int foo()".  */
513890075Sobrien  tree decl = build_decl (FUNCTION_DECL, get_identifier (name),
513990075Sobrien			  build_function_type (integer_type_node, NULL_TREE));
514090075Sobrien  DECL_ARTIFICIAL (decl) = 1;
514190075Sobrien  DECL_EXTERNAL (decl) = 1;
514290075Sobrien  TREE_PUBLIC (decl) = 1;
514318334Speter
5144132718Skan  symbol = XEXP (DECL_RTL (decl), 0);
5145132718Skan
5146132718Skan  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
5147132718Skan     are the flags assigned by targetm.encode_section_info.  */
5148169689Skan  SET_SYMBOL_REF_DECL (symbol, 0);
5149132718Skan
5150132718Skan  return symbol;
515190075Sobrien}
515290075Sobrien
5153132718Skan/* Call this to reset the function entry for one optab (OPTABLE) in mode
5154132718Skan   MODE to NAME, which should be either 0 or a string constant.  */
5155132718Skanvoid
5156132718Skanset_optab_libfunc (optab optable, enum machine_mode mode, const char *name)
5157132718Skan{
5158132718Skan  if (name)
5159132718Skan    optable->handlers[mode].libfunc = init_one_libfunc (name);
5160132718Skan  else
5161132718Skan    optable->handlers[mode].libfunc = 0;
5162132718Skan}
5163132718Skan
5164132718Skan/* Call this to reset the function entry for one conversion optab
5165132718Skan   (OPTABLE) from mode FMODE to mode TMODE to NAME, which should be
5166132718Skan   either 0 or a string constant.  */
5167132718Skanvoid
5168132718Skanset_conv_libfunc (convert_optab optable, enum machine_mode tmode,
5169132718Skan		  enum machine_mode fmode, const char *name)
5170132718Skan{
5171132718Skan  if (name)
5172132718Skan    optable->handlers[tmode][fmode].libfunc = init_one_libfunc (name);
5173132718Skan  else
5174132718Skan    optable->handlers[tmode][fmode].libfunc = 0;
5175132718Skan}
5176132718Skan
517718334Speter/* Call this once to initialize the contents of the optabs
517818334Speter   appropriately for the current target machine.  */
517918334Speter
518018334Spetervoid
5181132718Skaninit_optabs (void)
518218334Speter{
5183132718Skan  unsigned int i;
518450397Sobrien
518518334Speter  /* Start by initializing all tables to contain CODE_FOR_nothing.  */
518618334Speter
518718334Speter  for (i = 0; i < NUM_RTX_CODE; i++)
518818334Speter    setcc_gen_code[i] = CODE_FOR_nothing;
518918334Speter
519018334Speter#ifdef HAVE_conditional_move
519118334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
519218334Speter    movcc_gen_code[i] = CODE_FOR_nothing;
519318334Speter#endif
519418334Speter
5195169689Skan  for (i = 0; i < NUM_MACHINE_MODES; i++)
5196169689Skan    {
5197169689Skan      vcond_gen_code[i] = CODE_FOR_nothing;
5198169689Skan      vcondu_gen_code[i] = CODE_FOR_nothing;
5199169689Skan    }
5200169689Skan
520118334Speter  add_optab = init_optab (PLUS);
520290075Sobrien  addv_optab = init_optabv (PLUS);
520318334Speter  sub_optab = init_optab (MINUS);
520490075Sobrien  subv_optab = init_optabv (MINUS);
520518334Speter  smul_optab = init_optab (MULT);
520690075Sobrien  smulv_optab = init_optabv (MULT);
520718334Speter  smul_highpart_optab = init_optab (UNKNOWN);
520818334Speter  umul_highpart_optab = init_optab (UNKNOWN);
520918334Speter  smul_widen_optab = init_optab (UNKNOWN);
521018334Speter  umul_widen_optab = init_optab (UNKNOWN);
5211169689Skan  usmul_widen_optab = init_optab (UNKNOWN);
521218334Speter  sdiv_optab = init_optab (DIV);
521390075Sobrien  sdivv_optab = init_optabv (DIV);
521418334Speter  sdivmod_optab = init_optab (UNKNOWN);
521518334Speter  udiv_optab = init_optab (UDIV);
521618334Speter  udivmod_optab = init_optab (UNKNOWN);
521718334Speter  smod_optab = init_optab (MOD);
521818334Speter  umod_optab = init_optab (UMOD);
5219169689Skan  fmod_optab = init_optab (UNKNOWN);
5220169689Skan  drem_optab = init_optab (UNKNOWN);
522118334Speter  ftrunc_optab = init_optab (UNKNOWN);
522218334Speter  and_optab = init_optab (AND);
522318334Speter  ior_optab = init_optab (IOR);
522418334Speter  xor_optab = init_optab (XOR);
522518334Speter  ashl_optab = init_optab (ASHIFT);
522618334Speter  ashr_optab = init_optab (ASHIFTRT);
522718334Speter  lshr_optab = init_optab (LSHIFTRT);
522818334Speter  rotl_optab = init_optab (ROTATE);
522918334Speter  rotr_optab = init_optab (ROTATERT);
523018334Speter  smin_optab = init_optab (SMIN);
523118334Speter  smax_optab = init_optab (SMAX);
523218334Speter  umin_optab = init_optab (UMIN);
523318334Speter  umax_optab = init_optab (UMAX);
5234132718Skan  pow_optab = init_optab (UNKNOWN);
5235132718Skan  atan2_optab = init_optab (UNKNOWN);
523690075Sobrien
523790075Sobrien  /* These three have codes assigned exclusively for the sake of
523890075Sobrien     have_insn_for.  */
523990075Sobrien  mov_optab = init_optab (SET);
524090075Sobrien  movstrict_optab = init_optab (STRICT_LOW_PART);
524190075Sobrien  cmp_optab = init_optab (COMPARE);
524290075Sobrien
524318334Speter  ucmp_optab = init_optab (UNKNOWN);
524418334Speter  tst_optab = init_optab (UNKNOWN);
5245132718Skan
5246132718Skan  eq_optab = init_optab (EQ);
5247132718Skan  ne_optab = init_optab (NE);
5248132718Skan  gt_optab = init_optab (GT);
5249132718Skan  ge_optab = init_optab (GE);
5250132718Skan  lt_optab = init_optab (LT);
5251132718Skan  le_optab = init_optab (LE);
5252132718Skan  unord_optab = init_optab (UNORDERED);
5253132718Skan
525418334Speter  neg_optab = init_optab (NEG);
525590075Sobrien  negv_optab = init_optabv (NEG);
525618334Speter  abs_optab = init_optab (ABS);
525790075Sobrien  absv_optab = init_optabv (ABS);
5258132718Skan  addcc_optab = init_optab (UNKNOWN);
525918334Speter  one_cmpl_optab = init_optab (NOT);
5260259563Spfg  bswap_optab = init_optab (BSWAP);
526118334Speter  ffs_optab = init_optab (FFS);
5262132718Skan  clz_optab = init_optab (CLZ);
5263132718Skan  ctz_optab = init_optab (CTZ);
5264132718Skan  popcount_optab = init_optab (POPCOUNT);
5265132718Skan  parity_optab = init_optab (PARITY);
526618334Speter  sqrt_optab = init_optab (SQRT);
5267132718Skan  floor_optab = init_optab (UNKNOWN);
5268169689Skan  lfloor_optab = init_optab (UNKNOWN);
5269132718Skan  ceil_optab = init_optab (UNKNOWN);
5270169689Skan  lceil_optab = init_optab (UNKNOWN);
5271132718Skan  round_optab = init_optab (UNKNOWN);
5272132718Skan  btrunc_optab = init_optab (UNKNOWN);
5273132718Skan  nearbyint_optab = init_optab (UNKNOWN);
5274169689Skan  rint_optab = init_optab (UNKNOWN);
5275169689Skan  lrint_optab = init_optab (UNKNOWN);
5276169689Skan  sincos_optab = init_optab (UNKNOWN);
527718334Speter  sin_optab = init_optab (UNKNOWN);
5278169689Skan  asin_optab = init_optab (UNKNOWN);
527918334Speter  cos_optab = init_optab (UNKNOWN);
5280169689Skan  acos_optab = init_optab (UNKNOWN);
5281117395Skan  exp_optab = init_optab (UNKNOWN);
5282169689Skan  exp10_optab = init_optab (UNKNOWN);
5283169689Skan  exp2_optab = init_optab (UNKNOWN);
5284169689Skan  expm1_optab = init_optab (UNKNOWN);
5285169689Skan  ldexp_optab = init_optab (UNKNOWN);
5286169689Skan  logb_optab = init_optab (UNKNOWN);
5287169689Skan  ilogb_optab = init_optab (UNKNOWN);
5288117395Skan  log_optab = init_optab (UNKNOWN);
5289169689Skan  log10_optab = init_optab (UNKNOWN);
5290169689Skan  log2_optab = init_optab (UNKNOWN);
5291169689Skan  log1p_optab = init_optab (UNKNOWN);
5292132718Skan  tan_optab = init_optab (UNKNOWN);
5293132718Skan  atan_optab = init_optab (UNKNOWN);
5294169689Skan  copysign_optab = init_optab (UNKNOWN);
5295169689Skan
529618334Speter  strlen_optab = init_optab (UNKNOWN);
529790075Sobrien  cbranch_optab = init_optab (UNKNOWN);
529890075Sobrien  cmov_optab = init_optab (UNKNOWN);
529990075Sobrien  cstore_optab = init_optab (UNKNOWN);
530090075Sobrien  push_optab = init_optab (UNKNOWN);
530118334Speter
5302169689Skan  reduc_smax_optab = init_optab (UNKNOWN);
5303169689Skan  reduc_umax_optab = init_optab (UNKNOWN);
5304169689Skan  reduc_smin_optab = init_optab (UNKNOWN);
5305169689Skan  reduc_umin_optab = init_optab (UNKNOWN);
5306169689Skan  reduc_splus_optab = init_optab (UNKNOWN);
5307169689Skan  reduc_uplus_optab = init_optab (UNKNOWN);
5308169689Skan
5309169689Skan  ssum_widen_optab = init_optab (UNKNOWN);
5310169689Skan  usum_widen_optab = init_optab (UNKNOWN);
5311169689Skan  sdot_prod_optab = init_optab (UNKNOWN);
5312169689Skan  udot_prod_optab = init_optab (UNKNOWN);
5313169689Skan
5314132718Skan  vec_extract_optab = init_optab (UNKNOWN);
5315132718Skan  vec_set_optab = init_optab (UNKNOWN);
5316132718Skan  vec_init_optab = init_optab (UNKNOWN);
5317169689Skan  vec_shl_optab = init_optab (UNKNOWN);
5318169689Skan  vec_shr_optab = init_optab (UNKNOWN);
5319169689Skan  vec_realign_load_optab = init_optab (UNKNOWN);
5320169689Skan  movmisalign_optab = init_optab (UNKNOWN);
5321169689Skan
5322169689Skan  powi_optab = init_optab (UNKNOWN);
5323169689Skan
5324132718Skan  /* Conversions.  */
5325132718Skan  sext_optab = init_convert_optab (SIGN_EXTEND);
5326132718Skan  zext_optab = init_convert_optab (ZERO_EXTEND);
5327132718Skan  trunc_optab = init_convert_optab (TRUNCATE);
5328132718Skan  sfix_optab = init_convert_optab (FIX);
5329132718Skan  ufix_optab = init_convert_optab (UNSIGNED_FIX);
5330132718Skan  sfixtrunc_optab = init_convert_optab (UNKNOWN);
5331132718Skan  ufixtrunc_optab = init_convert_optab (UNKNOWN);
5332132718Skan  sfloat_optab = init_convert_optab (FLOAT);
5333132718Skan  ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
5334132718Skan
533518334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
533618334Speter    {
5337169689Skan      movmem_optab[i] = CODE_FOR_nothing;
5338132718Skan      cmpstr_optab[i] = CODE_FOR_nothing;
5339169689Skan      cmpstrn_optab[i] = CODE_FOR_nothing;
5340132718Skan      cmpmem_optab[i] = CODE_FOR_nothing;
5341169689Skan      setmem_optab[i] = CODE_FOR_nothing;
534218334Speter
5343169689Skan      sync_add_optab[i] = CODE_FOR_nothing;
5344169689Skan      sync_sub_optab[i] = CODE_FOR_nothing;
5345169689Skan      sync_ior_optab[i] = CODE_FOR_nothing;
5346169689Skan      sync_and_optab[i] = CODE_FOR_nothing;
5347169689Skan      sync_xor_optab[i] = CODE_FOR_nothing;
5348169689Skan      sync_nand_optab[i] = CODE_FOR_nothing;
5349169689Skan      sync_old_add_optab[i] = CODE_FOR_nothing;
5350169689Skan      sync_old_sub_optab[i] = CODE_FOR_nothing;
5351169689Skan      sync_old_ior_optab[i] = CODE_FOR_nothing;
5352169689Skan      sync_old_and_optab[i] = CODE_FOR_nothing;
5353169689Skan      sync_old_xor_optab[i] = CODE_FOR_nothing;
5354169689Skan      sync_old_nand_optab[i] = CODE_FOR_nothing;
5355169689Skan      sync_new_add_optab[i] = CODE_FOR_nothing;
5356169689Skan      sync_new_sub_optab[i] = CODE_FOR_nothing;
5357169689Skan      sync_new_ior_optab[i] = CODE_FOR_nothing;
5358169689Skan      sync_new_and_optab[i] = CODE_FOR_nothing;
5359169689Skan      sync_new_xor_optab[i] = CODE_FOR_nothing;
5360169689Skan      sync_new_nand_optab[i] = CODE_FOR_nothing;
5361169689Skan      sync_compare_and_swap[i] = CODE_FOR_nothing;
5362169689Skan      sync_compare_and_swap_cc[i] = CODE_FOR_nothing;
5363169689Skan      sync_lock_test_and_set[i] = CODE_FOR_nothing;
5364169689Skan      sync_lock_release[i] = CODE_FOR_nothing;
5365169689Skan
536618334Speter      reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
536718334Speter    }
536818334Speter
536918334Speter  /* Fill in the optabs with the insns we support.  */
537018334Speter  init_all_optabs ();
537118334Speter
537218334Speter  /* Initialize the optabs with the names of the library functions.  */
537318334Speter  init_integral_libfuncs (add_optab, "add", '3');
537418334Speter  init_floating_libfuncs (add_optab, "add", '3');
537590075Sobrien  init_integral_libfuncs (addv_optab, "addv", '3');
537690075Sobrien  init_floating_libfuncs (addv_optab, "add", '3');
537718334Speter  init_integral_libfuncs (sub_optab, "sub", '3');
537818334Speter  init_floating_libfuncs (sub_optab, "sub", '3');
537990075Sobrien  init_integral_libfuncs (subv_optab, "subv", '3');
538090075Sobrien  init_floating_libfuncs (subv_optab, "sub", '3');
538118334Speter  init_integral_libfuncs (smul_optab, "mul", '3');
538218334Speter  init_floating_libfuncs (smul_optab, "mul", '3');
538390075Sobrien  init_integral_libfuncs (smulv_optab, "mulv", '3');
538490075Sobrien  init_floating_libfuncs (smulv_optab, "mul", '3');
538518334Speter  init_integral_libfuncs (sdiv_optab, "div", '3');
538690075Sobrien  init_floating_libfuncs (sdiv_optab, "div", '3');
538790075Sobrien  init_integral_libfuncs (sdivv_optab, "divv", '3');
538818334Speter  init_integral_libfuncs (udiv_optab, "udiv", '3');
538918334Speter  init_integral_libfuncs (sdivmod_optab, "divmod", '4');
539018334Speter  init_integral_libfuncs (udivmod_optab, "udivmod", '4');
539118334Speter  init_integral_libfuncs (smod_optab, "mod", '3');
539218334Speter  init_integral_libfuncs (umod_optab, "umod", '3');
539318334Speter  init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
539418334Speter  init_integral_libfuncs (and_optab, "and", '3');
539518334Speter  init_integral_libfuncs (ior_optab, "ior", '3');
539618334Speter  init_integral_libfuncs (xor_optab, "xor", '3');
539718334Speter  init_integral_libfuncs (ashl_optab, "ashl", '3');
539818334Speter  init_integral_libfuncs (ashr_optab, "ashr", '3');
539918334Speter  init_integral_libfuncs (lshr_optab, "lshr", '3');
540018334Speter  init_integral_libfuncs (smin_optab, "min", '3');
540118334Speter  init_floating_libfuncs (smin_optab, "min", '3');
540218334Speter  init_integral_libfuncs (smax_optab, "max", '3');
540318334Speter  init_floating_libfuncs (smax_optab, "max", '3');
540418334Speter  init_integral_libfuncs (umin_optab, "umin", '3');
540518334Speter  init_integral_libfuncs (umax_optab, "umax", '3');
540618334Speter  init_integral_libfuncs (neg_optab, "neg", '2');
540718334Speter  init_floating_libfuncs (neg_optab, "neg", '2');
540890075Sobrien  init_integral_libfuncs (negv_optab, "negv", '2');
540990075Sobrien  init_floating_libfuncs (negv_optab, "neg", '2');
541018334Speter  init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
541118334Speter  init_integral_libfuncs (ffs_optab, "ffs", '2');
5412132718Skan  init_integral_libfuncs (clz_optab, "clz", '2');
5413132718Skan  init_integral_libfuncs (ctz_optab, "ctz", '2');
5414132718Skan  init_integral_libfuncs (popcount_optab, "popcount", '2');
5415132718Skan  init_integral_libfuncs (parity_optab, "parity", '2');
541618334Speter
5417169689Skan  /* Comparison libcalls for integers MUST come in pairs,
5418169689Skan     signed/unsigned.  */
541918334Speter  init_integral_libfuncs (cmp_optab, "cmp", '2');
542018334Speter  init_integral_libfuncs (ucmp_optab, "ucmp", '2');
542118334Speter  init_floating_libfuncs (cmp_optab, "cmp", '2');
542218334Speter
5423132718Skan  /* EQ etc are floating point only.  */
5424132718Skan  init_floating_libfuncs (eq_optab, "eq", '2');
5425132718Skan  init_floating_libfuncs (ne_optab, "ne", '2');
5426132718Skan  init_floating_libfuncs (gt_optab, "gt", '2');
5427132718Skan  init_floating_libfuncs (ge_optab, "ge", '2');
5428132718Skan  init_floating_libfuncs (lt_optab, "lt", '2');
5429132718Skan  init_floating_libfuncs (le_optab, "le", '2');
5430132718Skan  init_floating_libfuncs (unord_optab, "unord", '2');
543118334Speter
5432169689Skan  init_floating_libfuncs (powi_optab, "powi", '2');
5433169689Skan
5434132718Skan  /* Conversions.  */
5435169689Skan  init_interclass_conv_libfuncs (sfloat_optab, "float",
5436169689Skan				 MODE_INT, MODE_FLOAT);
5437169689Skan  init_interclass_conv_libfuncs (sfloat_optab, "float",
5438169689Skan				 MODE_INT, MODE_DECIMAL_FLOAT);
5439169689Skan  init_interclass_conv_libfuncs (ufloat_optab, "floatun",
5440169689Skan				 MODE_INT, MODE_FLOAT);
5441169689Skan  init_interclass_conv_libfuncs (ufloat_optab, "floatun",
5442169689Skan				 MODE_INT, MODE_DECIMAL_FLOAT);
5443169689Skan  init_interclass_conv_libfuncs (sfix_optab, "fix",
5444169689Skan				 MODE_FLOAT, MODE_INT);
5445169689Skan  init_interclass_conv_libfuncs (sfix_optab, "fix",
5446169689Skan				 MODE_DECIMAL_FLOAT, MODE_INT);
5447169689Skan  init_interclass_conv_libfuncs (ufix_optab, "fixuns",
5448169689Skan				 MODE_FLOAT, MODE_INT);
5449169689Skan  init_interclass_conv_libfuncs (ufix_optab, "fixuns",
5450169689Skan				 MODE_DECIMAL_FLOAT, MODE_INT);
5451169689Skan  init_interclass_conv_libfuncs (ufloat_optab, "floatuns",
5452169689Skan				 MODE_INT, MODE_DECIMAL_FLOAT);
545318334Speter
5454132718Skan  /* sext_optab is also used for FLOAT_EXTEND.  */
5455132718Skan  init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);
5456169689Skan  init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, true);
5457169689Skan  init_interclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, MODE_DECIMAL_FLOAT);
5458169689Skan  init_interclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, MODE_FLOAT);
5459132718Skan  init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false);
5460169689Skan  init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, false);
5461169689Skan  init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, MODE_DECIMAL_FLOAT);
5462169689Skan  init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, MODE_FLOAT);
546318334Speter
5464259563Spfg  /* Explicitly initialize the bswap libfuncs since we need them to be
5465259563Spfg     valid for things other than word_mode.  */
5466259563Spfg  set_optab_libfunc (bswap_optab, SImode, "__bswapsi2");
5467259563Spfg  set_optab_libfunc (bswap_optab, DImode, "__bswapdi2");
5468259563Spfg
5469132718Skan  /* Use cabs for double complex abs, since systems generally have cabs.
5470132718Skan     Don't define any libcall for float complex, so that cabs will be used.  */
5471132718Skan  if (complex_double_type_node)
5472132718Skan    abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc
5473132718Skan      = init_one_libfunc ("cabs");
547418334Speter
547518334Speter  /* The ffs function operates on `int'.  */
547690075Sobrien  ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
547790075Sobrien    = init_one_libfunc ("ffs");
547818334Speter
547996263Sobrien  abort_libfunc = init_one_libfunc ("abort");
548090075Sobrien  memcpy_libfunc = init_one_libfunc ("memcpy");
548190075Sobrien  memmove_libfunc = init_one_libfunc ("memmove");
548290075Sobrien  memcmp_libfunc = init_one_libfunc ("memcmp");
548390075Sobrien  memset_libfunc = init_one_libfunc ("memset");
5484132718Skan  setbits_libfunc = init_one_libfunc ("__setbits");
548518334Speter
548650397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
548790075Sobrien  setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
548890075Sobrien  longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
548950397Sobrien#else
549090075Sobrien  setjmp_libfunc = init_one_libfunc ("setjmp");
549190075Sobrien  longjmp_libfunc = init_one_libfunc ("longjmp");
549250397Sobrien#endif
549390075Sobrien  unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
549490075Sobrien  unwind_sjlj_unregister_libfunc
549590075Sobrien    = init_one_libfunc ("_Unwind_SjLj_Unregister");
549618334Speter
549752284Sobrien  /* For function entry/exit instrumentation.  */
549852284Sobrien  profile_function_entry_libfunc
549990075Sobrien    = init_one_libfunc ("__cyg_profile_func_enter");
550052284Sobrien  profile_function_exit_libfunc
550190075Sobrien    = init_one_libfunc ("__cyg_profile_func_exit");
550252284Sobrien
5503132718Skan  gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
5504132718Skan
5505117395Skan  if (HAVE_conditional_trap)
5506117395Skan    trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
550750397Sobrien
550818334Speter  /* Allow the target to add more libcalls or rename some, etc.  */
5509132718Skan  targetm.init_libfuncs ();
551018334Speter}
5511169689Skan
5512169689Skan#ifdef DEBUG
5513169689Skan
5514169689Skan/* Print information about the current contents of the optabs on
5515169689Skan   STDERR.  */
5516169689Skan
5517169689Skanstatic void
5518169689Skandebug_optab_libfuncs (void)
5519169689Skan{
5520169689Skan  int i;
5521169689Skan  int j;
5522169689Skan  int k;
5523169689Skan
5524169689Skan  /* Dump the arithmetic optabs.  */
5525169689Skan  for (i = 0; i != (int) OTI_MAX; i++)
5526169689Skan    for (j = 0; j < NUM_MACHINE_MODES; ++j)
5527169689Skan      {
5528169689Skan	optab o;
5529169689Skan	struct optab_handlers *h;
5530169689Skan
5531169689Skan	o = optab_table[i];
5532169689Skan	h = &o->handlers[j];
5533169689Skan	if (h->libfunc)
5534169689Skan	  {
5535169689Skan	    gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF);
5536169689Skan	    fprintf (stderr, "%s\t%s:\t%s\n",
5537169689Skan		     GET_RTX_NAME (o->code),
5538169689Skan		     GET_MODE_NAME (j),
5539169689Skan		     XSTR (h->libfunc, 0));
5540169689Skan	  }
5541169689Skan      }
5542169689Skan
5543169689Skan  /* Dump the conversion optabs.  */
5544169689Skan  for (i = 0; i < (int) COI_MAX; ++i)
5545169689Skan    for (j = 0; j < NUM_MACHINE_MODES; ++j)
5546169689Skan      for (k = 0; k < NUM_MACHINE_MODES; ++k)
5547169689Skan	{
5548169689Skan	  convert_optab o;
5549169689Skan	  struct optab_handlers *h;
5550169689Skan
5551169689Skan	  o = &convert_optab_table[i];
5552169689Skan	  h = &o->handlers[j][k];
5553169689Skan	  if (h->libfunc)
5554169689Skan	    {
5555169689Skan	      gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF);
5556169689Skan	      fprintf (stderr, "%s\t%s\t%s:\t%s\n",
5557169689Skan		       GET_RTX_NAME (o->code),
5558169689Skan		       GET_MODE_NAME (j),
5559169689Skan		       GET_MODE_NAME (k),
5560169689Skan		       XSTR (h->libfunc, 0));
5561169689Skan	    }
5562169689Skan	}
5563169689Skan}
5564169689Skan
5565169689Skan#endif /* DEBUG */
5566169689Skan
556750397Sobrien
556850397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
556950397Sobrien   CODE.  Return 0 on failure.  */
557050397Sobrien
557150397Sobrienrtx
5572132718Skangen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1,
5573132718Skan	       rtx op2 ATTRIBUTE_UNUSED, rtx tcode ATTRIBUTE_UNUSED)
557450397Sobrien{
557550397Sobrien  enum machine_mode mode = GET_MODE (op1);
5576117395Skan  enum insn_code icode;
5577117395Skan  rtx insn;
557850397Sobrien
5579117395Skan  if (!HAVE_conditional_trap)
5580117395Skan    return 0;
5581117395Skan
558250397Sobrien  if (mode == VOIDmode)
558350397Sobrien    return 0;
558450397Sobrien
5585117395Skan  icode = cmp_optab->handlers[(int) mode].insn_code;
5586117395Skan  if (icode == CODE_FOR_nothing)
5587117395Skan    return 0;
5588117395Skan
5589117395Skan  start_sequence ();
5590117395Skan  op1 = prepare_operand (icode, op1, 0, mode, mode, 0);
5591119256Skan  op2 = prepare_operand (icode, op2, 1, mode, mode, 0);
5592119256Skan  if (!op1 || !op2)
5593119256Skan    {
5594119256Skan      end_sequence ();
5595119256Skan      return 0;
5596119256Skan    }
5597117395Skan  emit_insn (GEN_FCN (icode) (op1, op2));
5598117395Skan
5599117395Skan  PUT_CODE (trap_rtx, code);
5600169689Skan  gcc_assert (HAVE_conditional_trap);
5601117395Skan  insn = gen_conditional_trap (trap_rtx, tcode);
5602117395Skan  if (insn)
560350397Sobrien    {
5604117395Skan      emit_insn (insn);
5605117395Skan      insn = get_insns ();
560650397Sobrien    }
5607117395Skan  end_sequence ();
560850397Sobrien
5609117395Skan  return insn;
561050397Sobrien}
5611117395Skan
5612169689Skan/* Return rtx code for TCODE. Use UNSIGNEDP to select signed
5613169689Skan   or unsigned operation code.  */
5614169689Skan
5615169689Skanstatic enum rtx_code
5616169689Skanget_rtx_code (enum tree_code tcode, bool unsignedp)
5617169689Skan{
5618169689Skan  enum rtx_code code;
5619169689Skan  switch (tcode)
5620169689Skan    {
5621169689Skan    case EQ_EXPR:
5622169689Skan      code = EQ;
5623169689Skan      break;
5624169689Skan    case NE_EXPR:
5625169689Skan      code = NE;
5626169689Skan      break;
5627169689Skan    case LT_EXPR:
5628169689Skan      code = unsignedp ? LTU : LT;
5629169689Skan      break;
5630169689Skan    case LE_EXPR:
5631169689Skan      code = unsignedp ? LEU : LE;
5632169689Skan      break;
5633169689Skan    case GT_EXPR:
5634169689Skan      code = unsignedp ? GTU : GT;
5635169689Skan      break;
5636169689Skan    case GE_EXPR:
5637169689Skan      code = unsignedp ? GEU : GE;
5638169689Skan      break;
5639169689Skan
5640169689Skan    case UNORDERED_EXPR:
5641169689Skan      code = UNORDERED;
5642169689Skan      break;
5643169689Skan    case ORDERED_EXPR:
5644169689Skan      code = ORDERED;
5645169689Skan      break;
5646169689Skan    case UNLT_EXPR:
5647169689Skan      code = UNLT;
5648169689Skan      break;
5649169689Skan    case UNLE_EXPR:
5650169689Skan      code = UNLE;
5651169689Skan      break;
5652169689Skan    case UNGT_EXPR:
5653169689Skan      code = UNGT;
5654169689Skan      break;
5655169689Skan    case UNGE_EXPR:
5656169689Skan      code = UNGE;
5657169689Skan      break;
5658169689Skan    case UNEQ_EXPR:
5659169689Skan      code = UNEQ;
5660169689Skan      break;
5661169689Skan    case LTGT_EXPR:
5662169689Skan      code = LTGT;
5663169689Skan      break;
5664169689Skan
5665169689Skan    default:
5666169689Skan      gcc_unreachable ();
5667169689Skan    }
5668169689Skan  return code;
5669169689Skan}
5670169689Skan
5671169689Skan/* Return comparison rtx for COND. Use UNSIGNEDP to select signed or
5672169689Skan   unsigned operators. Do not generate compare instruction.  */
5673169689Skan
5674169689Skanstatic rtx
5675169689Skanvector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
5676169689Skan{
5677169689Skan  enum rtx_code rcode;
5678169689Skan  tree t_op0, t_op1;
5679169689Skan  rtx rtx_op0, rtx_op1;
5680169689Skan
5681169689Skan  /* This is unlikely. While generating VEC_COND_EXPR, auto vectorizer
5682169689Skan     ensures that condition is a relational operation.  */
5683169689Skan  gcc_assert (COMPARISON_CLASS_P (cond));
5684169689Skan
5685169689Skan  rcode = get_rtx_code (TREE_CODE (cond), unsignedp);
5686169689Skan  t_op0 = TREE_OPERAND (cond, 0);
5687169689Skan  t_op1 = TREE_OPERAND (cond, 1);
5688169689Skan
5689169689Skan  /* Expand operands.  */
5690169689Skan  rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)), 1);
5691169689Skan  rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), 1);
5692169689Skan
5693169689Skan  if (!insn_data[icode].operand[4].predicate (rtx_op0, GET_MODE (rtx_op0))
5694169689Skan      && GET_MODE (rtx_op0) != VOIDmode)
5695169689Skan    rtx_op0 = force_reg (GET_MODE (rtx_op0), rtx_op0);
5696169689Skan
5697169689Skan  if (!insn_data[icode].operand[5].predicate (rtx_op1, GET_MODE (rtx_op1))
5698169689Skan      && GET_MODE (rtx_op1) != VOIDmode)
5699169689Skan    rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1);
5700169689Skan
5701169689Skan  return gen_rtx_fmt_ee (rcode, VOIDmode, rtx_op0, rtx_op1);
5702169689Skan}
5703169689Skan
5704169689Skan/* Return insn code for VEC_COND_EXPR EXPR.  */
5705169689Skan
5706169689Skanstatic inline enum insn_code
5707169689Skanget_vcond_icode (tree expr, enum machine_mode mode)
5708169689Skan{
5709169689Skan  enum insn_code icode = CODE_FOR_nothing;
5710169689Skan
5711169689Skan  if (TYPE_UNSIGNED (TREE_TYPE (expr)))
5712169689Skan    icode = vcondu_gen_code[mode];
5713169689Skan  else
5714169689Skan    icode = vcond_gen_code[mode];
5715169689Skan  return icode;
5716169689Skan}
5717169689Skan
5718169689Skan/* Return TRUE iff, appropriate vector insns are available
5719169689Skan   for vector cond expr expr in VMODE mode.  */
5720169689Skan
5721169689Skanbool
5722169689Skanexpand_vec_cond_expr_p (tree expr, enum machine_mode vmode)
5723169689Skan{
5724169689Skan  if (get_vcond_icode (expr, vmode) == CODE_FOR_nothing)
5725169689Skan    return false;
5726169689Skan  return true;
5727169689Skan}
5728169689Skan
5729169689Skan/* Generate insns for VEC_COND_EXPR.  */
5730169689Skan
5731169689Skanrtx
5732169689Skanexpand_vec_cond_expr (tree vec_cond_expr, rtx target)
5733169689Skan{
5734169689Skan  enum insn_code icode;
5735169689Skan  rtx comparison, rtx_op1, rtx_op2, cc_op0, cc_op1;
5736169689Skan  enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_cond_expr));
5737169689Skan  bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (vec_cond_expr));
5738169689Skan
5739169689Skan  icode = get_vcond_icode (vec_cond_expr, mode);
5740169689Skan  if (icode == CODE_FOR_nothing)
5741169689Skan    return 0;
5742169689Skan
5743169689Skan  if (!target || !insn_data[icode].operand[0].predicate (target, mode))
5744169689Skan    target = gen_reg_rtx (mode);
5745169689Skan
5746169689Skan  /* Get comparison rtx.  First expand both cond expr operands.  */
5747169689Skan  comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0),
5748169689Skan				   unsignedp, icode);
5749169689Skan  cc_op0 = XEXP (comparison, 0);
5750169689Skan  cc_op1 = XEXP (comparison, 1);
5751169689Skan  /* Expand both operands and force them in reg, if required.  */
5752169689Skan  rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1),
5753169689Skan			 NULL_RTX, VOIDmode, EXPAND_NORMAL);
5754169689Skan  if (!insn_data[icode].operand[1].predicate (rtx_op1, mode)
5755169689Skan      && mode != VOIDmode)
5756169689Skan    rtx_op1 = force_reg (mode, rtx_op1);
5757169689Skan
5758169689Skan  rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2),
5759169689Skan			 NULL_RTX, VOIDmode, EXPAND_NORMAL);
5760169689Skan  if (!insn_data[icode].operand[2].predicate (rtx_op2, mode)
5761169689Skan      && mode != VOIDmode)
5762169689Skan    rtx_op2 = force_reg (mode, rtx_op2);
5763169689Skan
5764169689Skan  /* Emit instruction! */
5765169689Skan  emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2,
5766169689Skan			      comparison, cc_op0,  cc_op1));
5767169689Skan
5768169689Skan  return target;
5769169689Skan}
5770169689Skan
5771169689Skan
5772169689Skan/* This is an internal subroutine of the other compare_and_swap expanders.
5773169689Skan   MEM, OLD_VAL and NEW_VAL are as you'd expect for a compare-and-swap
5774169689Skan   operation.  TARGET is an optional place to store the value result of
5775169689Skan   the operation.  ICODE is the particular instruction to expand.  Return
5776169689Skan   the result of the operation.  */
5777169689Skan
5778169689Skanstatic rtx
5779169689Skanexpand_val_compare_and_swap_1 (rtx mem, rtx old_val, rtx new_val,
5780169689Skan			       rtx target, enum insn_code icode)
5781169689Skan{
5782169689Skan  enum machine_mode mode = GET_MODE (mem);
5783169689Skan  rtx insn;
5784169689Skan
5785169689Skan  if (!target || !insn_data[icode].operand[0].predicate (target, mode))
5786169689Skan    target = gen_reg_rtx (mode);
5787169689Skan
5788169689Skan  if (GET_MODE (old_val) != VOIDmode && GET_MODE (old_val) != mode)
5789169689Skan    old_val = convert_modes (mode, GET_MODE (old_val), old_val, 1);
5790169689Skan  if (!insn_data[icode].operand[2].predicate (old_val, mode))
5791169689Skan    old_val = force_reg (mode, old_val);
5792169689Skan
5793169689Skan  if (GET_MODE (new_val) != VOIDmode && GET_MODE (new_val) != mode)
5794169689Skan    new_val = convert_modes (mode, GET_MODE (new_val), new_val, 1);
5795169689Skan  if (!insn_data[icode].operand[3].predicate (new_val, mode))
5796169689Skan    new_val = force_reg (mode, new_val);
5797169689Skan
5798169689Skan  insn = GEN_FCN (icode) (target, mem, old_val, new_val);
5799169689Skan  if (insn == NULL_RTX)
5800169689Skan    return NULL_RTX;
5801169689Skan  emit_insn (insn);
5802169689Skan
5803169689Skan  return target;
5804169689Skan}
5805169689Skan
5806169689Skan/* Expand a compare-and-swap operation and return its value.  */
5807169689Skan
5808169689Skanrtx
5809169689Skanexpand_val_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
5810169689Skan{
5811169689Skan  enum machine_mode mode = GET_MODE (mem);
5812169689Skan  enum insn_code icode = sync_compare_and_swap[mode];
5813169689Skan
5814169689Skan  if (icode == CODE_FOR_nothing)
5815169689Skan    return NULL_RTX;
5816169689Skan
5817169689Skan  return expand_val_compare_and_swap_1 (mem, old_val, new_val, target, icode);
5818169689Skan}
5819169689Skan
5820169689Skan/* Expand a compare-and-swap operation and store true into the result if
5821169689Skan   the operation was successful and false otherwise.  Return the result.
5822169689Skan   Unlike other routines, TARGET is not optional.  */
5823169689Skan
5824169689Skanrtx
5825169689Skanexpand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
5826169689Skan{
5827169689Skan  enum machine_mode mode = GET_MODE (mem);
5828169689Skan  enum insn_code icode;
5829169689Skan  rtx subtarget, label0, label1;
5830169689Skan
5831169689Skan  /* If the target supports a compare-and-swap pattern that simultaneously
5832169689Skan     sets some flag for success, then use it.  Otherwise use the regular
5833169689Skan     compare-and-swap and follow that immediately with a compare insn.  */
5834169689Skan  icode = sync_compare_and_swap_cc[mode];
5835169689Skan  switch (icode)
5836169689Skan    {
5837169689Skan    default:
5838169689Skan      subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
5839169689Skan						 NULL_RTX, icode);
5840169689Skan      if (subtarget != NULL_RTX)
5841169689Skan	break;
5842169689Skan
5843169689Skan      /* FALLTHRU */
5844169689Skan    case CODE_FOR_nothing:
5845169689Skan      icode = sync_compare_and_swap[mode];
5846169689Skan      if (icode == CODE_FOR_nothing)
5847169689Skan	return NULL_RTX;
5848169689Skan
5849169689Skan      /* Ensure that if old_val == mem, that we're not comparing
5850169689Skan	 against an old value.  */
5851169689Skan      if (MEM_P (old_val))
5852169689Skan	old_val = force_reg (mode, old_val);
5853169689Skan
5854169689Skan      subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
5855169689Skan						 NULL_RTX, icode);
5856169689Skan      if (subtarget == NULL_RTX)
5857169689Skan	return NULL_RTX;
5858169689Skan
5859169689Skan      emit_cmp_insn (subtarget, old_val, EQ, const0_rtx, mode, true);
5860169689Skan    }
5861169689Skan
5862169689Skan  /* If the target has a sane STORE_FLAG_VALUE, then go ahead and use a
5863169689Skan     setcc instruction from the beginning.  We don't work too hard here,
5864169689Skan     but it's nice to not be stupid about initial code gen either.  */
5865169689Skan  if (STORE_FLAG_VALUE == 1)
5866169689Skan    {
5867169689Skan      icode = setcc_gen_code[EQ];
5868169689Skan      if (icode != CODE_FOR_nothing)
5869169689Skan	{
5870169689Skan	  enum machine_mode cmode = insn_data[icode].operand[0].mode;
5871169689Skan	  rtx insn;
5872169689Skan
5873169689Skan	  subtarget = target;
5874169689Skan	  if (!insn_data[icode].operand[0].predicate (target, cmode))
5875169689Skan	    subtarget = gen_reg_rtx (cmode);
5876169689Skan
5877169689Skan	  insn = GEN_FCN (icode) (subtarget);
5878169689Skan	  if (insn)
5879169689Skan	    {
5880169689Skan	      emit_insn (insn);
5881169689Skan	      if (GET_MODE (target) != GET_MODE (subtarget))
5882169689Skan		{
5883169689Skan	          convert_move (target, subtarget, 1);
5884169689Skan		  subtarget = target;
5885169689Skan		}
5886169689Skan	      return subtarget;
5887169689Skan	    }
5888169689Skan	}
5889169689Skan    }
5890169689Skan
5891169689Skan  /* Without an appropriate setcc instruction, use a set of branches to
5892169689Skan     get 1 and 0 stored into target.  Presumably if the target has a
5893169689Skan     STORE_FLAG_VALUE that isn't 1, then this will get cleaned up by ifcvt.  */
5894169689Skan
5895169689Skan  label0 = gen_label_rtx ();
5896169689Skan  label1 = gen_label_rtx ();
5897169689Skan
5898169689Skan  emit_jump_insn (bcc_gen_fctn[EQ] (label0));
5899169689Skan  emit_move_insn (target, const0_rtx);
5900169689Skan  emit_jump_insn (gen_jump (label1));
5901169689Skan  emit_barrier ();
5902169689Skan  emit_label (label0);
5903169689Skan  emit_move_insn (target, const1_rtx);
5904169689Skan  emit_label (label1);
5905169689Skan
5906169689Skan  return target;
5907169689Skan}
5908169689Skan
5909169689Skan/* This is a helper function for the other atomic operations.  This function
5910169689Skan   emits a loop that contains SEQ that iterates until a compare-and-swap
5911169689Skan   operation at the end succeeds.  MEM is the memory to be modified.  SEQ is
5912169689Skan   a set of instructions that takes a value from OLD_REG as an input and
5913169689Skan   produces a value in NEW_REG as an output.  Before SEQ, OLD_REG will be
5914169689Skan   set to the current contents of MEM.  After SEQ, a compare-and-swap will
5915169689Skan   attempt to update MEM with NEW_REG.  The function returns true when the
5916169689Skan   loop was generated successfully.  */
5917169689Skan
5918169689Skanstatic bool
5919169689Skanexpand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
5920169689Skan{
5921169689Skan  enum machine_mode mode = GET_MODE (mem);
5922169689Skan  enum insn_code icode;
5923169689Skan  rtx label, cmp_reg, subtarget;
5924169689Skan
5925169689Skan  /* The loop we want to generate looks like
5926169689Skan
5927169689Skan	cmp_reg = mem;
5928169689Skan      label:
5929169689Skan        old_reg = cmp_reg;
5930169689Skan	seq;
5931169689Skan	cmp_reg = compare-and-swap(mem, old_reg, new_reg)
5932169689Skan	if (cmp_reg != old_reg)
5933169689Skan	  goto label;
5934169689Skan
5935169689Skan     Note that we only do the plain load from memory once.  Subsequent
5936169689Skan     iterations use the value loaded by the compare-and-swap pattern.  */
5937169689Skan
5938169689Skan  label = gen_label_rtx ();
5939169689Skan  cmp_reg = gen_reg_rtx (mode);
5940169689Skan
5941169689Skan  emit_move_insn (cmp_reg, mem);
5942169689Skan  emit_label (label);
5943169689Skan  emit_move_insn (old_reg, cmp_reg);
5944169689Skan  if (seq)
5945169689Skan    emit_insn (seq);
5946169689Skan
5947169689Skan  /* If the target supports a compare-and-swap pattern that simultaneously
5948169689Skan     sets some flag for success, then use it.  Otherwise use the regular
5949169689Skan     compare-and-swap and follow that immediately with a compare insn.  */
5950169689Skan  icode = sync_compare_and_swap_cc[mode];
5951169689Skan  switch (icode)
5952169689Skan    {
5953169689Skan    default:
5954169689Skan      subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
5955169689Skan						 cmp_reg, icode);
5956169689Skan      if (subtarget != NULL_RTX)
5957169689Skan	{
5958169689Skan	  gcc_assert (subtarget == cmp_reg);
5959169689Skan	  break;
5960169689Skan	}
5961169689Skan
5962169689Skan      /* FALLTHRU */
5963169689Skan    case CODE_FOR_nothing:
5964169689Skan      icode = sync_compare_and_swap[mode];
5965169689Skan      if (icode == CODE_FOR_nothing)
5966169689Skan	return false;
5967169689Skan
5968169689Skan      subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
5969169689Skan						 cmp_reg, icode);
5970169689Skan      if (subtarget == NULL_RTX)
5971169689Skan	return false;
5972169689Skan      if (subtarget != cmp_reg)
5973169689Skan	emit_move_insn (cmp_reg, subtarget);
5974169689Skan
5975169689Skan      emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true);
5976169689Skan    }
5977169689Skan
5978169689Skan  /* ??? Mark this jump predicted not taken?  */
5979169689Skan  emit_jump_insn (bcc_gen_fctn[NE] (label));
5980169689Skan
5981169689Skan  return true;
5982169689Skan}
5983169689Skan
5984169689Skan/* This function generates the atomic operation MEM CODE= VAL.  In this
5985169689Skan   case, we do not care about any resulting value.  Returns NULL if we
5986169689Skan   cannot generate the operation.  */
5987169689Skan
5988169689Skanrtx
5989169689Skanexpand_sync_operation (rtx mem, rtx val, enum rtx_code code)
5990169689Skan{
5991169689Skan  enum machine_mode mode = GET_MODE (mem);
5992169689Skan  enum insn_code icode;
5993169689Skan  rtx insn;
5994169689Skan
5995169689Skan  /* Look to see if the target supports the operation directly.  */
5996169689Skan  switch (code)
5997169689Skan    {
5998169689Skan    case PLUS:
5999169689Skan      icode = sync_add_optab[mode];
6000169689Skan      break;
6001169689Skan    case IOR:
6002169689Skan      icode = sync_ior_optab[mode];
6003169689Skan      break;
6004169689Skan    case XOR:
6005169689Skan      icode = sync_xor_optab[mode];
6006169689Skan      break;
6007169689Skan    case AND:
6008169689Skan      icode = sync_and_optab[mode];
6009169689Skan      break;
6010169689Skan    case NOT:
6011169689Skan      icode = sync_nand_optab[mode];
6012169689Skan      break;
6013169689Skan
6014169689Skan    case MINUS:
6015169689Skan      icode = sync_sub_optab[mode];
6016169689Skan      if (icode == CODE_FOR_nothing)
6017169689Skan	{
6018169689Skan	  icode = sync_add_optab[mode];
6019169689Skan	  if (icode != CODE_FOR_nothing)
6020169689Skan	    {
6021169689Skan	      val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1);
6022169689Skan	      code = PLUS;
6023169689Skan	    }
6024169689Skan	}
6025169689Skan      break;
6026169689Skan
6027169689Skan    default:
6028169689Skan      gcc_unreachable ();
6029169689Skan    }
6030169689Skan
6031169689Skan  /* Generate the direct operation, if present.  */
6032169689Skan  if (icode != CODE_FOR_nothing)
6033169689Skan    {
6034169689Skan      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
6035169689Skan	val = convert_modes (mode, GET_MODE (val), val, 1);
6036169689Skan      if (!insn_data[icode].operand[1].predicate (val, mode))
6037169689Skan	val = force_reg (mode, val);
6038169689Skan
6039169689Skan      insn = GEN_FCN (icode) (mem, val);
6040169689Skan      if (insn)
6041169689Skan	{
6042169689Skan	  emit_insn (insn);
6043169689Skan	  return const0_rtx;
6044169689Skan	}
6045169689Skan    }
6046169689Skan
6047169689Skan  /* Failing that, generate a compare-and-swap loop in which we perform the
6048169689Skan     operation with normal arithmetic instructions.  */
6049169689Skan  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
6050169689Skan    {
6051169689Skan      rtx t0 = gen_reg_rtx (mode), t1;
6052169689Skan
6053169689Skan      start_sequence ();
6054169689Skan
6055169689Skan      t1 = t0;
6056169689Skan      if (code == NOT)
6057169689Skan	{
6058169689Skan	  t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true);
6059169689Skan	  code = AND;
6060169689Skan	}
6061169689Skan      t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX,
6062169689Skan				true, OPTAB_LIB_WIDEN);
6063169689Skan
6064169689Skan      insn = get_insns ();
6065169689Skan      end_sequence ();
6066169689Skan
6067169689Skan      if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn))
6068169689Skan	return const0_rtx;
6069169689Skan    }
6070169689Skan
6071169689Skan  return NULL_RTX;
6072169689Skan}
6073169689Skan
6074169689Skan/* This function generates the atomic operation MEM CODE= VAL.  In this
6075169689Skan   case, we do care about the resulting value: if AFTER is true then
6076169689Skan   return the value MEM holds after the operation, if AFTER is false
6077169689Skan   then return the value MEM holds before the operation.  TARGET is an
6078169689Skan   optional place for the result value to be stored.  */
6079169689Skan
6080169689Skanrtx
6081169689Skanexpand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code,
6082169689Skan			     bool after, rtx target)
6083169689Skan{
6084169689Skan  enum machine_mode mode = GET_MODE (mem);
6085169689Skan  enum insn_code old_code, new_code, icode;
6086169689Skan  bool compensate;
6087169689Skan  rtx insn;
6088169689Skan
6089169689Skan  /* Look to see if the target supports the operation directly.  */
6090169689Skan  switch (code)
6091169689Skan    {
6092169689Skan    case PLUS:
6093169689Skan      old_code = sync_old_add_optab[mode];
6094169689Skan      new_code = sync_new_add_optab[mode];
6095169689Skan      break;
6096169689Skan    case IOR:
6097169689Skan      old_code = sync_old_ior_optab[mode];
6098169689Skan      new_code = sync_new_ior_optab[mode];
6099169689Skan      break;
6100169689Skan    case XOR:
6101169689Skan      old_code = sync_old_xor_optab[mode];
6102169689Skan      new_code = sync_new_xor_optab[mode];
6103169689Skan      break;
6104169689Skan    case AND:
6105169689Skan      old_code = sync_old_and_optab[mode];
6106169689Skan      new_code = sync_new_and_optab[mode];
6107169689Skan      break;
6108169689Skan    case NOT:
6109169689Skan      old_code = sync_old_nand_optab[mode];
6110169689Skan      new_code = sync_new_nand_optab[mode];
6111169689Skan      break;
6112169689Skan
6113169689Skan    case MINUS:
6114169689Skan      old_code = sync_old_sub_optab[mode];
6115169689Skan      new_code = sync_new_sub_optab[mode];
6116169689Skan      if (old_code == CODE_FOR_nothing && new_code == CODE_FOR_nothing)
6117169689Skan	{
6118169689Skan	  old_code = sync_old_add_optab[mode];
6119169689Skan	  new_code = sync_new_add_optab[mode];
6120169689Skan	  if (old_code != CODE_FOR_nothing || new_code != CODE_FOR_nothing)
6121169689Skan	    {
6122169689Skan	      val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1);
6123169689Skan	      code = PLUS;
6124169689Skan	    }
6125169689Skan	}
6126169689Skan      break;
6127169689Skan
6128169689Skan    default:
6129169689Skan      gcc_unreachable ();
6130169689Skan    }
6131169689Skan
6132169689Skan  /* If the target does supports the proper new/old operation, great.  But
6133169689Skan     if we only support the opposite old/new operation, check to see if we
6134169689Skan     can compensate.  In the case in which the old value is supported, then
6135169689Skan     we can always perform the operation again with normal arithmetic.  In
6136169689Skan     the case in which the new value is supported, then we can only handle
6137169689Skan     this in the case the operation is reversible.  */
6138169689Skan  compensate = false;
6139169689Skan  if (after)
6140169689Skan    {
6141169689Skan      icode = new_code;
6142169689Skan      if (icode == CODE_FOR_nothing)
6143169689Skan	{
6144169689Skan	  icode = old_code;
6145169689Skan	  if (icode != CODE_FOR_nothing)
6146169689Skan	    compensate = true;
6147169689Skan	}
6148169689Skan    }
6149169689Skan  else
6150169689Skan    {
6151169689Skan      icode = old_code;
6152169689Skan      if (icode == CODE_FOR_nothing
6153169689Skan	  && (code == PLUS || code == MINUS || code == XOR))
6154169689Skan	{
6155169689Skan	  icode = new_code;
6156169689Skan	  if (icode != CODE_FOR_nothing)
6157169689Skan	    compensate = true;
6158169689Skan	}
6159169689Skan    }
6160169689Skan
6161169689Skan  /* If we found something supported, great.  */
6162169689Skan  if (icode != CODE_FOR_nothing)
6163169689Skan    {
6164169689Skan      if (!target || !insn_data[icode].operand[0].predicate (target, mode))
6165169689Skan	target = gen_reg_rtx (mode);
6166169689Skan
6167169689Skan      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
6168169689Skan	val = convert_modes (mode, GET_MODE (val), val, 1);
6169169689Skan      if (!insn_data[icode].operand[2].predicate (val, mode))
6170169689Skan	val = force_reg (mode, val);
6171169689Skan
6172169689Skan      insn = GEN_FCN (icode) (target, mem, val);
6173169689Skan      if (insn)
6174169689Skan	{
6175169689Skan	  emit_insn (insn);
6176169689Skan
6177169689Skan	  /* If we need to compensate for using an operation with the
6178169689Skan	     wrong return value, do so now.  */
6179169689Skan	  if (compensate)
6180169689Skan	    {
6181169689Skan	      if (!after)
6182169689Skan		{
6183169689Skan		  if (code == PLUS)
6184169689Skan		    code = MINUS;
6185169689Skan		  else if (code == MINUS)
6186169689Skan		    code = PLUS;
6187169689Skan		}
6188169689Skan
6189169689Skan	      if (code == NOT)
6190169689Skan		target = expand_simple_unop (mode, NOT, target, NULL_RTX, true);
6191169689Skan	      target = expand_simple_binop (mode, code, target, val, NULL_RTX,
6192169689Skan					    true, OPTAB_LIB_WIDEN);
6193169689Skan	    }
6194169689Skan
6195169689Skan	  return target;
6196169689Skan	}
6197169689Skan    }
6198169689Skan
6199169689Skan  /* Failing that, generate a compare-and-swap loop in which we perform the
6200169689Skan     operation with normal arithmetic instructions.  */
6201169689Skan  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
6202169689Skan    {
6203169689Skan      rtx t0 = gen_reg_rtx (mode), t1;
6204169689Skan
6205169689Skan      if (!target || !register_operand (target, mode))
6206169689Skan	target = gen_reg_rtx (mode);
6207169689Skan
6208169689Skan      start_sequence ();
6209169689Skan
6210169689Skan      if (!after)
6211169689Skan	emit_move_insn (target, t0);
6212169689Skan      t1 = t0;
6213169689Skan      if (code == NOT)
6214169689Skan	{
6215169689Skan	  t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true);
6216169689Skan	  code = AND;
6217169689Skan	}
6218169689Skan      t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX,
6219169689Skan				true, OPTAB_LIB_WIDEN);
6220169689Skan      if (after)
6221169689Skan	emit_move_insn (target, t1);
6222169689Skan
6223169689Skan      insn = get_insns ();
6224169689Skan      end_sequence ();
6225169689Skan
6226169689Skan      if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn))
6227169689Skan	return target;
6228169689Skan    }
6229169689Skan
6230169689Skan  return NULL_RTX;
6231169689Skan}
6232169689Skan
6233169689Skan/* This function expands a test-and-set operation.  Ideally we atomically
6234169689Skan   store VAL in MEM and return the previous value in MEM.  Some targets
6235169689Skan   may not support this operation and only support VAL with the constant 1;
6236169689Skan   in this case while the return value will be 0/1, but the exact value
6237169689Skan   stored in MEM is target defined.  TARGET is an option place to stick
6238169689Skan   the return value.  */
6239169689Skan
6240169689Skanrtx
6241169689Skanexpand_sync_lock_test_and_set (rtx mem, rtx val, rtx target)
6242169689Skan{
6243169689Skan  enum machine_mode mode = GET_MODE (mem);
6244169689Skan  enum insn_code icode;
6245169689Skan  rtx insn;
6246169689Skan
6247169689Skan  /* If the target supports the test-and-set directly, great.  */
6248169689Skan  icode = sync_lock_test_and_set[mode];
6249169689Skan  if (icode != CODE_FOR_nothing)
6250169689Skan    {
6251169689Skan      if (!target || !insn_data[icode].operand[0].predicate (target, mode))
6252169689Skan	target = gen_reg_rtx (mode);
6253169689Skan
6254169689Skan      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
6255169689Skan	val = convert_modes (mode, GET_MODE (val), val, 1);
6256169689Skan      if (!insn_data[icode].operand[2].predicate (val, mode))
6257169689Skan	val = force_reg (mode, val);
6258169689Skan
6259169689Skan      insn = GEN_FCN (icode) (target, mem, val);
6260169689Skan      if (insn)
6261169689Skan	{
6262169689Skan	  emit_insn (insn);
6263169689Skan	  return target;
6264169689Skan	}
6265169689Skan    }
6266169689Skan
6267169689Skan  /* Otherwise, use a compare-and-swap loop for the exchange.  */
6268169689Skan  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
6269169689Skan    {
6270169689Skan      if (!target || !register_operand (target, mode))
6271169689Skan	target = gen_reg_rtx (mode);
6272169689Skan      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
6273169689Skan	val = convert_modes (mode, GET_MODE (val), val, 1);
6274169689Skan      if (expand_compare_and_swap_loop (mem, target, val, NULL_RTX))
6275169689Skan	return target;
6276169689Skan    }
6277169689Skan
6278169689Skan  return NULL_RTX;
6279169689Skan}
6280169689Skan
6281117395Skan#include "gt-optabs.h"
6282