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
2594169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
2595169689Skan    for (wider_mode = GET_MODE_WIDER_MODE (mode);
2596169689Skan	 wider_mode != VOIDmode;
259718334Speter	 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
259818334Speter      {
259918334Speter	if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
260018334Speter	  {
260118334Speter	    rtx xop0 = op0;
260218334Speter
260318334Speter	    /* For certain operations, we need not actually extend
260418334Speter	       the narrow operand, as long as we will truncate the
260518334Speter	       results to the same narrowness.  */
260618334Speter
260718334Speter	    xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
260818334Speter				  (unoptab == neg_optab
260918334Speter				   || unoptab == one_cmpl_optab)
261018334Speter				  && class == MODE_INT);
2611132718Skan
261218334Speter	    temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
261318334Speter				unsignedp);
261418334Speter
261518334Speter	    if (temp)
261618334Speter	      {
2617169689Skan		if (class != MODE_INT
2618169689Skan		    || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
2619169689Skan					       GET_MODE_BITSIZE (wider_mode)))
262018334Speter		  {
262118334Speter		    if (target == 0)
262218334Speter		      target = gen_reg_rtx (mode);
262318334Speter		    convert_move (target, temp, 0);
262418334Speter		    return target;
262518334Speter		  }
262618334Speter		else
262718334Speter		  return gen_lowpart (mode, temp);
262818334Speter	      }
262918334Speter	    else
263018334Speter	      delete_insns_since (last);
263118334Speter	  }
263218334Speter      }
263318334Speter
263418334Speter  /* These can be done a word at a time.  */
263518334Speter  if (unoptab == one_cmpl_optab
263618334Speter      && class == MODE_INT
263718334Speter      && GET_MODE_SIZE (mode) > UNITS_PER_WORD
263818334Speter      && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
263918334Speter    {
264018334Speter      int i;
264118334Speter      rtx insns;
264218334Speter
264318334Speter      if (target == 0 || target == op0)
264418334Speter	target = gen_reg_rtx (mode);
264518334Speter
264618334Speter      start_sequence ();
264718334Speter
264818334Speter      /* Do the actual arithmetic.  */
264918334Speter      for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
265018334Speter	{
265118334Speter	  rtx target_piece = operand_subword (target, i, 1, mode);
265218334Speter	  rtx x = expand_unop (word_mode, unoptab,
265318334Speter			       operand_subword_force (op0, i, mode),
265418334Speter			       target_piece, unsignedp);
265590075Sobrien
265618334Speter	  if (target_piece != x)
265718334Speter	    emit_move_insn (target_piece, x);
265818334Speter	}
265918334Speter
266018334Speter      insns = get_insns ();
266118334Speter      end_sequence ();
266218334Speter
266318334Speter      emit_no_conflict_block (insns, target, op0, NULL_RTX,
266450397Sobrien			      gen_rtx_fmt_e (unoptab->code, mode,
266550397Sobrien					     copy_rtx (op0)));
266618334Speter      return target;
266718334Speter    }
266818334Speter
2669169689Skan  if (unoptab->code == NEG)
267018334Speter    {
2671169689Skan      /* Try negating floating point values by flipping the sign bit.  */
2672169689Skan      if (SCALAR_FLOAT_MODE_P (mode))
2673169689Skan	{
2674169689Skan	  temp = expand_absneg_bit (NEG, mode, op0, target);
2675169689Skan	  if (temp)
2676169689Skan	    return temp;
2677169689Skan	}
267818334Speter
2679169689Skan      /* If there is no negation pattern, and we have no negative zero,
2680169689Skan	 try subtracting from zero.  */
2681169689Skan      if (!HONOR_SIGNED_ZEROS (mode))
2682132718Skan	{
2683169689Skan	  temp = expand_binop (mode, (unoptab == negv_optab
2684169689Skan				      ? subv_optab : sub_optab),
2685169689Skan			       CONST0_RTX (mode), op0, target,
2686169689Skan			       unsignedp, OPTAB_DIRECT);
2687169689Skan	  if (temp)
2688169689Skan	    return temp;
2689169689Skan	}
2690132718Skan    }
2691132718Skan
2692132718Skan  /* Try calculating parity (x) as popcount (x) % 2.  */
2693132718Skan  if (unoptab == parity_optab)
2694132718Skan    {
2695132718Skan      temp = expand_parity (mode, op0, target);
2696132718Skan      if (temp)
2697132718Skan	return temp;
2698132718Skan    }
2699132718Skan
2700132718Skan try_libcall:
270118334Speter  /* Now try a library call in this mode.  */
270218334Speter  if (unoptab->handlers[(int) mode].libfunc)
270318334Speter    {
270418334Speter      rtx insns;
270518334Speter      rtx value;
2706132718Skan      enum machine_mode outmode = mode;
270718334Speter
2708132718Skan      /* All of these functions return small values.  Thus we choose to
2709132718Skan	 have them return something that isn't a double-word.  */
2710132718Skan      if (unoptab == ffs_optab || unoptab == clz_optab || unoptab == ctz_optab
2711132718Skan	  || unoptab == popcount_optab || unoptab == parity_optab)
2712132718Skan	outmode
2713132718Skan	    = GET_MODE (hard_libcall_value (TYPE_MODE (integer_type_node)));
2714132718Skan
271518334Speter      start_sequence ();
271618334Speter
271718334Speter      /* Pass 1 for NO_QUEUE so we don't lose any increments
271818334Speter	 if the libcall is cse'd or moved.  */
271918334Speter      value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
2720132718Skan				       NULL_RTX, LCT_CONST, outmode,
2721132718Skan				       1, op0, mode);
272218334Speter      insns = get_insns ();
272318334Speter      end_sequence ();
272418334Speter
2725132718Skan      target = gen_reg_rtx (outmode);
272618334Speter      emit_libcall_block (insns, target, value,
2727169689Skan			  gen_rtx_fmt_e (unoptab->code, outmode, op0));
272818334Speter
272918334Speter      return target;
273018334Speter    }
273118334Speter
273218334Speter  /* It can't be done in this mode.  Can we do it in a wider mode?  */
273318334Speter
2734169689Skan  if (CLASS_HAS_WIDER_MODES_P (class))
273518334Speter    {
2736169689Skan      for (wider_mode = GET_MODE_WIDER_MODE (mode);
2737169689Skan	   wider_mode != VOIDmode;
273818334Speter	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
273918334Speter	{
274018334Speter	  if ((unoptab->handlers[(int) wider_mode].insn_code
274118334Speter	       != CODE_FOR_nothing)
274218334Speter	      || unoptab->handlers[(int) wider_mode].libfunc)
274318334Speter	    {
274418334Speter	      rtx xop0 = op0;
274518334Speter
274618334Speter	      /* For certain operations, we need not actually extend
274718334Speter		 the narrow operand, as long as we will truncate the
274818334Speter		 results to the same narrowness.  */
274918334Speter
275018334Speter	      xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
275118334Speter				    (unoptab == neg_optab
275218334Speter				     || unoptab == one_cmpl_optab)
275318334Speter				    && class == MODE_INT);
2754132718Skan
275518334Speter	      temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
275618334Speter				  unsignedp);
275718334Speter
2758132718Skan	      /* If we are generating clz using wider mode, adjust the
2759132718Skan		 result.  */
2760132718Skan	      if (unoptab == clz_optab && temp != 0)
2761132718Skan		temp = expand_binop (wider_mode, sub_optab, temp,
2762132718Skan				     GEN_INT (GET_MODE_BITSIZE (wider_mode)
2763132718Skan					      - GET_MODE_BITSIZE (mode)),
2764132718Skan				     target, true, OPTAB_DIRECT);
2765132718Skan
276618334Speter	      if (temp)
276718334Speter		{
276818334Speter		  if (class != MODE_INT)
276918334Speter		    {
277018334Speter		      if (target == 0)
277118334Speter			target = gen_reg_rtx (mode);
277218334Speter		      convert_move (target, temp, 0);
277318334Speter		      return target;
277418334Speter		    }
277518334Speter		  else
277618334Speter		    return gen_lowpart (mode, temp);
277718334Speter		}
277818334Speter	      else
277918334Speter		delete_insns_since (last);
278018334Speter	    }
278118334Speter	}
278218334Speter    }
278318334Speter
2784169689Skan  /* One final attempt at implementing negation via subtraction,
2785169689Skan     this time allowing widening of the operand.  */
2786169689Skan  if (unoptab->code == NEG && !HONOR_SIGNED_ZEROS (mode))
2787132718Skan    {
278818334Speter      rtx temp;
278990075Sobrien      temp = expand_binop (mode,
279090075Sobrien                           unoptab == negv_optab ? subv_optab : sub_optab,
279190075Sobrien                           CONST0_RTX (mode), op0,
279290075Sobrien                           target, unsignedp, OPTAB_LIB_WIDEN);
279318334Speter      if (temp)
2794169689Skan        return temp;
279518334Speter    }
2796132718Skan
279718334Speter  return 0;
279818334Speter}
279918334Speter
280018334Speter/* Emit code to compute the absolute value of OP0, with result to
280118334Speter   TARGET if convenient.  (TARGET may be 0.)  The return value says
280218334Speter   where the result actually is to be found.
280318334Speter
280418334Speter   MODE is the mode of the operand; the mode of the result is
280518334Speter   different but can be deduced from MODE.
280618334Speter
280752284Sobrien */
280818334Speter
280918334Speterrtx
2810132718Skanexpand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
2811132718Skan		   int result_unsignedp)
281218334Speter{
2813132718Skan  rtx temp;
281418334Speter
281590075Sobrien  if (! flag_trapv)
281690075Sobrien    result_unsignedp = 1;
281790075Sobrien
281818334Speter  /* First try to do it with a special abs instruction.  */
281990075Sobrien  temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab,
282090075Sobrien                      op0, target, 0);
282118334Speter  if (temp != 0)
282218334Speter    return temp;
282318334Speter
2824132718Skan  /* For floating point modes, try clearing the sign bit.  */
2825169689Skan  if (SCALAR_FLOAT_MODE_P (mode))
2826132718Skan    {
2827169689Skan      temp = expand_absneg_bit (ABS, mode, op0, target);
2828169689Skan      if (temp)
2829169689Skan	return temp;
2830132718Skan    }
2831132718Skan
283290075Sobrien  /* If we have a MAX insn, we can do this as MAX (x, -x).  */
2833169689Skan  if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
2834169689Skan      && !HONOR_SIGNED_ZEROS (mode))
283590075Sobrien    {
283690075Sobrien      rtx last = get_last_insn ();
283790075Sobrien
283890075Sobrien      temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0);
283990075Sobrien      if (temp != 0)
284090075Sobrien	temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
284190075Sobrien			     OPTAB_WIDEN);
284290075Sobrien
284390075Sobrien      if (temp != 0)
284490075Sobrien	return temp;
284590075Sobrien
284690075Sobrien      delete_insns_since (last);
284790075Sobrien    }
284890075Sobrien
284918334Speter  /* If this machine has expensive jumps, we can do integer absolute
285018334Speter     value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
285118334Speter     where W is the width of MODE.  */
285218334Speter
285318334Speter  if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
285418334Speter    {
285518334Speter      rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
285618334Speter				   size_int (GET_MODE_BITSIZE (mode) - 1),
285718334Speter				   NULL_RTX, 0);
285818334Speter
285918334Speter      temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
286018334Speter			   OPTAB_LIB_WIDEN);
286118334Speter      if (temp != 0)
286290075Sobrien	temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab,
286390075Sobrien                             temp, extended, target, 0, OPTAB_LIB_WIDEN);
286418334Speter
286518334Speter      if (temp != 0)
286618334Speter	return temp;
286718334Speter    }
286818334Speter
2869132718Skan  return NULL_RTX;
2870132718Skan}
2871132718Skan
2872132718Skanrtx
2873132718Skanexpand_abs (enum machine_mode mode, rtx op0, rtx target,
2874132718Skan	    int result_unsignedp, int safe)
2875132718Skan{
2876132718Skan  rtx temp, op1;
2877132718Skan
2878132718Skan  if (! flag_trapv)
2879132718Skan    result_unsignedp = 1;
2880132718Skan
2881132718Skan  temp = expand_abs_nojump (mode, op0, target, result_unsignedp);
2882132718Skan  if (temp != 0)
2883132718Skan    return temp;
2884132718Skan
288518334Speter  /* If that does not win, use conditional jump and negate.  */
288650397Sobrien
288750397Sobrien  /* It is safe to use the target if it is the same
288850397Sobrien     as the source if this is also a pseudo register */
2889169689Skan  if (op0 == target && REG_P (op0)
289050397Sobrien      && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
289150397Sobrien    safe = 1;
289250397Sobrien
289318334Speter  op1 = gen_label_rtx ();
289418334Speter  if (target == 0 || ! safe
289518334Speter      || GET_MODE (target) != mode
2896169689Skan      || (MEM_P (target) && MEM_VOLATILE_P (target))
2897169689Skan      || (REG_P (target)
289818334Speter	  && REGNO (target) < FIRST_PSEUDO_REGISTER))
289918334Speter    target = gen_reg_rtx (mode);
290018334Speter
290118334Speter  emit_move_insn (target, op0);
290218334Speter  NO_DEFER_POP;
290318334Speter
2904169689Skan  do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
2905169689Skan			   NULL_RTX, NULL_RTX, op1);
290618334Speter
290790075Sobrien  op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
290890075Sobrien                     target, target, 0);
290918334Speter  if (op0 != target)
291018334Speter    emit_move_insn (target, op0);
291118334Speter  emit_label (op1);
291218334Speter  OK_DEFER_POP;
291318334Speter  return target;
291418334Speter}
291518334Speter
2916169689Skan/* A subroutine of expand_copysign, perform the copysign operation using the
2917169689Skan   abs and neg primitives advertised to exist on the target.  The assumption
2918169689Skan   is that we have a split register file, and leaving op0 in fp registers,
2919169689Skan   and not playing with subregs so much, will help the register allocator.  */
292018334Speter
2921169689Skanstatic rtx
2922169689Skanexpand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
2923169689Skan		        int bitpos, bool op0_is_abs)
292418334Speter{
2925169689Skan  enum machine_mode imode;
2926169689Skan  HOST_WIDE_INT hi, lo;
2927169689Skan  int word;
2928169689Skan  rtx label;
292918334Speter
2930169689Skan  if (target == op1)
2931169689Skan    target = NULL_RTX;
293218334Speter
2933169689Skan  if (!op0_is_abs)
2934169689Skan    {
2935169689Skan      op0 = expand_unop (mode, abs_optab, op0, target, 0);
2936169689Skan      if (op0 == NULL)
2937169689Skan	return NULL_RTX;
2938169689Skan      target = op0;
2939169689Skan    }
2940169689Skan  else
2941169689Skan    {
2942169689Skan      if (target == NULL_RTX)
2943169689Skan        target = copy_to_reg (op0);
2944169689Skan      else
2945169689Skan	emit_move_insn (target, op0);
2946169689Skan    }
294718334Speter
2948169689Skan  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2949169689Skan    {
2950169689Skan      imode = int_mode_for_mode (mode);
2951169689Skan      if (imode == BLKmode)
2952169689Skan	return NULL_RTX;
2953169689Skan      op1 = gen_lowpart (imode, op1);
2954169689Skan    }
2955169689Skan  else
2956169689Skan    {
2957169689Skan      imode = word_mode;
2958169689Skan      if (FLOAT_WORDS_BIG_ENDIAN)
2959169689Skan	word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD;
2960169689Skan      else
2961169689Skan	word = bitpos / BITS_PER_WORD;
2962169689Skan      bitpos = bitpos % BITS_PER_WORD;
2963169689Skan      op1 = operand_subword_force (op1, word, mode);
2964169689Skan    }
296518334Speter
2966169689Skan  if (bitpos < HOST_BITS_PER_WIDE_INT)
296718334Speter    {
2968169689Skan      hi = 0;
2969169689Skan      lo = (HOST_WIDE_INT) 1 << bitpos;
297018334Speter    }
2971169689Skan  else
2972169689Skan    {
2973169689Skan      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
2974169689Skan      lo = 0;
2975169689Skan    }
297618334Speter
2977169689Skan  op1 = expand_binop (imode, and_optab, op1,
2978169689Skan		      immed_double_const (lo, hi, imode),
2979169689Skan		      NULL_RTX, 1, OPTAB_LIB_WIDEN);
298018334Speter
2981169689Skan  label = gen_label_rtx ();
2982169689Skan  emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, imode, 1, label);
298318334Speter
2984169689Skan  if (GET_CODE (op0) == CONST_DOUBLE)
2985169689Skan    op0 = simplify_unary_operation (NEG, mode, op0, mode);
2986169689Skan  else
2987169689Skan    op0 = expand_unop (mode, neg_optab, op0, target, 0);
2988169689Skan  if (op0 != target)
2989169689Skan    emit_move_insn (target, op0);
299090075Sobrien
2991169689Skan  emit_label (label);
299218334Speter
2993169689Skan  return target;
2994169689Skan}
299518334Speter
299618334Speter
2997169689Skan/* A subroutine of expand_copysign, perform the entire copysign operation
2998169689Skan   with integer bitmasks.  BITPOS is the position of the sign bit; OP0_IS_ABS
2999169689Skan   is true if op0 is known to have its sign bit clear.  */
300018334Speter
3001169689Skanstatic rtx
3002169689Skanexpand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
3003169689Skan		     int bitpos, bool op0_is_abs)
3004169689Skan{
3005169689Skan  enum machine_mode imode;
3006169689Skan  HOST_WIDE_INT hi, lo;
3007169689Skan  int word, nwords, i;
3008169689Skan  rtx temp, insns;
300918334Speter
3010169689Skan  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
3011169689Skan    {
3012169689Skan      imode = int_mode_for_mode (mode);
3013169689Skan      if (imode == BLKmode)
3014169689Skan	return NULL_RTX;
3015169689Skan      word = 0;
3016169689Skan      nwords = 1;
3017169689Skan    }
3018169689Skan  else
3019169689Skan    {
3020169689Skan      imode = word_mode;
302118334Speter
3022169689Skan      if (FLOAT_WORDS_BIG_ENDIAN)
3023169689Skan	word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD;
302418334Speter      else
3025169689Skan	word = bitpos / BITS_PER_WORD;
3026169689Skan      bitpos = bitpos % BITS_PER_WORD;
3027169689Skan      nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
302818334Speter    }
302918334Speter
3030169689Skan  if (bitpos < HOST_BITS_PER_WIDE_INT)
3031169689Skan    {
3032169689Skan      hi = 0;
3033169689Skan      lo = (HOST_WIDE_INT) 1 << bitpos;
3034169689Skan    }
3035169689Skan  else
3036169689Skan    {
3037169689Skan      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
3038169689Skan      lo = 0;
3039169689Skan    }
304018334Speter
3041169689Skan  if (target == 0 || target == op0 || target == op1)
3042169689Skan    target = gen_reg_rtx (mode);
3043169689Skan
3044169689Skan  if (nwords > 1)
304518334Speter    {
3046169689Skan      start_sequence ();
3047169689Skan
3048169689Skan      for (i = 0; i < nwords; ++i)
304918334Speter	{
3050169689Skan	  rtx targ_piece = operand_subword (target, i, 1, mode);
3051169689Skan	  rtx op0_piece = operand_subword_force (op0, i, mode);
305218334Speter
3053169689Skan	  if (i == word)
3054169689Skan	    {
3055169689Skan	      if (!op0_is_abs)
3056169689Skan		op0_piece = expand_binop (imode, and_optab, op0_piece,
3057169689Skan					  immed_double_const (~lo, ~hi, imode),
3058169689Skan					  NULL_RTX, 1, OPTAB_LIB_WIDEN);
305918334Speter
3060169689Skan	      op1 = expand_binop (imode, and_optab,
3061169689Skan				  operand_subword_force (op1, i, mode),
3062169689Skan				  immed_double_const (lo, hi, imode),
3063169689Skan				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
3064169689Skan
3065169689Skan	      temp = expand_binop (imode, ior_optab, op0_piece, op1,
3066169689Skan				   targ_piece, 1, OPTAB_LIB_WIDEN);
3067169689Skan	      if (temp != targ_piece)
3068169689Skan		emit_move_insn (targ_piece, temp);
306918334Speter	    }
307018334Speter	  else
3071169689Skan	    emit_move_insn (targ_piece, op0_piece);
307218334Speter	}
3073169689Skan
3074169689Skan      insns = get_insns ();
3075169689Skan      end_sequence ();
3076169689Skan
3077169689Skan      emit_no_conflict_block (insns, target, op0, op1, NULL_RTX);
307818334Speter    }
3079169689Skan  else
308018334Speter    {
3081169689Skan      op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
3082169689Skan		          immed_double_const (lo, hi, imode),
3083169689Skan		          NULL_RTX, 1, OPTAB_LIB_WIDEN);
308418334Speter
3085169689Skan      op0 = gen_lowpart (imode, op0);
3086169689Skan      if (!op0_is_abs)
3087169689Skan	op0 = expand_binop (imode, and_optab, op0,
3088169689Skan			    immed_double_const (~lo, ~hi, imode),
3089169689Skan			    NULL_RTX, 1, OPTAB_LIB_WIDEN);
309018334Speter
3091169689Skan      temp = expand_binop (imode, ior_optab, op0, op1,
3092169689Skan			   gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
3093169689Skan      target = lowpart_subreg_maybe_copy (mode, temp, imode);
3094169689Skan    }
309518334Speter
3096169689Skan  return target;
3097169689Skan}
309818334Speter
3099169689Skan/* Expand the C99 copysign operation.  OP0 and OP1 must be the same
3100169689Skan   scalar floating point mode.  Return NULL if we do not know how to
3101169689Skan   expand the operation inline.  */
310218334Speter
3103169689Skanrtx
3104169689Skanexpand_copysign (rtx op0, rtx op1, rtx target)
3105169689Skan{
3106169689Skan  enum machine_mode mode = GET_MODE (op0);
3107169689Skan  const struct real_format *fmt;
3108169689Skan  bool op0_is_abs;
3109169689Skan  rtx temp;
311018334Speter
3111169689Skan  gcc_assert (SCALAR_FLOAT_MODE_P (mode));
3112169689Skan  gcc_assert (GET_MODE (op1) == mode);
311318334Speter
3114169689Skan  /* First try to do it with a special instruction.  */
3115169689Skan  temp = expand_binop (mode, copysign_optab, op0, op1,
3116169689Skan		       target, 0, OPTAB_DIRECT);
3117169689Skan  if (temp)
3118169689Skan    return temp;
311918334Speter
3120169689Skan  fmt = REAL_MODE_FORMAT (mode);
3121169689Skan  if (fmt == NULL || !fmt->has_signed_zero)
3122169689Skan    return NULL_RTX;
312318334Speter
3124169689Skan  op0_is_abs = false;
3125169689Skan  if (GET_CODE (op0) == CONST_DOUBLE)
3126169689Skan    {
3127169689Skan      if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0)))
3128169689Skan	op0 = simplify_unary_operation (ABS, mode, op0, mode);
3129169689Skan      op0_is_abs = true;
313018334Speter    }
313118334Speter
3132169689Skan  if (fmt->signbit_ro >= 0
3133169689Skan      && (GET_CODE (op0) == CONST_DOUBLE
3134169689Skan	  || (neg_optab->handlers[mode].insn_code != CODE_FOR_nothing
3135169689Skan	      && abs_optab->handlers[mode].insn_code != CODE_FOR_nothing)))
313618334Speter    {
3137169689Skan      temp = expand_copysign_absneg (mode, op0, op1, target,
3138169689Skan				     fmt->signbit_ro, op0_is_abs);
3139169689Skan      if (temp)
3140169689Skan	return temp;
314118334Speter    }
314218334Speter
3143169689Skan  if (fmt->signbit_rw < 0)
3144169689Skan    return NULL_RTX;
3145169689Skan  return expand_copysign_bit (mode, op0, op1, target,
3146169689Skan			      fmt->signbit_rw, op0_is_abs);
314718334Speter}
314818334Speter
314918334Speter/* Generate an instruction whose insn-code is INSN_CODE,
315018334Speter   with two operands: an output TARGET and an input OP0.
315118334Speter   TARGET *must* be nonzero, and the output is always stored there.
315218334Speter   CODE is an rtx code such that (CODE OP0) is an rtx that describes
315318334Speter   the value that is stored into TARGET.  */
315418334Speter
315518334Spetervoid
3156132718Skanemit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code)
315718334Speter{
315890075Sobrien  rtx temp;
315990075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
316018334Speter  rtx pat;
316118334Speter
3162169689Skan  temp = target;
316318334Speter
316418334Speter  /* Now, if insn does not accept our operands, put them into pseudos.  */
316518334Speter
3166169689Skan  if (!insn_data[icode].operand[1].predicate (op0, mode0))
316718334Speter    op0 = copy_to_mode_reg (mode0, op0);
316818334Speter
3169169689Skan  if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp)))
317018334Speter    temp = gen_reg_rtx (GET_MODE (temp));
317118334Speter
317218334Speter  pat = GEN_FCN (icode) (temp, op0);
317318334Speter
3174117395Skan  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN)
317518334Speter    add_equal_note (pat, temp, code, op0, NULL_RTX);
3176132718Skan
317718334Speter  emit_insn (pat);
317818334Speter
317918334Speter  if (temp != target)
318018334Speter    emit_move_insn (target, temp);
318118334Speter}
318218334Speter
3183169689Skanstruct no_conflict_data
3184169689Skan{
3185169689Skan  rtx target, first, insn;
3186169689Skan  bool must_stay;
3187169689Skan};
3188169689Skan
3189169689Skan/* Called via note_stores by emit_no_conflict_block and emit_libcall_block.
3190169689Skan   Set P->must_stay if the currently examined clobber / store has to stay
3191169689Skan   in the list of insns that constitute the actual no_conflict block /
3192169689Skan   libcall block.  */
3193169689Skanstatic void
3194169689Skanno_conflict_move_test (rtx dest, rtx set, void *p0)
3195169689Skan{
3196169689Skan  struct no_conflict_data *p= p0;
3197169689Skan
3198169689Skan  /* If this inns directly contributes to setting the target, it must stay.  */
3199169689Skan  if (reg_overlap_mentioned_p (p->target, dest))
3200169689Skan    p->must_stay = true;
3201169689Skan  /* If we haven't committed to keeping any other insns in the list yet,
3202169689Skan     there is nothing more to check.  */
3203169689Skan  else if (p->insn == p->first)
3204169689Skan    return;
3205169689Skan  /* If this insn sets / clobbers a register that feeds one of the insns
3206169689Skan     already in the list, this insn has to stay too.  */
3207169689Skan  else if (reg_overlap_mentioned_p (dest, PATTERN (p->first))
3208169689Skan	   || (CALL_P (p->first) && (find_reg_fusage (p->first, USE, dest)))
3209169689Skan	   || reg_used_between_p (dest, p->first, p->insn)
3210169689Skan	   /* Likewise if this insn depends on a register set by a previous
3211169689Skan	      insn in the list, or if it sets a result (presumably a hard
3212169689Skan	      register) that is set or clobbered by a previous insn.
3213169689Skan	      N.B. the modified_*_p (SET_DEST...) tests applied to a MEM
3214169689Skan	      SET_DEST perform the former check on the address, and the latter
3215169689Skan	      check on the MEM.  */
3216169689Skan	   || (GET_CODE (set) == SET
3217169689Skan	       && (modified_in_p (SET_SRC (set), p->first)
3218169689Skan		   || modified_in_p (SET_DEST (set), p->first)
3219169689Skan		   || modified_between_p (SET_SRC (set), p->first, p->insn)
3220169689Skan		   || modified_between_p (SET_DEST (set), p->first, p->insn))))
3221169689Skan    p->must_stay = true;
3222169689Skan}
3223169689Skan
3224169689Skan/* Encapsulate the block starting at FIRST and ending with LAST, which is
3225169689Skan   logically equivalent to EQUIV, so it gets manipulated as a unit if it
3226169689Skan   is possible to do so.  */
3227169689Skan
3228169689Skanstatic void
3229169689Skanmaybe_encapsulate_block (rtx first, rtx last, rtx equiv)
3230169689Skan{
3231169689Skan  if (!flag_non_call_exceptions || !may_trap_p (equiv))
3232169689Skan    {
3233169689Skan      /* We can't attach the REG_LIBCALL and REG_RETVAL notes when the
3234169689Skan	 encapsulated region would not be in one basic block, i.e. when
3235169689Skan	 there is a control_flow_insn_p insn between FIRST and LAST.  */
3236169689Skan      bool attach_libcall_retval_notes = true;
3237169689Skan      rtx insn, next = NEXT_INSN (last);
3238169689Skan
3239169689Skan      for (insn = first; insn != next; insn = NEXT_INSN (insn))
3240169689Skan	if (control_flow_insn_p (insn))
3241169689Skan	  {
3242169689Skan	    attach_libcall_retval_notes = false;
3243169689Skan	    break;
3244169689Skan	  }
3245169689Skan
3246169689Skan      if (attach_libcall_retval_notes)
3247169689Skan	{
3248169689Skan	  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
3249169689Skan						 REG_NOTES (first));
3250169689Skan	  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
3251169689Skan						REG_NOTES (last));
3252169689Skan	}
3253169689Skan    }
3254169689Skan}
3255169689Skan
325618334Speter/* Emit code to perform a series of operations on a multi-word quantity, one
325718334Speter   word at a time.
325818334Speter
325918334Speter   Such a block is preceded by a CLOBBER of the output, consists of multiple
326018334Speter   insns, each setting one word of the output, and followed by a SET copying
326118334Speter   the output to itself.
326218334Speter
326318334Speter   Each of the insns setting words of the output receives a REG_NO_CONFLICT
326418334Speter   note indicating that it doesn't conflict with the (also multi-word)
326518334Speter   inputs.  The entire block is surrounded by REG_LIBCALL and REG_RETVAL
326618334Speter   notes.
326718334Speter
326818334Speter   INSNS is a block of code generated to perform the operation, not including
326918334Speter   the CLOBBER and final copy.  All insns that compute intermediate values
3270132718Skan   are first emitted, followed by the block as described above.
327118334Speter
327218334Speter   TARGET, OP0, and OP1 are the output and inputs of the operations,
327318334Speter   respectively.  OP1 may be zero for a unary operation.
327418334Speter
3275117395Skan   EQUIV, if nonzero, is an expression to be placed into a REG_EQUAL note
327618334Speter   on the last insn.
327718334Speter
327818334Speter   If TARGET is not a register, INSNS is simply emitted with no special
327918334Speter   processing.  Likewise if anything in INSNS is not an INSN or if
328018334Speter   there is a libcall block inside INSNS.
328118334Speter
328218334Speter   The final insn emitted is returned.  */
328318334Speter
328418334Speterrtx
3285132718Skanemit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
328618334Speter{
328718334Speter  rtx prev, next, first, last, insn;
328818334Speter
3289169689Skan  if (!REG_P (target) || reload_in_progress)
3290117395Skan    return emit_insn (insns);
329118334Speter  else
329218334Speter    for (insn = insns; insn; insn = NEXT_INSN (insn))
3293169689Skan      if (!NONJUMP_INSN_P (insn)
329418334Speter	  || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
3295117395Skan	return emit_insn (insns);
329618334Speter
329718334Speter  /* First emit all insns that do not store into words of the output and remove
329818334Speter     these from the list.  */
329918334Speter  for (insn = insns; insn; insn = next)
330018334Speter    {
3301169689Skan      rtx note;
3302169689Skan      struct no_conflict_data data;
330318334Speter
330418334Speter      next = NEXT_INSN (insn);
330518334Speter
3306132718Skan      /* Some ports (cris) create a libcall regions at their own.  We must
330796263Sobrien	 avoid any potential nesting of LIBCALLs.  */
330896263Sobrien      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
330996263Sobrien	remove_note (insn, note);
331096263Sobrien      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
331196263Sobrien	remove_note (insn, note);
331296263Sobrien
3313169689Skan      data.target = target;
3314169689Skan      data.first = insns;
3315169689Skan      data.insn = insn;
3316169689Skan      data.must_stay = 0;
3317169689Skan      note_stores (PATTERN (insn), no_conflict_move_test, &data);
3318169689Skan      if (! data.must_stay)
331918334Speter	{
332018334Speter	  if (PREV_INSN (insn))
332118334Speter	    NEXT_INSN (PREV_INSN (insn)) = next;
332218334Speter	  else
332318334Speter	    insns = next;
332418334Speter
332518334Speter	  if (next)
332618334Speter	    PREV_INSN (next) = PREV_INSN (insn);
332718334Speter
332818334Speter	  add_insn (insn);
332918334Speter	}
333018334Speter    }
333118334Speter
333218334Speter  prev = get_last_insn ();
333318334Speter
333418334Speter  /* Now write the CLOBBER of the output, followed by the setting of each
333518334Speter     of the words, followed by the final copy.  */
333618334Speter  if (target != op0 && target != op1)
333750397Sobrien    emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
333818334Speter
333918334Speter  for (insn = insns; insn; insn = next)
334018334Speter    {
334118334Speter      next = NEXT_INSN (insn);
334218334Speter      add_insn (insn);
334318334Speter
3344169689Skan      if (op1 && REG_P (op1))
334550397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
334650397Sobrien					      REG_NOTES (insn));
334718334Speter
3348169689Skan      if (op0 && REG_P (op0))
334950397Sobrien	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
335050397Sobrien					      REG_NOTES (insn));
335118334Speter    }
335218334Speter
335318334Speter  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
335418334Speter      != CODE_FOR_nothing)
335518334Speter    {
335618334Speter      last = emit_move_insn (target, target);
335718334Speter      if (equiv)
335852284Sobrien	set_unique_reg_note (last, REG_EQUAL, equiv);
335918334Speter    }
336018334Speter  else
336190075Sobrien    {
336290075Sobrien      last = get_last_insn ();
336318334Speter
336490075Sobrien      /* Remove any existing REG_EQUAL note from "last", or else it will
336590075Sobrien	 be mistaken for a note referring to the full contents of the
336690075Sobrien	 alleged libcall value when found together with the REG_RETVAL
336790075Sobrien	 note added below.  An existing note can come from an insn
336890075Sobrien	 expansion at "last".  */
336990075Sobrien      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
337090075Sobrien    }
337190075Sobrien
337218334Speter  if (prev == 0)
337318334Speter    first = get_insns ();
337418334Speter  else
337518334Speter    first = NEXT_INSN (prev);
337618334Speter
3377169689Skan  maybe_encapsulate_block (first, last, equiv);
337818334Speter
337918334Speter  return last;
338018334Speter}
338118334Speter
338218334Speter/* Emit code to make a call to a constant function or a library call.
338318334Speter
338418334Speter   INSNS is a list containing all insns emitted in the call.
338518334Speter   These insns leave the result in RESULT.  Our block is to copy RESULT
338618334Speter   to TARGET, which is logically equivalent to EQUIV.
338718334Speter
338818334Speter   We first emit any insns that set a pseudo on the assumption that these are
338918334Speter   loading constants into registers; doing so allows them to be safely cse'ed
339018334Speter   between blocks.  Then we emit all the other insns in the block, followed by
339118334Speter   an insn to move RESULT to TARGET.  This last insn will have a REQ_EQUAL
339218334Speter   note with an operand of EQUIV.
339318334Speter
339418334Speter   Moving assignments to pseudos outside of the block is done to improve
339518334Speter   the generated code, but is not required to generate correct code,
339618334Speter   hence being unable to move an assignment is not grounds for not making
339718334Speter   a libcall block.  There are two reasons why it is safe to leave these
339818334Speter   insns inside the block: First, we know that these pseudos cannot be
339918334Speter   used in generated RTL outside the block since they are created for
340018334Speter   temporary purposes within the block.  Second, CSE will not record the
340118334Speter   values of anything set inside a libcall block, so we know they must
340218334Speter   be dead at the end of the block.
340318334Speter
340418334Speter   Except for the first group of insns (the ones setting pseudos), the
340518334Speter   block is delimited by REG_RETVAL and REG_LIBCALL notes.  */
340618334Speter
340718334Spetervoid
3408132718Skanemit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
340918334Speter{
341070635Sobrien  rtx final_dest = target;
341118334Speter  rtx prev, next, first, last, insn;
341218334Speter
341370635Sobrien  /* If this is a reg with REG_USERVAR_P set, then it could possibly turn
341470635Sobrien     into a MEM later.  Protect the libcall block from this change.  */
341570635Sobrien  if (! REG_P (target) || REG_USERVAR_P (target))
341670635Sobrien    target = gen_reg_rtx (GET_MODE (target));
3417132718Skan
341890075Sobrien  /* If we're using non-call exceptions, a libcall corresponding to an
341990075Sobrien     operation that may trap may also trap.  */
342090075Sobrien  if (flag_non_call_exceptions && may_trap_p (equiv))
342190075Sobrien    {
342290075Sobrien      for (insn = insns; insn; insn = NEXT_INSN (insn))
3423169689Skan	if (CALL_P (insn))
342490075Sobrien	  {
342590075Sobrien	    rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
3426132718Skan
342790075Sobrien	    if (note != 0 && INTVAL (XEXP (note, 0)) <= 0)
342890075Sobrien	      remove_note (insn, note);
342990075Sobrien	  }
343090075Sobrien    }
343190075Sobrien  else
343252284Sobrien  /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION
343390075Sobrien     reg note to indicate that this call cannot throw or execute a nonlocal
343490075Sobrien     goto (unless there is already a REG_EH_REGION note, in which case
343590075Sobrien     we update it).  */
343690075Sobrien    for (insn = insns; insn; insn = NEXT_INSN (insn))
3437169689Skan      if (CALL_P (insn))
343890075Sobrien	{
343990075Sobrien	  rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
3440132718Skan
344190075Sobrien	  if (note != 0)
3442169689Skan	    XEXP (note, 0) = constm1_rtx;
344390075Sobrien	  else
3444169689Skan	    REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx,
344590075Sobrien						  REG_NOTES (insn));
344690075Sobrien	}
344752284Sobrien
344818334Speter  /* First emit all insns that set pseudos.  Remove them from the list as
344918334Speter     we go.  Avoid insns that set pseudos which were referenced in previous
345018334Speter     insns.  These can be generated by move_by_pieces, for example,
345118334Speter     to update an address.  Similarly, avoid insns that reference things
345218334Speter     set in previous insns.  */
345318334Speter
345418334Speter  for (insn = insns; insn; insn = next)
345518334Speter    {
345618334Speter      rtx set = single_set (insn);
345796263Sobrien      rtx note;
345818334Speter
3459132718Skan      /* Some ports (cris) create a libcall regions at their own.  We must
346096263Sobrien	 avoid any potential nesting of LIBCALLs.  */
346196263Sobrien      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
346296263Sobrien	remove_note (insn, note);
346396263Sobrien      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
346496263Sobrien	remove_note (insn, note);
346596263Sobrien
346618334Speter      next = NEXT_INSN (insn);
346718334Speter
3468169689Skan      if (set != 0 && REG_P (SET_DEST (set))
3469169689Skan	  && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
347018334Speter	{
3471169689Skan	  struct no_conflict_data data;
347218334Speter
3473169689Skan	  data.target = const0_rtx;
3474169689Skan	  data.first = insns;
3475169689Skan	  data.insn = insn;
3476169689Skan	  data.must_stay = 0;
3477169689Skan	  note_stores (PATTERN (insn), no_conflict_move_test, &data);
3478169689Skan	  if (! data.must_stay)
3479169689Skan	    {
3480169689Skan	      if (PREV_INSN (insn))
3481169689Skan		NEXT_INSN (PREV_INSN (insn)) = next;
3482169689Skan	      else
3483169689Skan		insns = next;
348418334Speter
3485169689Skan	      if (next)
3486169689Skan		PREV_INSN (next) = PREV_INSN (insn);
3487169689Skan
3488169689Skan	      add_insn (insn);
3489169689Skan	    }
349018334Speter	}
3491132718Skan
3492132718Skan      /* Some ports use a loop to copy large arguments onto the stack.
3493132718Skan	 Don't move anything outside such a loop.  */
3494169689Skan      if (LABEL_P (insn))
3495132718Skan	break;
349618334Speter    }
349718334Speter
349818334Speter  prev = get_last_insn ();
349918334Speter
350018334Speter  /* Write the remaining insns followed by the final copy.  */
350118334Speter
350218334Speter  for (insn = insns; insn; insn = next)
350318334Speter    {
350418334Speter      next = NEXT_INSN (insn);
350518334Speter
350618334Speter      add_insn (insn);
350718334Speter    }
350818334Speter
350918334Speter  last = emit_move_insn (target, result);
351050397Sobrien  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
351150397Sobrien      != CODE_FOR_nothing)
351252284Sobrien    set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
351390075Sobrien  else
351490075Sobrien    {
351590075Sobrien      /* Remove any existing REG_EQUAL note from "last", or else it will
351690075Sobrien	 be mistaken for a note referring to the full contents of the
351790075Sobrien	 libcall value when found together with the REG_RETVAL note added
351890075Sobrien	 below.  An existing note can come from an insn expansion at
351990075Sobrien	 "last".  */
352090075Sobrien      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
352190075Sobrien    }
352218334Speter
352370635Sobrien  if (final_dest != target)
352470635Sobrien    emit_move_insn (final_dest, target);
352570635Sobrien
352618334Speter  if (prev == 0)
352718334Speter    first = get_insns ();
352818334Speter  else
352918334Speter    first = NEXT_INSN (prev);
353018334Speter
3531169689Skan  maybe_encapsulate_block (first, last, equiv);
353218334Speter}
353318334Speter
353490075Sobrien/* Nonzero if we can perform a comparison of mode MODE straightforwardly.
353590075Sobrien   PURPOSE describes how this comparison will be used.  CODE is the rtx
353690075Sobrien   comparison code we will be using.
353718334Speter
353890075Sobrien   ??? Actually, CODE is slightly weaker than that.  A target is still
3539132718Skan   required to implement all of the normal bcc operations, but not
354090075Sobrien   required to implement all (or any) of the unordered bcc operations.  */
3541132718Skan
354290075Sobrienint
3543132718Skancan_compare_p (enum rtx_code code, enum machine_mode mode,
3544132718Skan	       enum can_compare_purpose purpose)
354590075Sobrien{
354690075Sobrien  do
354790075Sobrien    {
3548117395Skan      if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
354990075Sobrien	{
355090075Sobrien	  if (purpose == ccp_jump)
3551117395Skan	    return bcc_gen_fctn[(int) code] != NULL;
355290075Sobrien	  else if (purpose == ccp_store_flag)
3553117395Skan	    return setcc_gen_code[(int) code] != CODE_FOR_nothing;
355490075Sobrien	  else
355590075Sobrien	    /* There's only one cmov entry point, and it's allowed to fail.  */
355690075Sobrien	    return 1;
355790075Sobrien	}
355890075Sobrien      if (purpose == ccp_jump
3559117395Skan	  && cbranch_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
356090075Sobrien	return 1;
356190075Sobrien      if (purpose == ccp_cmov
3562117395Skan	  && cmov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
356390075Sobrien	return 1;
356490075Sobrien      if (purpose == ccp_store_flag
3565117395Skan	  && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
356690075Sobrien	return 1;
356790075Sobrien      mode = GET_MODE_WIDER_MODE (mode);
356890075Sobrien    }
356990075Sobrien  while (mode != VOIDmode);
357090075Sobrien
357190075Sobrien  return 0;
357290075Sobrien}
357390075Sobrien
357490075Sobrien/* This function is called when we are going to emit a compare instruction that
357590075Sobrien   compares the values found in *PX and *PY, using the rtl operator COMPARISON.
357690075Sobrien
357790075Sobrien   *PMODE is the mode of the inputs (in case they are const_int).
357890075Sobrien   *PUNSIGNEDP nonzero says that the operands are unsigned;
357918334Speter   this matters if they need to be widened.
358018334Speter
358190075Sobrien   If they have mode BLKmode, then SIZE specifies the size of both operands.
358218334Speter
358390075Sobrien   This function performs all the setup necessary so that the caller only has
358490075Sobrien   to emit a single comparison insn.  This setup can involve doing a BLKmode
358590075Sobrien   comparison or emitting a library call to perform the comparison if no insn
358690075Sobrien   is available to handle it.
358790075Sobrien   The values which are passed in through pointers can be modified; the caller
3588169689Skan   should perform the comparison on the modified values.  Constant
3589169689Skan   comparisons must have already been folded.  */
359018334Speter
359190075Sobrienstatic void
3592132718Skanprepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
3593132718Skan		  enum machine_mode *pmode, int *punsignedp,
3594132718Skan		  enum can_compare_purpose purpose)
359518334Speter{
359690075Sobrien  enum machine_mode mode = *pmode;
359790075Sobrien  rtx x = *px, y = *py;
359890075Sobrien  int unsignedp = *punsignedp;
359918334Speter
3600169689Skan  /* If we are inside an appropriately-short loop and we are optimizing,
3601169689Skan     force expensive constants into a register.  */
3602169689Skan  if (CONSTANT_P (x) && optimize
360390075Sobrien      && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1))
360418334Speter    x = force_reg (mode, x);
360518334Speter
3606169689Skan  if (CONSTANT_P (y) && optimize
360790075Sobrien      && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1))
360818334Speter    y = force_reg (mode, y);
360918334Speter
361052284Sobrien#ifdef HAVE_cc0
3611169689Skan  /* Make sure if we have a canonical comparison.  The RTL
3612169689Skan     documentation states that canonical comparisons are required only
3613169689Skan     for targets which have cc0.  */
3614169689Skan  gcc_assert (!CONSTANT_P (x) || CONSTANT_P (y));
361552284Sobrien#endif
361652284Sobrien
361718334Speter  /* Don't let both operands fail to indicate the mode.  */
361818334Speter  if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode)
361918334Speter    x = force_reg (mode, x);
362018334Speter
362118334Speter  /* Handle all BLKmode compares.  */
362218334Speter
362318334Speter  if (mode == BLKmode)
362418334Speter    {
3625132718Skan      enum machine_mode cmp_mode, result_mode;
3626132718Skan      enum insn_code cmp_code;
3627132718Skan      tree length_type;
3628132718Skan      rtx libfunc;
362990075Sobrien      rtx result;
3630132718Skan      rtx opalign
363190075Sobrien	= GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
363290075Sobrien
3633169689Skan      gcc_assert (size);
3634132718Skan
3635132718Skan      /* Try to use a memory block compare insn - either cmpstr
3636132718Skan	 or cmpmem will do.  */
3637132718Skan      for (cmp_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
3638132718Skan	   cmp_mode != VOIDmode;
3639132718Skan	   cmp_mode = GET_MODE_WIDER_MODE (cmp_mode))
364018334Speter	{
3641132718Skan	  cmp_code = cmpmem_optab[cmp_mode];
3642132718Skan	  if (cmp_code == CODE_FOR_nothing)
3643132718Skan	    cmp_code = cmpstr_optab[cmp_mode];
3644132718Skan	  if (cmp_code == CODE_FOR_nothing)
3645169689Skan	    cmp_code = cmpstrn_optab[cmp_mode];
3646169689Skan	  if (cmp_code == CODE_FOR_nothing)
3647132718Skan	    continue;
3648132718Skan
3649132718Skan	  /* Must make sure the size fits the insn's mode.  */
3650132718Skan	  if ((GET_CODE (size) == CONST_INT
3651132718Skan	       && INTVAL (size) >= (1 << GET_MODE_BITSIZE (cmp_mode)))
3652132718Skan	      || (GET_MODE_BITSIZE (GET_MODE (size))
3653132718Skan		  > GET_MODE_BITSIZE (cmp_mode)))
3654132718Skan	    continue;
3655132718Skan
3656132718Skan	  result_mode = insn_data[cmp_code].operand[0].mode;
365790075Sobrien	  result = gen_reg_rtx (result_mode);
3658132718Skan	  size = convert_to_mode (cmp_mode, size, 1);
3659132718Skan	  emit_insn (GEN_FCN (cmp_code) (result, x, y, size, opalign));
3660132718Skan
3661132718Skan	  *px = result;
3662132718Skan	  *py = const0_rtx;
3663132718Skan	  *pmode = result_mode;
3664132718Skan	  return;
366518334Speter	}
3666132718Skan
3667169689Skan      /* Otherwise call a library function, memcmp.  */
3668132718Skan      libfunc = memcmp_libfunc;
3669132718Skan      length_type = sizetype;
3670132718Skan      result_mode = TYPE_MODE (integer_type_node);
3671132718Skan      cmp_mode = TYPE_MODE (length_type);
3672132718Skan      size = convert_to_mode (TYPE_MODE (length_type), size,
3673169689Skan			      TYPE_UNSIGNED (length_type));
367450397Sobrien
3675132718Skan      result = emit_library_call_value (libfunc, 0, LCT_PURE_MAKE_BLOCK,
3676132718Skan					result_mode, 3,
3677132718Skan					XEXP (x, 0), Pmode,
3678132718Skan					XEXP (y, 0), Pmode,
3679132718Skan					size, cmp_mode);
368090075Sobrien      *px = result;
368190075Sobrien      *py = const0_rtx;
368290075Sobrien      *pmode = result_mode;
368318334Speter      return;
368418334Speter    }
368518334Speter
3686132718Skan  /* Don't allow operands to the compare to trap, as that can put the
3687132718Skan     compare and branch in different basic blocks.  */
3688132718Skan  if (flag_non_call_exceptions)
3689132718Skan    {
3690132718Skan      if (may_trap_p (x))
3691132718Skan	x = force_reg (mode, x);
3692132718Skan      if (may_trap_p (y))
3693132718Skan	y = force_reg (mode, y);
3694132718Skan    }
3695132718Skan
369690075Sobrien  *px = x;
369790075Sobrien  *py = y;
369890075Sobrien  if (can_compare_p (*pcomparison, mode, purpose))
369990075Sobrien    return;
370018334Speter
370118334Speter  /* Handle a lib call just for the mode we are using.  */
370218334Speter
3703169689Skan  if (cmp_optab->handlers[(int) mode].libfunc && !SCALAR_FLOAT_MODE_P (mode))
370418334Speter    {
370518334Speter      rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
370650397Sobrien      rtx result;
370750397Sobrien
370818334Speter      /* If we want unsigned, and this mode has a distinct unsigned
370918334Speter	 comparison routine, use that.  */
371018334Speter      if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
371118334Speter	libfunc = ucmp_optab->handlers[(int) mode].libfunc;
371218334Speter
3713117395Skan      result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
3714117395Skan					word_mode, 2, x, mode, y, mode);
371518334Speter
3716169689Skan      /* There are two kinds of comparison routines. Biased routines
3717169689Skan	 return 0/1/2, and unbiased routines return -1/0/1. Other parts
3718169689Skan	 of gcc expect that the comparison operation is equivalent
3719169689Skan	 to the modified comparison. For signed comparisons compare the
3720169689Skan	 result against 1 in the biased case, and zero in the unbiased
3721169689Skan	 case. For unsigned comparisons always compare against 1 after
3722169689Skan	 biasing the unbiased result by adding 1. This gives us a way to
3723169689Skan	 represent LTU. */
372490075Sobrien      *px = result;
3725169689Skan      *pmode = word_mode;
372690075Sobrien      *py = const1_rtx;
3727169689Skan
3728169689Skan      if (!TARGET_LIB_INT_CMP_BIASED)
3729169689Skan	{
3730169689Skan	  if (*punsignedp)
3731169689Skan	    *px = plus_constant (result, 1);
3732169689Skan	  else
3733169689Skan	    *py = const0_rtx;
3734169689Skan	}
373518334Speter      return;
373618334Speter    }
373718334Speter
3738169689Skan  gcc_assert (SCALAR_FLOAT_MODE_P (mode));
3739169689Skan  prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
374018334Speter}
374118334Speter
374290075Sobrien/* Before emitting an insn with code ICODE, make sure that X, which is going
374390075Sobrien   to be used for operand OPNUM of the insn, is converted from mode MODE to
374490075Sobrien   WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and
374590075Sobrien   that it is accepted by the operand predicate.  Return the new value.  */
374690075Sobrien
3747169689Skanstatic rtx
3748132718Skanprepare_operand (int icode, rtx x, int opnum, enum machine_mode mode,
3749132718Skan		 enum machine_mode wider_mode, int unsignedp)
375090075Sobrien{
375190075Sobrien  if (mode != wider_mode)
375290075Sobrien    x = convert_modes (wider_mode, mode, x, unsignedp);
375390075Sobrien
3754169689Skan  if (!insn_data[icode].operand[opnum].predicate
375590075Sobrien      (x, insn_data[icode].operand[opnum].mode))
3756119256Skan    {
3757119256Skan      if (no_new_pseudos)
3758119256Skan	return NULL_RTX;
3759119256Skan      x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
3760119256Skan    }
3761119256Skan
376290075Sobrien  return x;
376390075Sobrien}
376490075Sobrien
376590075Sobrien/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
376690075Sobrien   we can do the comparison.
376790075Sobrien   The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
376890075Sobrien   be NULL_RTX which indicates that only a comparison is to be generated.  */
376990075Sobrien
377090075Sobrienstatic void
3771132718Skanemit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
3772132718Skan			  enum rtx_code comparison, int unsignedp, rtx label)
377390075Sobrien{
377490075Sobrien  rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
377590075Sobrien  enum mode_class class = GET_MODE_CLASS (mode);
377690075Sobrien  enum machine_mode wider_mode = mode;
377790075Sobrien
377890075Sobrien  /* Try combined insns first.  */
377990075Sobrien  do
378090075Sobrien    {
378190075Sobrien      enum insn_code icode;
378290075Sobrien      PUT_MODE (test, wider_mode);
378390075Sobrien
378490075Sobrien      if (label)
3785132718Skan	{
3786117395Skan	  icode = cbranch_optab->handlers[(int) wider_mode].insn_code;
3787132718Skan
378890075Sobrien	  if (icode != CODE_FOR_nothing
3789169689Skan	      && insn_data[icode].operand[0].predicate (test, wider_mode))
379090075Sobrien	    {
379190075Sobrien	      x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
379290075Sobrien	      y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
379390075Sobrien	      emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
379490075Sobrien	      return;
379590075Sobrien	    }
379690075Sobrien	}
379790075Sobrien
379890075Sobrien      /* Handle some compares against zero.  */
379990075Sobrien      icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
380090075Sobrien      if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
380190075Sobrien	{
380290075Sobrien	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
380390075Sobrien	  emit_insn (GEN_FCN (icode) (x));
380490075Sobrien	  if (label)
3805169689Skan	    emit_jump_insn (bcc_gen_fctn[(int) comparison] (label));
380690075Sobrien	  return;
380790075Sobrien	}
380890075Sobrien
380990075Sobrien      /* Handle compares for which there is a directly suitable insn.  */
381090075Sobrien
381190075Sobrien      icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code;
381290075Sobrien      if (icode != CODE_FOR_nothing)
381390075Sobrien	{
381490075Sobrien	  x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
381590075Sobrien	  y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp);
381690075Sobrien	  emit_insn (GEN_FCN (icode) (x, y));
381790075Sobrien	  if (label)
3818169689Skan	    emit_jump_insn (bcc_gen_fctn[(int) comparison] (label));
381990075Sobrien	  return;
382090075Sobrien	}
382190075Sobrien
3822169689Skan      if (!CLASS_HAS_WIDER_MODES_P (class))
382390075Sobrien	break;
382490075Sobrien
382590075Sobrien      wider_mode = GET_MODE_WIDER_MODE (wider_mode);
3826117395Skan    }
3827117395Skan  while (wider_mode != VOIDmode);
382890075Sobrien
3829169689Skan  gcc_unreachable ();
383090075Sobrien}
383190075Sobrien
383252284Sobrien/* Generate code to compare X with Y so that the condition codes are
383352284Sobrien   set and to jump to LABEL if the condition is true.  If X is a
383452284Sobrien   constant and Y is not a constant, then the comparison is swapped to
383552284Sobrien   ensure that the comparison RTL has the canonical form.
383652284Sobrien
383752284Sobrien   UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they
383852284Sobrien   need to be widened by emit_cmp_insn.  UNSIGNEDP is also used to select
383952284Sobrien   the proper branch condition code.
384052284Sobrien
384190075Sobrien   If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y.
384252284Sobrien
384352284Sobrien   MODE is the mode of the inputs (in case they are const_int).
384452284Sobrien
384552284Sobrien   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  It will
384652284Sobrien   be passed unchanged to emit_cmp_insn, then potentially converted into an
384752284Sobrien   unsigned variant based on UNSIGNEDP to select a proper jump instruction.  */
384852284Sobrien
384952284Sobrienvoid
3850132718Skanemit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
3851132718Skan			 enum machine_mode mode, int unsignedp, rtx label)
385252284Sobrien{
385390075Sobrien  rtx op0 = x, op1 = y;
385490075Sobrien
385590075Sobrien  /* Swap operands and condition to ensure canonical RTL.  */
385690075Sobrien  if (swap_commutative_operands_p (x, y))
385752284Sobrien    {
385890075Sobrien      /* If we're not emitting a branch, this means some caller
385990075Sobrien         is out of sync.  */
3860169689Skan      gcc_assert (label);
386190075Sobrien
386290075Sobrien      op0 = y, op1 = x;
386352284Sobrien      comparison = swap_condition (comparison);
386452284Sobrien    }
386552284Sobrien
386652284Sobrien#ifdef HAVE_cc0
3867169689Skan  /* If OP0 is still a constant, then both X and Y must be constants.
3868169689Skan     Force X into a register to create canonical RTL.  */
386952284Sobrien  if (CONSTANT_P (op0))
387052284Sobrien    op0 = force_reg (mode, op0);
387152284Sobrien#endif
387252284Sobrien
387352284Sobrien  if (unsignedp)
387452284Sobrien    comparison = unsigned_condition (comparison);
387590075Sobrien
387690075Sobrien  prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp,
387790075Sobrien		    ccp_jump);
387890075Sobrien  emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
387952284Sobrien}
388052284Sobrien
388190075Sobrien/* Like emit_cmp_and_jump_insns, but generate only the comparison.  */
388252284Sobrien
388390075Sobrienvoid
3884132718Skanemit_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
3885132718Skan	       enum machine_mode mode, int unsignedp)
388618334Speter{
388790075Sobrien  emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0);
388818334Speter}
388918334Speter
389018334Speter/* Emit a library call comparison between floating point X and Y.
389118334Speter   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
389218334Speter
389390075Sobrienstatic void
3894132718Skanprepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
3895132718Skan		       enum machine_mode *pmode, int *punsignedp)
389618334Speter{
389790075Sobrien  enum rtx_code comparison = *pcomparison;
3898132718Skan  enum rtx_code swapped = swap_condition (comparison);
3899169689Skan  enum rtx_code reversed = reverse_condition_maybe_unordered (comparison);
3900169689Skan  rtx x = *px;
3901169689Skan  rtx y = *py;
3902132718Skan  enum machine_mode orig_mode = GET_MODE (x);
3903132718Skan  enum machine_mode mode;
3904132718Skan  rtx value, target, insns, equiv;
390518334Speter  rtx libfunc = 0;
3906169689Skan  bool reversed_p = false;
390718334Speter
3908169689Skan  for (mode = orig_mode;
3909169689Skan       mode != VOIDmode;
3910169689Skan       mode = GET_MODE_WIDER_MODE (mode))
3911132718Skan    {
3912132718Skan      if ((libfunc = code_to_optab[comparison]->handlers[mode].libfunc))
391318334Speter	break;
391418334Speter
3915132718Skan      if ((libfunc = code_to_optab[swapped]->handlers[mode].libfunc))
3916132718Skan	{
3917132718Skan	  rtx tmp;
3918132718Skan	  tmp = x; x = y; y = tmp;
3919132718Skan	  comparison = swapped;
3920132718Skan	  break;
3921132718Skan	}
3922169689Skan
3923169689Skan      if ((libfunc = code_to_optab[reversed]->handlers[mode].libfunc)
3924169689Skan	  && FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, reversed))
3925169689Skan	{
3926169689Skan	  comparison = reversed;
3927169689Skan	  reversed_p = true;
3928169689Skan	  break;
3929169689Skan	}
3930132718Skan    }
393118334Speter
3932169689Skan  gcc_assert (mode != VOIDmode);
393318334Speter
3934132718Skan  if (mode != orig_mode)
3935132718Skan    {
3936132718Skan      x = convert_to_mode (mode, x, 0);
3937132718Skan      y = convert_to_mode (mode, y, 0);
3938132718Skan    }
393918334Speter
3940132718Skan  /* Attach a REG_EQUAL note describing the semantics of the libcall to
3941132718Skan     the RTL.  The allows the RTL optimizers to delete the libcall if the
3942132718Skan     condition can be determined at compile-time.  */
3943132718Skan  if (comparison == UNORDERED)
3944132718Skan    {
3945132718Skan      rtx temp = simplify_gen_relational (NE, word_mode, mode, x, x);
3946132718Skan      equiv = simplify_gen_relational (NE, word_mode, mode, y, y);
3947132718Skan      equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
3948132718Skan				    temp, const_true_rtx, equiv);
3949132718Skan    }
3950132718Skan  else
3951132718Skan    {
3952132718Skan      equiv = simplify_gen_relational (comparison, word_mode, mode, x, y);
3953132718Skan      if (! FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
3954132718Skan	{
3955132718Skan	  rtx true_rtx, false_rtx;
395618334Speter
3957132718Skan	  switch (comparison)
3958132718Skan	    {
3959132718Skan	    case EQ:
3960132718Skan	      true_rtx = const0_rtx;
3961132718Skan	      false_rtx = const_true_rtx;
3962132718Skan	      break;
396350397Sobrien
3964132718Skan	    case NE:
3965132718Skan	      true_rtx = const_true_rtx;
3966132718Skan	      false_rtx = const0_rtx;
3967132718Skan	      break;
396890075Sobrien
3969132718Skan	    case GT:
3970132718Skan	      true_rtx = const1_rtx;
3971132718Skan	      false_rtx = const0_rtx;
3972132718Skan	      break;
397318334Speter
3974132718Skan	    case GE:
3975132718Skan	      true_rtx = const0_rtx;
3976132718Skan	      false_rtx = constm1_rtx;
3977132718Skan	      break;
397818334Speter
3979132718Skan	    case LT:
3980132718Skan	      true_rtx = constm1_rtx;
3981132718Skan	      false_rtx = const0_rtx;
3982132718Skan	      break;
398318334Speter
3984132718Skan	    case LE:
3985132718Skan	      true_rtx = const0_rtx;
3986132718Skan	      false_rtx = const1_rtx;
3987132718Skan	      break;
398818334Speter
3989132718Skan	    default:
3990169689Skan	      gcc_unreachable ();
3991132718Skan	    }
3992132718Skan	  equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
3993132718Skan					equiv, true_rtx, false_rtx);
3994132718Skan	}
3995132718Skan    }
399618334Speter
3997132718Skan  start_sequence ();
3998132718Skan  value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
3999132718Skan				   word_mode, 2, x, mode, y, mode);
4000132718Skan  insns = get_insns ();
4001132718Skan  end_sequence ();
400250397Sobrien
4003132718Skan  target = gen_reg_rtx (word_mode);
4004132718Skan  emit_libcall_block (insns, target, value, equiv);
400590075Sobrien
4006132718Skan  if (comparison == UNORDERED
4007132718Skan      || FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
4008169689Skan    comparison = reversed_p ? EQ : NE;
400918334Speter
4010132718Skan  *px = target;
401190075Sobrien  *py = const0_rtx;
401290075Sobrien  *pmode = word_mode;
4013132718Skan  *pcomparison = comparison;
401490075Sobrien  *punsignedp = 0;
401518334Speter}
401618334Speter
401718334Speter/* Generate code to indirectly jump to a location given in the rtx LOC.  */
401818334Speter
401918334Spetervoid
4020132718Skanemit_indirect_jump (rtx loc)
402118334Speter{
4022169689Skan  if (!insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate
4023169689Skan      (loc, Pmode))
402418334Speter    loc = copy_to_mode_reg (Pmode, loc);
402518334Speter
402618334Speter  emit_jump_insn (gen_indirect_jump (loc));
402718334Speter  emit_barrier ();
402818334Speter}
402918334Speter
403018334Speter#ifdef HAVE_conditional_move
403118334Speter
403218334Speter/* Emit a conditional move instruction if the machine supports one for that
403318334Speter   condition and machine mode.
403418334Speter
403518334Speter   OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
403618334Speter   the mode to use should they be constants.  If it is VOIDmode, they cannot
403718334Speter   both be constants.
403818334Speter
403918334Speter   OP2 should be stored in TARGET if the comparison is true, otherwise OP3
404018334Speter   should be stored there.  MODE is the mode to use should they be constants.
404118334Speter   If it is VOIDmode, they cannot both be constants.
404218334Speter
404318334Speter   The result is either TARGET (perhaps modified) or NULL_RTX if the operation
404418334Speter   is not supported.  */
404518334Speter
404618334Speterrtx
4047132718Skanemit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
4048132718Skan		       enum machine_mode cmode, rtx op2, rtx op3,
4049132718Skan		       enum machine_mode mode, int unsignedp)
405018334Speter{
405118334Speter  rtx tem, subtarget, comparison, insn;
405218334Speter  enum insn_code icode;
405390075Sobrien  enum rtx_code reversed;
405418334Speter
405518334Speter  /* If one operand is constant, make it the second one.  Only do this
405618334Speter     if the other operand is not constant as well.  */
405718334Speter
405890075Sobrien  if (swap_commutative_operands_p (op0, op1))
405918334Speter    {
406018334Speter      tem = op0;
406118334Speter      op0 = op1;
406218334Speter      op1 = tem;
406318334Speter      code = swap_condition (code);
406418334Speter    }
406518334Speter
406690075Sobrien  /* get_condition will prefer to generate LT and GT even if the old
406790075Sobrien     comparison was against zero, so undo that canonicalization here since
406890075Sobrien     comparisons against zero are cheaper.  */
4069132718Skan  if (code == LT && op1 == const1_rtx)
407090075Sobrien    code = LE, op1 = const0_rtx;
4071132718Skan  else if (code == GT && op1 == constm1_rtx)
407290075Sobrien    code = GE, op1 = const0_rtx;
407390075Sobrien
407418334Speter  if (cmode == VOIDmode)
407518334Speter    cmode = GET_MODE (op0);
407618334Speter
407790075Sobrien  if (swap_commutative_operands_p (op2, op3)
407890075Sobrien      && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
407990075Sobrien          != UNKNOWN))
408018334Speter    {
408118334Speter      tem = op2;
408218334Speter      op2 = op3;
408318334Speter      op3 = tem;
408490075Sobrien      code = reversed;
408518334Speter    }
408618334Speter
408718334Speter  if (mode == VOIDmode)
408818334Speter    mode = GET_MODE (op2);
408918334Speter
409018334Speter  icode = movcc_gen_code[mode];
409118334Speter
409218334Speter  if (icode == CODE_FOR_nothing)
409318334Speter    return 0;
409418334Speter
4095169689Skan  if (!target)
409618334Speter    target = gen_reg_rtx (mode);
409718334Speter
409818334Speter  subtarget = target;
409918334Speter
410018334Speter  /* If the insn doesn't accept these operands, put them in pseudos.  */
410118334Speter
4102169689Skan  if (!insn_data[icode].operand[0].predicate
410390075Sobrien      (subtarget, insn_data[icode].operand[0].mode))
410490075Sobrien    subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
410518334Speter
4106169689Skan  if (!insn_data[icode].operand[2].predicate
410790075Sobrien      (op2, insn_data[icode].operand[2].mode))
410890075Sobrien    op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
410918334Speter
4110169689Skan  if (!insn_data[icode].operand[3].predicate
411190075Sobrien      (op3, insn_data[icode].operand[3].mode))
411290075Sobrien    op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
411318334Speter
411418334Speter  /* Everything should now be in the suitable form, so emit the compare insn
411518334Speter     and then the conditional move.  */
411618334Speter
4117132718Skan  comparison
411890075Sobrien    = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
411918334Speter
412018334Speter  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
412190075Sobrien  /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
412290075Sobrien     return NULL and let the caller figure out how best to deal with this
412390075Sobrien     situation.  */
412418334Speter  if (GET_CODE (comparison) != code)
412590075Sobrien    return NULL_RTX;
4126132718Skan
412718334Speter  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
412818334Speter
412918334Speter  /* If that failed, then give up.  */
413018334Speter  if (insn == 0)
413118334Speter    return 0;
413218334Speter
413318334Speter  emit_insn (insn);
413418334Speter
413518334Speter  if (subtarget != target)
413618334Speter    convert_move (target, subtarget, 0);
413718334Speter
413818334Speter  return target;
413918334Speter}
414018334Speter
4141117395Skan/* Return nonzero if a conditional move of mode MODE is supported.
414218334Speter
414318334Speter   This function is for combine so it can tell whether an insn that looks
414418334Speter   like a conditional move is actually supported by the hardware.  If we
414518334Speter   guess wrong we lose a bit on optimization, but that's it.  */
414618334Speter/* ??? sparc64 supports conditionally moving integers values based on fp
414718334Speter   comparisons, and vice versa.  How do we handle them?  */
414818334Speter
414918334Speterint
4150132718Skancan_conditionally_move_p (enum machine_mode mode)
415118334Speter{
415218334Speter  if (movcc_gen_code[mode] != CODE_FOR_nothing)
415318334Speter    return 1;
415418334Speter
415518334Speter  return 0;
415618334Speter}
415718334Speter
415818334Speter#endif /* HAVE_conditional_move */
4159132718Skan
4160132718Skan/* Emit a conditional addition instruction if the machine supports one for that
4161132718Skan   condition and machine mode.
4162132718Skan
4163132718Skan   OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
4164132718Skan   the mode to use should they be constants.  If it is VOIDmode, they cannot
4165132718Skan   both be constants.
4166132718Skan
4167132718Skan   OP2 should be stored in TARGET if the comparison is true, otherwise OP2+OP3
4168132718Skan   should be stored there.  MODE is the mode to use should they be constants.
4169132718Skan   If it is VOIDmode, they cannot both be constants.
4170132718Skan
4171132718Skan   The result is either TARGET (perhaps modified) or NULL_RTX if the operation
4172132718Skan   is not supported.  */
4173132718Skan
4174132718Skanrtx
4175132718Skanemit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
4176132718Skan		      enum machine_mode cmode, rtx op2, rtx op3,
4177132718Skan		      enum machine_mode mode, int unsignedp)
4178132718Skan{
4179132718Skan  rtx tem, subtarget, comparison, insn;
4180132718Skan  enum insn_code icode;
4181132718Skan  enum rtx_code reversed;
4182132718Skan
4183132718Skan  /* If one operand is constant, make it the second one.  Only do this
4184132718Skan     if the other operand is not constant as well.  */
4185132718Skan
4186132718Skan  if (swap_commutative_operands_p (op0, op1))
4187132718Skan    {
4188132718Skan      tem = op0;
4189132718Skan      op0 = op1;
4190132718Skan      op1 = tem;
4191132718Skan      code = swap_condition (code);
4192132718Skan    }
4193132718Skan
4194132718Skan  /* get_condition will prefer to generate LT and GT even if the old
4195132718Skan     comparison was against zero, so undo that canonicalization here since
4196132718Skan     comparisons against zero are cheaper.  */
4197132718Skan  if (code == LT && op1 == const1_rtx)
4198132718Skan    code = LE, op1 = const0_rtx;
4199132718Skan  else if (code == GT && op1 == constm1_rtx)
4200132718Skan    code = GE, op1 = const0_rtx;
4201132718Skan
4202132718Skan  if (cmode == VOIDmode)
4203132718Skan    cmode = GET_MODE (op0);
4204132718Skan
4205132718Skan  if (swap_commutative_operands_p (op2, op3)
4206132718Skan      && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
4207132718Skan          != UNKNOWN))
4208132718Skan    {
4209132718Skan      tem = op2;
4210132718Skan      op2 = op3;
4211132718Skan      op3 = tem;
4212132718Skan      code = reversed;
4213132718Skan    }
4214132718Skan
4215132718Skan  if (mode == VOIDmode)
4216132718Skan    mode = GET_MODE (op2);
4217132718Skan
4218132718Skan  icode = addcc_optab->handlers[(int) mode].insn_code;
4219132718Skan
4220132718Skan  if (icode == CODE_FOR_nothing)
4221132718Skan    return 0;
4222132718Skan
4223169689Skan  if (!target)
4224132718Skan    target = gen_reg_rtx (mode);
4225132718Skan
4226132718Skan  /* If the insn doesn't accept these operands, put them in pseudos.  */
4227132718Skan
4228169689Skan  if (!insn_data[icode].operand[0].predicate
4229169689Skan      (target, insn_data[icode].operand[0].mode))
4230132718Skan    subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
4231169689Skan  else
4232169689Skan    subtarget = target;
4233132718Skan
4234169689Skan  if (!insn_data[icode].operand[2].predicate
4235132718Skan      (op2, insn_data[icode].operand[2].mode))
4236132718Skan    op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
4237132718Skan
4238169689Skan  if (!insn_data[icode].operand[3].predicate
4239132718Skan      (op3, insn_data[icode].operand[3].mode))
4240132718Skan    op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
4241132718Skan
4242132718Skan  /* Everything should now be in the suitable form, so emit the compare insn
4243132718Skan     and then the conditional move.  */
4244132718Skan
4245132718Skan  comparison
4246132718Skan    = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
4247132718Skan
4248132718Skan  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
4249132718Skan  /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
4250132718Skan     return NULL and let the caller figure out how best to deal with this
4251132718Skan     situation.  */
4252132718Skan  if (GET_CODE (comparison) != code)
4253132718Skan    return NULL_RTX;
4254132718Skan
4255132718Skan  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
4256132718Skan
4257132718Skan  /* If that failed, then give up.  */
4258132718Skan  if (insn == 0)
4259132718Skan    return 0;
4260132718Skan
4261132718Skan  emit_insn (insn);
4262132718Skan
4263132718Skan  if (subtarget != target)
4264132718Skan    convert_move (target, subtarget, 0);
4265132718Skan
4266132718Skan  return target;
4267132718Skan}
426818334Speter
4269132718Skan/* These functions attempt to generate an insn body, rather than
4270132718Skan   emitting the insn, but if the gen function already emits them, we
4271169689Skan   make no attempt to turn them back into naked patterns.  */
427218334Speter
427318334Speter/* Generate and return an insn body to add Y to X.  */
427418334Speter
427518334Speterrtx
4276132718Skangen_add2_insn (rtx x, rtx y)
427718334Speter{
4278132718Skan  int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
427918334Speter
4280169689Skan  gcc_assert (insn_data[icode].operand[0].predicate
4281169689Skan	      (x, insn_data[icode].operand[0].mode));
4282169689Skan  gcc_assert (insn_data[icode].operand[1].predicate
4283169689Skan	      (x, insn_data[icode].operand[1].mode));
4284169689Skan  gcc_assert (insn_data[icode].operand[2].predicate
4285169689Skan	      (y, insn_data[icode].operand[2].mode));
428618334Speter
4287169689Skan  return GEN_FCN (icode) (x, x, y);
428818334Speter}
428918334Speter
429090075Sobrien/* Generate and return an insn body to add r1 and c,
429190075Sobrien   storing the result in r0.  */
429290075Sobrienrtx
4293132718Skangen_add3_insn (rtx r0, rtx r1, rtx c)
429490075Sobrien{
429590075Sobrien  int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
429690075Sobrien
4297117395Skan  if (icode == CODE_FOR_nothing
4298169689Skan      || !(insn_data[icode].operand[0].predicate
4299169689Skan	   (r0, insn_data[icode].operand[0].mode))
4300169689Skan      || !(insn_data[icode].operand[1].predicate
4301169689Skan	   (r1, insn_data[icode].operand[1].mode))
4302169689Skan      || !(insn_data[icode].operand[2].predicate
4303169689Skan	   (c, insn_data[icode].operand[2].mode)))
430490075Sobrien    return NULL_RTX;
430590075Sobrien
4306169689Skan  return GEN_FCN (icode) (r0, r1, c);
430790075Sobrien}
430890075Sobrien
430918334Speterint
4310132718Skanhave_add2_insn (rtx x, rtx y)
431118334Speter{
431290075Sobrien  int icode;
431390075Sobrien
4314169689Skan  gcc_assert (GET_MODE (x) != VOIDmode);
431590075Sobrien
4316132718Skan  icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
431790075Sobrien
431890075Sobrien  if (icode == CODE_FOR_nothing)
431990075Sobrien    return 0;
432090075Sobrien
4321169689Skan  if (!(insn_data[icode].operand[0].predicate
4322169689Skan	(x, insn_data[icode].operand[0].mode))
4323169689Skan      || !(insn_data[icode].operand[1].predicate
4324169689Skan	   (x, insn_data[icode].operand[1].mode))
4325169689Skan      || !(insn_data[icode].operand[2].predicate
4326169689Skan	   (y, insn_data[icode].operand[2].mode)))
432790075Sobrien    return 0;
432890075Sobrien
432990075Sobrien  return 1;
433018334Speter}
433118334Speter
433218334Speter/* Generate and return an insn body to subtract Y from X.  */
433318334Speter
433418334Speterrtx
4335132718Skangen_sub2_insn (rtx x, rtx y)
433618334Speter{
4337132718Skan  int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
433818334Speter
4339169689Skan  gcc_assert (insn_data[icode].operand[0].predicate
4340169689Skan	      (x, insn_data[icode].operand[0].mode));
4341169689Skan  gcc_assert (insn_data[icode].operand[1].predicate
4342169689Skan	      (x, insn_data[icode].operand[1].mode));
4343169689Skan  gcc_assert  (insn_data[icode].operand[2].predicate
4344169689Skan	       (y, insn_data[icode].operand[2].mode));
434518334Speter
4346169689Skan  return GEN_FCN (icode) (x, x, y);
434718334Speter}
434818334Speter
434990075Sobrien/* Generate and return an insn body to subtract r1 and c,
435090075Sobrien   storing the result in r0.  */
435190075Sobrienrtx
4352132718Skangen_sub3_insn (rtx r0, rtx r1, rtx c)
435390075Sobrien{
435490075Sobrien  int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code;
435590075Sobrien
4356117395Skan  if (icode == CODE_FOR_nothing
4357169689Skan      || !(insn_data[icode].operand[0].predicate
4358169689Skan	   (r0, insn_data[icode].operand[0].mode))
4359169689Skan      || !(insn_data[icode].operand[1].predicate
4360169689Skan	   (r1, insn_data[icode].operand[1].mode))
4361169689Skan      || !(insn_data[icode].operand[2].predicate
4362169689Skan	   (c, insn_data[icode].operand[2].mode)))
436390075Sobrien    return NULL_RTX;
436490075Sobrien
4365169689Skan  return GEN_FCN (icode) (r0, r1, c);
436690075Sobrien}
436790075Sobrien
436818334Speterint
4369132718Skanhave_sub2_insn (rtx x, rtx y)
437018334Speter{
437190075Sobrien  int icode;
437290075Sobrien
4373169689Skan  gcc_assert (GET_MODE (x) != VOIDmode);
437490075Sobrien
4375132718Skan  icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
437690075Sobrien
437790075Sobrien  if (icode == CODE_FOR_nothing)
437890075Sobrien    return 0;
437990075Sobrien
4380169689Skan  if (!(insn_data[icode].operand[0].predicate
4381169689Skan	(x, insn_data[icode].operand[0].mode))
4382169689Skan      || !(insn_data[icode].operand[1].predicate
4383169689Skan	   (x, insn_data[icode].operand[1].mode))
4384169689Skan      || !(insn_data[icode].operand[2].predicate
4385169689Skan	   (y, insn_data[icode].operand[2].mode)))
438690075Sobrien    return 0;
438790075Sobrien
438890075Sobrien  return 1;
438918334Speter}
439018334Speter
439118334Speter/* Generate the body of an instruction to copy Y into X.
4392117395Skan   It may be a list of insns, if one insn isn't enough.  */
439318334Speter
439418334Speterrtx
4395132718Skangen_move_insn (rtx x, rtx y)
439618334Speter{
439718334Speter  rtx seq;
439818334Speter
439918334Speter  start_sequence ();
440018334Speter  emit_move_insn_1 (x, y);
4401117395Skan  seq = get_insns ();
440218334Speter  end_sequence ();
440318334Speter  return seq;
440418334Speter}
440518334Speter
440618334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE.
440718334Speter   UNSIGNEDP specifies zero-extension instead of sign-extension.  If
440818334Speter   no such operation exists, CODE_FOR_nothing will be returned.  */
440918334Speter
441018334Speterenum insn_code
4411132718Skancan_extend_p (enum machine_mode to_mode, enum machine_mode from_mode,
4412132718Skan	      int unsignedp)
441318334Speter{
4414132718Skan  convert_optab tab;
441590075Sobrien#ifdef HAVE_ptr_extend
441690075Sobrien  if (unsignedp < 0)
441790075Sobrien    return CODE_FOR_ptr_extend;
441890075Sobrien#endif
4419132718Skan
4420132718Skan  tab = unsignedp ? zext_optab : sext_optab;
4421132718Skan  return tab->handlers[to_mode][from_mode].insn_code;
442218334Speter}
442318334Speter
442418334Speter/* Generate the body of an insn to extend Y (with mode MFROM)
442518334Speter   into X (with mode MTO).  Do zero-extension if UNSIGNEDP is nonzero.  */
442618334Speter
442718334Speterrtx
4428132718Skangen_extend_insn (rtx x, rtx y, enum machine_mode mto,
4429132718Skan		 enum machine_mode mfrom, int unsignedp)
443018334Speter{
4431132718Skan  enum insn_code icode = can_extend_p (mto, mfrom, unsignedp);
4432132718Skan  return GEN_FCN (icode) (x, y);
443318334Speter}
443418334Speter
443518334Speter/* can_fix_p and can_float_p say whether the target machine
443618334Speter   can directly convert a given fixed point type to
443718334Speter   a given floating point type, or vice versa.
443818334Speter   The returned value is the CODE_FOR_... value to use,
443918334Speter   or CODE_FOR_nothing if these modes cannot be directly converted.
444018334Speter
444118334Speter   *TRUNCP_PTR is set to 1 if it is necessary to output
444218334Speter   an explicit FTRUNC insn before the fix insn; otherwise 0.  */
444318334Speter
444418334Speterstatic enum insn_code
4445132718Skancan_fix_p (enum machine_mode fixmode, enum machine_mode fltmode,
4446132718Skan	   int unsignedp, int *truncp_ptr)
444718334Speter{
4448132718Skan  convert_optab tab;
4449132718Skan  enum insn_code icode;
445018334Speter
4451132718Skan  tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
4452132718Skan  icode = tab->handlers[fixmode][fltmode].insn_code;
4453132718Skan  if (icode != CODE_FOR_nothing)
445418334Speter    {
4455132718Skan      *truncp_ptr = 0;
4456132718Skan      return icode;
4457132718Skan    }
4458132718Skan
4459169689Skan  /* FIXME: This requires a port to define both FIX and FTRUNC pattern
4460169689Skan     for this to work. We need to rework the fix* and ftrunc* patterns
4461169689Skan     and documentation.  */
4462132718Skan  tab = unsignedp ? ufix_optab : sfix_optab;
4463132718Skan  icode = tab->handlers[fixmode][fltmode].insn_code;
4464132718Skan  if (icode != CODE_FOR_nothing
4465132718Skan      && ftrunc_optab->handlers[fltmode].insn_code != CODE_FOR_nothing)
4466132718Skan    {
446718334Speter      *truncp_ptr = 1;
4468132718Skan      return icode;
446918334Speter    }
4470132718Skan
4471132718Skan  *truncp_ptr = 0;
447218334Speter  return CODE_FOR_nothing;
447318334Speter}
447418334Speter
447518334Speterstatic enum insn_code
4476132718Skancan_float_p (enum machine_mode fltmode, enum machine_mode fixmode,
4477132718Skan	     int unsignedp)
447818334Speter{
4479132718Skan  convert_optab tab;
4480132718Skan
4481132718Skan  tab = unsignedp ? ufloat_optab : sfloat_optab;
4482132718Skan  return tab->handlers[fltmode][fixmode].insn_code;
448318334Speter}
448418334Speter
448518334Speter/* Generate code to convert FROM to floating point
448618334Speter   and store in TO.  FROM must be fixed point and not VOIDmode.
448718334Speter   UNSIGNEDP nonzero means regard FROM as unsigned.
448818334Speter   Normally this is done by correcting the final value
448918334Speter   if it is negative.  */
449018334Speter
449118334Spetervoid
4492132718Skanexpand_float (rtx to, rtx from, int unsignedp)
449318334Speter{
449418334Speter  enum insn_code icode;
449590075Sobrien  rtx target = to;
449618334Speter  enum machine_mode fmode, imode;
4497169689Skan  bool can_do_signed = false;
449818334Speter
449918334Speter  /* Crash now, because we won't be able to decide which mode to use.  */
4500169689Skan  gcc_assert (GET_MODE (from) != VOIDmode);
450118334Speter
450218334Speter  /* Look for an insn to do the conversion.  Do it in the specified
450318334Speter     modes if possible; otherwise convert either input, output or both to
450418334Speter     wider mode.  If the integer mode is wider than the mode of FROM,
450518334Speter     we can do the conversion signed even if the input is unsigned.  */
450618334Speter
4507117395Skan  for (fmode = GET_MODE (to); fmode != VOIDmode;
4508117395Skan       fmode = GET_MODE_WIDER_MODE (fmode))
4509117395Skan    for (imode = GET_MODE (from); imode != VOIDmode;
4510117395Skan	 imode = GET_MODE_WIDER_MODE (imode))
451118334Speter      {
451218334Speter	int doing_unsigned = unsignedp;
451318334Speter
451490075Sobrien	if (fmode != GET_MODE (to)
451590075Sobrien	    && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from)))
451690075Sobrien	  continue;
451790075Sobrien
451818334Speter	icode = can_float_p (fmode, imode, unsignedp);
4519169689Skan	if (icode == CODE_FOR_nothing && unsignedp)
4520169689Skan	  {
4521169689Skan	    enum insn_code scode = can_float_p (fmode, imode, 0);
4522169689Skan	    if (scode != CODE_FOR_nothing)
4523169689Skan	      can_do_signed = true;
4524169689Skan	    if (imode != GET_MODE (from))
4525169689Skan	      icode = scode, doing_unsigned = 0;
4526169689Skan	  }
452718334Speter
452818334Speter	if (icode != CODE_FOR_nothing)
452918334Speter	  {
453018334Speter	    if (imode != GET_MODE (from))
453118334Speter	      from = convert_to_mode (imode, from, unsignedp);
453218334Speter
453318334Speter	    if (fmode != GET_MODE (to))
453418334Speter	      target = gen_reg_rtx (fmode);
453518334Speter
453618334Speter	    emit_unop_insn (icode, target, from,
453718334Speter			    doing_unsigned ? UNSIGNED_FLOAT : FLOAT);
453818334Speter
453918334Speter	    if (target != to)
454018334Speter	      convert_move (to, target, 0);
454118334Speter	    return;
454218334Speter	  }
4543117395Skan      }
454418334Speter
4545169689Skan  /* Unsigned integer, and no way to convert directly.  For binary
4546169689Skan     floating point modes, convert as signed, then conditionally adjust
4547169689Skan     the result.  */
4548169689Skan  if (unsignedp && can_do_signed && !DECIMAL_FLOAT_MODE_P (GET_MODE (to)))
454918334Speter    {
455018334Speter      rtx label = gen_label_rtx ();
455118334Speter      rtx temp;
455218334Speter      REAL_VALUE_TYPE offset;
455318334Speter
455418334Speter      /* Look for a usable floating mode FMODE wider than the source and at
455518334Speter	 least as wide as the target.  Using FMODE will avoid rounding woes
455618334Speter	 with unsigned values greater than the signed maximum value.  */
455718334Speter
455818334Speter      for (fmode = GET_MODE (to);  fmode != VOIDmode;
455918334Speter	   fmode = GET_MODE_WIDER_MODE (fmode))
456018334Speter	if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
456118334Speter	    && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
456218334Speter	  break;
456318334Speter
456418334Speter      if (fmode == VOIDmode)
456518334Speter	{
456618334Speter	  /* There is no such mode.  Pretend the target is wide enough.  */
456718334Speter	  fmode = GET_MODE (to);
456818334Speter
456950397Sobrien	  /* Avoid double-rounding when TO is narrower than FROM.  */
457018334Speter	  if ((significand_size (fmode) + 1)
457118334Speter	      < GET_MODE_BITSIZE (GET_MODE (from)))
457218334Speter	    {
457318334Speter	      rtx temp1;
457418334Speter	      rtx neglabel = gen_label_rtx ();
457518334Speter
4576132718Skan	      /* Don't use TARGET if it isn't a register, is a hard register,
457718334Speter		 or is the wrong mode.  */
4578169689Skan	      if (!REG_P (target)
457918334Speter		  || REGNO (target) < FIRST_PSEUDO_REGISTER
458018334Speter		  || GET_MODE (target) != fmode)
458118334Speter		target = gen_reg_rtx (fmode);
458218334Speter
458318334Speter	      imode = GET_MODE (from);
458418334Speter	      do_pending_stack_adjust ();
458518334Speter
458618334Speter	      /* Test whether the sign bit is set.  */
458790075Sobrien	      emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode,
458890075Sobrien				       0, neglabel);
458918334Speter
459018334Speter	      /* The sign bit is not set.  Convert as signed.  */
459118334Speter	      expand_float (target, from, 0);
459218334Speter	      emit_jump_insn (gen_jump (label));
459318334Speter	      emit_barrier ();
459418334Speter
459518334Speter	      /* The sign bit is set.
459618334Speter		 Convert to a usable (positive signed) value by shifting right
459718334Speter		 one bit, while remembering if a nonzero bit was shifted
459818334Speter		 out; i.e., compute  (from & 1) | (from >> 1).  */
459918334Speter
460018334Speter	      emit_label (neglabel);
460118334Speter	      temp = expand_binop (imode, and_optab, from, const1_rtx,
460218334Speter				   NULL_RTX, 1, OPTAB_LIB_WIDEN);
460318334Speter	      temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
460418334Speter				    NULL_RTX, 1);
4605132718Skan	      temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
460618334Speter				   OPTAB_LIB_WIDEN);
460718334Speter	      expand_float (target, temp, 0);
460818334Speter
460918334Speter	      /* Multiply by 2 to undo the shift above.  */
461018334Speter	      temp = expand_binop (fmode, add_optab, target, target,
4611117395Skan				   target, 0, OPTAB_LIB_WIDEN);
461218334Speter	      if (temp != target)
461318334Speter		emit_move_insn (target, temp);
461418334Speter
461518334Speter	      do_pending_stack_adjust ();
461618334Speter	      emit_label (label);
461718334Speter	      goto done;
461818334Speter	    }
461918334Speter	}
462018334Speter
462118334Speter      /* If we are about to do some arithmetic to correct for an
462218334Speter	 unsigned operand, do it in a pseudo-register.  */
462318334Speter
462418334Speter      if (GET_MODE (to) != fmode
4625169689Skan	  || !REG_P (to) || REGNO (to) < FIRST_PSEUDO_REGISTER)
462618334Speter	target = gen_reg_rtx (fmode);
462718334Speter
462818334Speter      /* Convert as signed integer to floating.  */
462918334Speter      expand_float (target, from, 0);
463018334Speter
463118334Speter      /* If FROM is negative (and therefore TO is negative),
463218334Speter	 correct its value by 2**bitwidth.  */
463318334Speter
463418334Speter      do_pending_stack_adjust ();
463552284Sobrien      emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
463690075Sobrien			       0, label);
463718334Speter
4638132718Skan
4639117395Skan      real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from)));
464018334Speter      temp = expand_binop (fmode, add_optab, target,
464118334Speter			   CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
464218334Speter			   target, 0, OPTAB_LIB_WIDEN);
464318334Speter      if (temp != target)
464418334Speter	emit_move_insn (target, temp);
464518334Speter
464618334Speter      do_pending_stack_adjust ();
464718334Speter      emit_label (label);
464818334Speter      goto done;
464918334Speter    }
465018334Speter
4651132718Skan  /* No hardware instruction available; call a library routine.  */
465218334Speter    {
4653132718Skan      rtx libfunc;
465418334Speter      rtx insns;
465518334Speter      rtx value;
4656132718Skan      convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
465718334Speter
465818334Speter      if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
465918334Speter	from = convert_to_mode (SImode, from, unsignedp);
466018334Speter
4661132718Skan      libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
4662169689Skan      gcc_assert (libfunc);
466318334Speter
466418334Speter      start_sequence ();
466518334Speter
4666132718Skan      value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
466790075Sobrien				       GET_MODE (to), 1, from,
466890075Sobrien				       GET_MODE (from));
466918334Speter      insns = get_insns ();
467018334Speter      end_sequence ();
467118334Speter
467218334Speter      emit_libcall_block (insns, target, value,
467350397Sobrien			  gen_rtx_FLOAT (GET_MODE (to), from));
467418334Speter    }
467518334Speter
467618334Speter done:
467718334Speter
467818334Speter  /* Copy result to requested destination
467918334Speter     if we have been computing in a temp location.  */
468018334Speter
468118334Speter  if (target != to)
468218334Speter    {
468318334Speter      if (GET_MODE (target) == GET_MODE (to))
468418334Speter	emit_move_insn (to, target);
468518334Speter      else
468618334Speter	convert_move (to, target, 0);
468718334Speter    }
468818334Speter}
468918334Speter
4690169689Skan/* Generate code to convert FROM to fixed point and store in TO.  FROM
4691169689Skan   must be floating point.  */
469218334Speter
469318334Spetervoid
4694132718Skanexpand_fix (rtx to, rtx from, int unsignedp)
469518334Speter{
469618334Speter  enum insn_code icode;
469790075Sobrien  rtx target = to;
469818334Speter  enum machine_mode fmode, imode;
469918334Speter  int must_trunc = 0;
470018334Speter
470118334Speter  /* We first try to find a pair of modes, one real and one integer, at
470218334Speter     least as wide as FROM and TO, respectively, in which we can open-code
470318334Speter     this conversion.  If the integer mode is wider than the mode of TO,
470418334Speter     we can do the conversion either signed or unsigned.  */
470518334Speter
470690075Sobrien  for (fmode = GET_MODE (from); fmode != VOIDmode;
470790075Sobrien       fmode = GET_MODE_WIDER_MODE (fmode))
470890075Sobrien    for (imode = GET_MODE (to); imode != VOIDmode;
470990075Sobrien	 imode = GET_MODE_WIDER_MODE (imode))
471018334Speter      {
471118334Speter	int doing_unsigned = unsignedp;
471218334Speter
471318334Speter	icode = can_fix_p (imode, fmode, unsignedp, &must_trunc);
471418334Speter	if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp)
471518334Speter	  icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0;
471618334Speter
471718334Speter	if (icode != CODE_FOR_nothing)
471818334Speter	  {
471918334Speter	    if (fmode != GET_MODE (from))
472018334Speter	      from = convert_to_mode (fmode, from, 0);
472118334Speter
472218334Speter	    if (must_trunc)
4723169689Skan	      {
4724169689Skan		rtx temp = gen_reg_rtx (GET_MODE (from));
4725169689Skan		from = expand_unop (GET_MODE (from), ftrunc_optab, from,
4726169689Skan				    temp, 0);
4727169689Skan	      }
472818334Speter
472918334Speter	    if (imode != GET_MODE (to))
473018334Speter	      target = gen_reg_rtx (imode);
473118334Speter
473218334Speter	    emit_unop_insn (icode, target, from,
473318334Speter			    doing_unsigned ? UNSIGNED_FIX : FIX);
473418334Speter	    if (target != to)
473518334Speter	      convert_move (to, target, unsignedp);
473618334Speter	    return;
473718334Speter	  }
473818334Speter      }
473918334Speter
474018334Speter  /* For an unsigned conversion, there is one more way to do it.
474118334Speter     If we have a signed conversion, we generate code that compares
474218334Speter     the real value to the largest representable positive number.  If if
474318334Speter     is smaller, the conversion is done normally.  Otherwise, subtract
474418334Speter     one plus the highest signed number, convert, and add it back.
474518334Speter
474618334Speter     We only need to check all real modes, since we know we didn't find
4747132718Skan     anything with a wider integer mode.
474818334Speter
4749132718Skan     This code used to extend FP value into mode wider than the destination.
4750132718Skan     This is not needed.  Consider, for instance conversion from SFmode
4751132718Skan     into DImode.
4752132718Skan
4753169689Skan     The hot path through the code is dealing with inputs smaller than 2^63
4754132718Skan     and doing just the conversion, so there is no bits to lose.
4755132718Skan
4756132718Skan     In the other path we know the value is positive in the range 2^63..2^64-1
4757132718Skan     inclusive.  (as for other imput overflow happens and result is undefined)
4758132718Skan     So we know that the most important bit set in mantissa corresponds to
4759132718Skan     2^63.  The subtraction of 2^63 should not generate any rounding as it
4760132718Skan     simply clears out that bit.  The rest is trivial.  */
4761132718Skan
476218334Speter  if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
476318334Speter    for (fmode = GET_MODE (from); fmode != VOIDmode;
476418334Speter	 fmode = GET_MODE_WIDER_MODE (fmode))
4765132718Skan      if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
4766132718Skan					 &must_trunc))
476718334Speter	{
476818334Speter	  int bitsize;
476918334Speter	  REAL_VALUE_TYPE offset;
477018334Speter	  rtx limit, lab1, lab2, insn;
477118334Speter
477218334Speter	  bitsize = GET_MODE_BITSIZE (GET_MODE (to));
4773117395Skan	  real_2expN (&offset, bitsize - 1);
477418334Speter	  limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
477518334Speter	  lab1 = gen_label_rtx ();
477618334Speter	  lab2 = gen_label_rtx ();
477718334Speter
477818334Speter	  if (fmode != GET_MODE (from))
477918334Speter	    from = convert_to_mode (fmode, from, 0);
478018334Speter
478118334Speter	  /* See if we need to do the subtraction.  */
478218334Speter	  do_pending_stack_adjust ();
478352284Sobrien	  emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
478490075Sobrien				   0, lab1);
478518334Speter
478618334Speter	  /* If not, do the signed "fix" and branch around fixup code.  */
478718334Speter	  expand_fix (to, from, 0);
478818334Speter	  emit_jump_insn (gen_jump (lab2));
478918334Speter	  emit_barrier ();
479018334Speter
479118334Speter	  /* Otherwise, subtract 2**(N-1), convert to signed number,
479218334Speter	     then add 2**(N-1).  Do the addition using XOR since this
479318334Speter	     will often generate better code.  */
479418334Speter	  emit_label (lab1);
479518334Speter	  target = expand_binop (GET_MODE (from), sub_optab, from, limit,
479618334Speter				 NULL_RTX, 0, OPTAB_LIB_WIDEN);
479718334Speter	  expand_fix (to, target, 0);
479818334Speter	  target = expand_binop (GET_MODE (to), xor_optab, to,
4799117395Skan				 gen_int_mode
4800117395Skan				 ((HOST_WIDE_INT) 1 << (bitsize - 1),
4801117395Skan				  GET_MODE (to)),
480218334Speter				 to, 1, OPTAB_LIB_WIDEN);
480318334Speter
480418334Speter	  if (target != to)
480518334Speter	    emit_move_insn (to, target);
480618334Speter
480718334Speter	  emit_label (lab2);
480818334Speter
480950397Sobrien	  if (mov_optab->handlers[(int) GET_MODE (to)].insn_code
481050397Sobrien	      != CODE_FOR_nothing)
481150397Sobrien	    {
481250397Sobrien	      /* Make a place for a REG_NOTE and add it.  */
481350397Sobrien	      insn = emit_move_insn (to, to);
481452284Sobrien	      set_unique_reg_note (insn,
481552284Sobrien	                           REG_EQUAL,
481652284Sobrien				   gen_rtx_fmt_e (UNSIGNED_FIX,
481752284Sobrien						  GET_MODE (to),
481852284Sobrien						  copy_rtx (from)));
481950397Sobrien	    }
482090075Sobrien
482118334Speter	  return;
482218334Speter	}
482318334Speter
482418334Speter  /* We can't do it with an insn, so use a library call.  But first ensure
482518334Speter     that the mode of TO is at least as wide as SImode, since those are the
482618334Speter     only library calls we know about.  */
482718334Speter
482818334Speter  if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
482918334Speter    {
483018334Speter      target = gen_reg_rtx (SImode);
483118334Speter
483218334Speter      expand_fix (target, from, unsignedp);
483318334Speter    }
483418334Speter  else
483518334Speter    {
483618334Speter      rtx insns;
483718334Speter      rtx value;
4838132718Skan      rtx libfunc;
4839169689Skan
4840132718Skan      convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
4841132718Skan      libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
4842169689Skan      gcc_assert (libfunc);
484318334Speter
484418334Speter      start_sequence ();
484518334Speter
4846132718Skan      value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
484790075Sobrien				       GET_MODE (to), 1, from,
484890075Sobrien				       GET_MODE (from));
484918334Speter      insns = get_insns ();
485018334Speter      end_sequence ();
485118334Speter
485218334Speter      emit_libcall_block (insns, target, value,
485350397Sobrien			  gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
485450397Sobrien					 GET_MODE (to), from));
485518334Speter    }
4856132718Skan
485750397Sobrien  if (target != to)
485850397Sobrien    {
485950397Sobrien      if (GET_MODE (to) == GET_MODE (target))
486050397Sobrien        emit_move_insn (to, target);
486150397Sobrien      else
486250397Sobrien        convert_move (to, target, 0);
486350397Sobrien    }
486418334Speter}
486518334Speter
486690075Sobrien/* Report whether we have an instruction to perform the operation
486790075Sobrien   specified by CODE on operands of mode MODE.  */
486890075Sobrienint
4869132718Skanhave_insn_for (enum rtx_code code, enum machine_mode mode)
487018334Speter{
487190075Sobrien  return (code_to_optab[(int) code] != 0
487290075Sobrien	  && (code_to_optab[(int) code]->handlers[(int) mode].insn_code
487390075Sobrien	      != CODE_FOR_nothing));
487490075Sobrien}
487590075Sobrien
487690075Sobrien/* Create a blank optab.  */
487790075Sobrienstatic optab
4878132718Skannew_optab (void)
487990075Sobrien{
488018334Speter  int i;
4881132718Skan  optab op = ggc_alloc (sizeof (struct optab));
488218334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
488318334Speter    {
488418334Speter      op->handlers[i].insn_code = CODE_FOR_nothing;
488518334Speter      op->handlers[i].libfunc = 0;
488618334Speter    }
488718334Speter
488890075Sobrien  return op;
488990075Sobrien}
489018334Speter
4891132718Skanstatic convert_optab
4892132718Skannew_convert_optab (void)
4893132718Skan{
4894132718Skan  int i, j;
4895132718Skan  convert_optab op = ggc_alloc (sizeof (struct convert_optab));
4896132718Skan  for (i = 0; i < NUM_MACHINE_MODES; i++)
4897132718Skan    for (j = 0; j < NUM_MACHINE_MODES; j++)
4898132718Skan      {
4899132718Skan	op->handlers[i][j].insn_code = CODE_FOR_nothing;
4900132718Skan	op->handlers[i][j].libfunc = 0;
4901132718Skan      }
4902132718Skan  return op;
4903132718Skan}
4904132718Skan
490590075Sobrien/* Same, but fill in its code as CODE, and write it into the
490690075Sobrien   code_to_optab table.  */
490790075Sobrienstatic inline optab
4908132718Skaninit_optab (enum rtx_code code)
490990075Sobrien{
491090075Sobrien  optab op = new_optab ();
491190075Sobrien  op->code = code;
491290075Sobrien  code_to_optab[(int) code] = op;
491318334Speter  return op;
491418334Speter}
491518334Speter
491690075Sobrien/* Same, but fill in its code as CODE, and do _not_ write it into
491790075Sobrien   the code_to_optab table.  */
491890075Sobrienstatic inline optab
4919132718Skaninit_optabv (enum rtx_code code)
492090075Sobrien{
492190075Sobrien  optab op = new_optab ();
492290075Sobrien  op->code = code;
492390075Sobrien  return op;
492490075Sobrien}
492590075Sobrien
4926132718Skan/* Conversion optabs never go in the code_to_optab table.  */
4927132718Skanstatic inline convert_optab
4928132718Skaninit_convert_optab (enum rtx_code code)
4929132718Skan{
4930132718Skan  convert_optab op = new_convert_optab ();
4931132718Skan  op->code = code;
4932132718Skan  return op;
4933132718Skan}
4934132718Skan
493518334Speter/* Initialize the libfunc fields of an entire group of entries in some
493618334Speter   optab.  Each entry is set equal to a string consisting of a leading
493718334Speter   pair of underscores followed by a generic operation name followed by
4938132718Skan   a mode name (downshifted to lowercase) followed by a single character
493918334Speter   representing the number of operands for the given operation (which is
494018334Speter   usually one of the characters '2', '3', or '4').
494118334Speter
494218334Speter   OPTABLE is the table in which libfunc fields are to be initialized.
494318334Speter   FIRST_MODE is the first machine mode index in the given optab to
494418334Speter     initialize.
494518334Speter   LAST_MODE is the last machine mode index in the given optab to
494618334Speter     initialize.
494718334Speter   OPNAME is the generic (string) name of the operation.
494818334Speter   SUFFIX is the character which specifies the number of operands for
494918334Speter     the given generic operation.
495018334Speter*/
495118334Speter
495218334Speterstatic void
4953132718Skaninit_libfuncs (optab optable, int first_mode, int last_mode,
4954132718Skan	       const char *opname, int suffix)
495518334Speter{
495690075Sobrien  int mode;
495790075Sobrien  unsigned opname_len = strlen (opname);
495818334Speter
495918334Speter  for (mode = first_mode; (int) mode <= (int) last_mode;
496018334Speter       mode = (enum machine_mode) ((int) mode + 1))
496118334Speter    {
4962117395Skan      const char *mname = GET_MODE_NAME (mode);
496390075Sobrien      unsigned mname_len = strlen (mname);
496490075Sobrien      char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
496590075Sobrien      char *p;
496690075Sobrien      const char *q;
496718334Speter
496818334Speter      p = libfunc_name;
496918334Speter      *p++ = '_';
497018334Speter      *p++ = '_';
497118334Speter      for (q = opname; *q; )
497218334Speter	*p++ = *q++;
497318334Speter      for (q = mname; *q; q++)
497490075Sobrien	*p++ = TOLOWER (*q);
497518334Speter      *p++ = suffix;
497690075Sobrien      *p = '\0';
497790075Sobrien
497818334Speter      optable->handlers[(int) mode].libfunc
4979132718Skan	= init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name));
498018334Speter    }
498118334Speter}
498218334Speter
498318334Speter/* Initialize the libfunc fields of an entire group of entries in some
498418334Speter   optab which correspond to all integer mode operations.  The parameters
498518334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
498618334Speter   routine.  (See above).  */
498718334Speter
498818334Speterstatic void
4989132718Skaninit_integral_libfuncs (optab optable, const char *opname, int suffix)
499018334Speter{
4991132718Skan  int maxsize = 2*BITS_PER_WORD;
4992132718Skan  if (maxsize < LONG_LONG_TYPE_SIZE)
4993132718Skan    maxsize = LONG_LONG_TYPE_SIZE;
4994132718Skan  init_libfuncs (optable, word_mode,
4995132718Skan		 mode_for_size (maxsize, MODE_INT, 0),
4996132718Skan		 opname, suffix);
499718334Speter}
499818334Speter
499918334Speter/* Initialize the libfunc fields of an entire group of entries in some
500018334Speter   optab which correspond to all real mode operations.  The parameters
500118334Speter   have the same meaning as similarly named ones for the `init_libfuncs'
500218334Speter   routine.  (See above).  */
500318334Speter
500418334Speterstatic void
5005132718Skaninit_floating_libfuncs (optab optable, const char *opname, int suffix)
500618334Speter{
5007132718Skan  init_libfuncs (optable, MIN_MODE_FLOAT, MAX_MODE_FLOAT, opname, suffix);
5008169689Skan  init_libfuncs (optable, MIN_MODE_DECIMAL_FLOAT, MAX_MODE_DECIMAL_FLOAT,
5009169689Skan		 opname, suffix);
501018334Speter}
501118334Speter
5012132718Skan/* Initialize the libfunc fields of an entire group of entries of an
5013132718Skan   inter-mode-class conversion optab.  The string formation rules are
5014132718Skan   similar to the ones for init_libfuncs, above, but instead of having
5015132718Skan   a mode name and an operand count these functions have two mode names
5016132718Skan   and no operand count.  */
5017132718Skanstatic void
5018132718Skaninit_interclass_conv_libfuncs (convert_optab tab, const char *opname,
5019132718Skan			       enum mode_class from_class,
5020132718Skan			       enum mode_class to_class)
5021132718Skan{
5022132718Skan  enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class);
5023132718Skan  enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class);
5024132718Skan  size_t opname_len = strlen (opname);
5025132718Skan  size_t max_mname_len = 0;
5026132718Skan
5027132718Skan  enum machine_mode fmode, tmode;
5028132718Skan  const char *fname, *tname;
5029132718Skan  const char *q;
5030132718Skan  char *libfunc_name, *suffix;
5031132718Skan  char *p;
5032132718Skan
5033132718Skan  for (fmode = first_from_mode;
5034132718Skan       fmode != VOIDmode;
5035132718Skan       fmode = GET_MODE_WIDER_MODE (fmode))
5036132718Skan    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode)));
5037132718Skan
5038132718Skan  for (tmode = first_to_mode;
5039132718Skan       tmode != VOIDmode;
5040132718Skan       tmode = GET_MODE_WIDER_MODE (tmode))
5041132718Skan    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode)));
5042132718Skan
5043132718Skan  libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
5044132718Skan  libfunc_name[0] = '_';
5045132718Skan  libfunc_name[1] = '_';
5046132718Skan  memcpy (&libfunc_name[2], opname, opname_len);
5047132718Skan  suffix = libfunc_name + opname_len + 2;
5048132718Skan
5049132718Skan  for (fmode = first_from_mode; fmode != VOIDmode;
5050132718Skan       fmode = GET_MODE_WIDER_MODE (fmode))
5051132718Skan    for (tmode = first_to_mode; tmode != VOIDmode;
5052132718Skan	 tmode = GET_MODE_WIDER_MODE (tmode))
5053132718Skan      {
5054132718Skan	fname = GET_MODE_NAME (fmode);
5055132718Skan	tname = GET_MODE_NAME (tmode);
5056132718Skan
5057132718Skan	p = suffix;
5058132718Skan	for (q = fname; *q; p++, q++)
5059132718Skan	  *p = TOLOWER (*q);
5060132718Skan	for (q = tname; *q; p++, q++)
5061132718Skan	  *p = TOLOWER (*q);
5062132718Skan
5063132718Skan	*p = '\0';
5064132718Skan
5065132718Skan	tab->handlers[tmode][fmode].libfunc
5066132718Skan	  = init_one_libfunc (ggc_alloc_string (libfunc_name,
5067132718Skan						p - libfunc_name));
5068132718Skan      }
5069132718Skan}
5070132718Skan
5071132718Skan/* Initialize the libfunc fields of an entire group of entries of an
5072132718Skan   intra-mode-class conversion optab.  The string formation rules are
5073132718Skan   similar to the ones for init_libfunc, above.  WIDENING says whether
5074132718Skan   the optab goes from narrow to wide modes or vice versa.  These functions
5075132718Skan   have two mode names _and_ an operand count.  */
5076132718Skanstatic void
5077132718Skaninit_intraclass_conv_libfuncs (convert_optab tab, const char *opname,
5078132718Skan			       enum mode_class class, bool widening)
5079132718Skan{
5080132718Skan  enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class);
5081132718Skan  size_t opname_len = strlen (opname);
5082132718Skan  size_t max_mname_len = 0;
5083132718Skan
5084132718Skan  enum machine_mode nmode, wmode;
5085132718Skan  const char *nname, *wname;
5086132718Skan  const char *q;
5087132718Skan  char *libfunc_name, *suffix;
5088132718Skan  char *p;
5089132718Skan
5090132718Skan  for (nmode = first_mode; nmode != VOIDmode;
5091132718Skan       nmode = GET_MODE_WIDER_MODE (nmode))
5092132718Skan    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode)));
5093132718Skan
5094132718Skan  libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
5095132718Skan  libfunc_name[0] = '_';
5096132718Skan  libfunc_name[1] = '_';
5097132718Skan  memcpy (&libfunc_name[2], opname, opname_len);
5098132718Skan  suffix = libfunc_name + opname_len + 2;
5099132718Skan
5100132718Skan  for (nmode = first_mode; nmode != VOIDmode;
5101132718Skan       nmode = GET_MODE_WIDER_MODE (nmode))
5102132718Skan    for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode;
5103132718Skan	 wmode = GET_MODE_WIDER_MODE (wmode))
5104132718Skan      {
5105132718Skan	nname = GET_MODE_NAME (nmode);
5106132718Skan	wname = GET_MODE_NAME (wmode);
5107132718Skan
5108132718Skan	p = suffix;
5109132718Skan	for (q = widening ? nname : wname; *q; p++, q++)
5110132718Skan	  *p = TOLOWER (*q);
5111132718Skan	for (q = widening ? wname : nname; *q; p++, q++)
5112132718Skan	  *p = TOLOWER (*q);
5113132718Skan
5114132718Skan	*p++ = '2';
5115132718Skan	*p = '\0';
5116132718Skan
5117132718Skan	tab->handlers[widening ? wmode : nmode]
5118132718Skan	             [widening ? nmode : wmode].libfunc
5119132718Skan	  = init_one_libfunc (ggc_alloc_string (libfunc_name,
5120132718Skan						p - libfunc_name));
5121132718Skan      }
5122132718Skan}
5123132718Skan
5124132718Skan
512590075Sobrienrtx
5126132718Skaninit_one_libfunc (const char *name)
512790075Sobrien{
5128132718Skan  rtx symbol;
5129132718Skan
5130117395Skan  /* Create a FUNCTION_DECL that can be passed to
5131117395Skan     targetm.encode_section_info.  */
513290075Sobrien  /* ??? We don't have any type information except for this is
513390075Sobrien     a function.  Pretend this is "int foo()".  */
513490075Sobrien  tree decl = build_decl (FUNCTION_DECL, get_identifier (name),
513590075Sobrien			  build_function_type (integer_type_node, NULL_TREE));
513690075Sobrien  DECL_ARTIFICIAL (decl) = 1;
513790075Sobrien  DECL_EXTERNAL (decl) = 1;
513890075Sobrien  TREE_PUBLIC (decl) = 1;
513918334Speter
5140132718Skan  symbol = XEXP (DECL_RTL (decl), 0);
5141132718Skan
5142132718Skan  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
5143132718Skan     are the flags assigned by targetm.encode_section_info.  */
5144169689Skan  SET_SYMBOL_REF_DECL (symbol, 0);
5145132718Skan
5146132718Skan  return symbol;
514790075Sobrien}
514890075Sobrien
5149132718Skan/* Call this to reset the function entry for one optab (OPTABLE) in mode
5150132718Skan   MODE to NAME, which should be either 0 or a string constant.  */
5151132718Skanvoid
5152132718Skanset_optab_libfunc (optab optable, enum machine_mode mode, const char *name)
5153132718Skan{
5154132718Skan  if (name)
5155132718Skan    optable->handlers[mode].libfunc = init_one_libfunc (name);
5156132718Skan  else
5157132718Skan    optable->handlers[mode].libfunc = 0;
5158132718Skan}
5159132718Skan
5160132718Skan/* Call this to reset the function entry for one conversion optab
5161132718Skan   (OPTABLE) from mode FMODE to mode TMODE to NAME, which should be
5162132718Skan   either 0 or a string constant.  */
5163132718Skanvoid
5164132718Skanset_conv_libfunc (convert_optab optable, enum machine_mode tmode,
5165132718Skan		  enum machine_mode fmode, const char *name)
5166132718Skan{
5167132718Skan  if (name)
5168132718Skan    optable->handlers[tmode][fmode].libfunc = init_one_libfunc (name);
5169132718Skan  else
5170132718Skan    optable->handlers[tmode][fmode].libfunc = 0;
5171132718Skan}
5172132718Skan
517318334Speter/* Call this once to initialize the contents of the optabs
517418334Speter   appropriately for the current target machine.  */
517518334Speter
517618334Spetervoid
5177132718Skaninit_optabs (void)
517818334Speter{
5179132718Skan  unsigned int i;
518050397Sobrien
518118334Speter  /* Start by initializing all tables to contain CODE_FOR_nothing.  */
518218334Speter
518318334Speter  for (i = 0; i < NUM_RTX_CODE; i++)
518418334Speter    setcc_gen_code[i] = CODE_FOR_nothing;
518518334Speter
518618334Speter#ifdef HAVE_conditional_move
518718334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
518818334Speter    movcc_gen_code[i] = CODE_FOR_nothing;
518918334Speter#endif
519018334Speter
5191169689Skan  for (i = 0; i < NUM_MACHINE_MODES; i++)
5192169689Skan    {
5193169689Skan      vcond_gen_code[i] = CODE_FOR_nothing;
5194169689Skan      vcondu_gen_code[i] = CODE_FOR_nothing;
5195169689Skan    }
5196169689Skan
519718334Speter  add_optab = init_optab (PLUS);
519890075Sobrien  addv_optab = init_optabv (PLUS);
519918334Speter  sub_optab = init_optab (MINUS);
520090075Sobrien  subv_optab = init_optabv (MINUS);
520118334Speter  smul_optab = init_optab (MULT);
520290075Sobrien  smulv_optab = init_optabv (MULT);
520318334Speter  smul_highpart_optab = init_optab (UNKNOWN);
520418334Speter  umul_highpart_optab = init_optab (UNKNOWN);
520518334Speter  smul_widen_optab = init_optab (UNKNOWN);
520618334Speter  umul_widen_optab = init_optab (UNKNOWN);
5207169689Skan  usmul_widen_optab = init_optab (UNKNOWN);
520818334Speter  sdiv_optab = init_optab (DIV);
520990075Sobrien  sdivv_optab = init_optabv (DIV);
521018334Speter  sdivmod_optab = init_optab (UNKNOWN);
521118334Speter  udiv_optab = init_optab (UDIV);
521218334Speter  udivmod_optab = init_optab (UNKNOWN);
521318334Speter  smod_optab = init_optab (MOD);
521418334Speter  umod_optab = init_optab (UMOD);
5215169689Skan  fmod_optab = init_optab (UNKNOWN);
5216169689Skan  drem_optab = init_optab (UNKNOWN);
521718334Speter  ftrunc_optab = init_optab (UNKNOWN);
521818334Speter  and_optab = init_optab (AND);
521918334Speter  ior_optab = init_optab (IOR);
522018334Speter  xor_optab = init_optab (XOR);
522118334Speter  ashl_optab = init_optab (ASHIFT);
522218334Speter  ashr_optab = init_optab (ASHIFTRT);
522318334Speter  lshr_optab = init_optab (LSHIFTRT);
522418334Speter  rotl_optab = init_optab (ROTATE);
522518334Speter  rotr_optab = init_optab (ROTATERT);
522618334Speter  smin_optab = init_optab (SMIN);
522718334Speter  smax_optab = init_optab (SMAX);
522818334Speter  umin_optab = init_optab (UMIN);
522918334Speter  umax_optab = init_optab (UMAX);
5230132718Skan  pow_optab = init_optab (UNKNOWN);
5231132718Skan  atan2_optab = init_optab (UNKNOWN);
523290075Sobrien
523390075Sobrien  /* These three have codes assigned exclusively for the sake of
523490075Sobrien     have_insn_for.  */
523590075Sobrien  mov_optab = init_optab (SET);
523690075Sobrien  movstrict_optab = init_optab (STRICT_LOW_PART);
523790075Sobrien  cmp_optab = init_optab (COMPARE);
523890075Sobrien
523918334Speter  ucmp_optab = init_optab (UNKNOWN);
524018334Speter  tst_optab = init_optab (UNKNOWN);
5241132718Skan
5242132718Skan  eq_optab = init_optab (EQ);
5243132718Skan  ne_optab = init_optab (NE);
5244132718Skan  gt_optab = init_optab (GT);
5245132718Skan  ge_optab = init_optab (GE);
5246132718Skan  lt_optab = init_optab (LT);
5247132718Skan  le_optab = init_optab (LE);
5248132718Skan  unord_optab = init_optab (UNORDERED);
5249132718Skan
525018334Speter  neg_optab = init_optab (NEG);
525190075Sobrien  negv_optab = init_optabv (NEG);
525218334Speter  abs_optab = init_optab (ABS);
525390075Sobrien  absv_optab = init_optabv (ABS);
5254132718Skan  addcc_optab = init_optab (UNKNOWN);
525518334Speter  one_cmpl_optab = init_optab (NOT);
525618334Speter  ffs_optab = init_optab (FFS);
5257132718Skan  clz_optab = init_optab (CLZ);
5258132718Skan  ctz_optab = init_optab (CTZ);
5259132718Skan  popcount_optab = init_optab (POPCOUNT);
5260132718Skan  parity_optab = init_optab (PARITY);
526118334Speter  sqrt_optab = init_optab (SQRT);
5262132718Skan  floor_optab = init_optab (UNKNOWN);
5263169689Skan  lfloor_optab = init_optab (UNKNOWN);
5264132718Skan  ceil_optab = init_optab (UNKNOWN);
5265169689Skan  lceil_optab = init_optab (UNKNOWN);
5266132718Skan  round_optab = init_optab (UNKNOWN);
5267132718Skan  btrunc_optab = init_optab (UNKNOWN);
5268132718Skan  nearbyint_optab = init_optab (UNKNOWN);
5269169689Skan  rint_optab = init_optab (UNKNOWN);
5270169689Skan  lrint_optab = init_optab (UNKNOWN);
5271169689Skan  sincos_optab = init_optab (UNKNOWN);
527218334Speter  sin_optab = init_optab (UNKNOWN);
5273169689Skan  asin_optab = init_optab (UNKNOWN);
527418334Speter  cos_optab = init_optab (UNKNOWN);
5275169689Skan  acos_optab = init_optab (UNKNOWN);
5276117395Skan  exp_optab = init_optab (UNKNOWN);
5277169689Skan  exp10_optab = init_optab (UNKNOWN);
5278169689Skan  exp2_optab = init_optab (UNKNOWN);
5279169689Skan  expm1_optab = init_optab (UNKNOWN);
5280169689Skan  ldexp_optab = init_optab (UNKNOWN);
5281169689Skan  logb_optab = init_optab (UNKNOWN);
5282169689Skan  ilogb_optab = init_optab (UNKNOWN);
5283117395Skan  log_optab = init_optab (UNKNOWN);
5284169689Skan  log10_optab = init_optab (UNKNOWN);
5285169689Skan  log2_optab = init_optab (UNKNOWN);
5286169689Skan  log1p_optab = init_optab (UNKNOWN);
5287132718Skan  tan_optab = init_optab (UNKNOWN);
5288132718Skan  atan_optab = init_optab (UNKNOWN);
5289169689Skan  copysign_optab = init_optab (UNKNOWN);
5290169689Skan
529118334Speter  strlen_optab = init_optab (UNKNOWN);
529290075Sobrien  cbranch_optab = init_optab (UNKNOWN);
529390075Sobrien  cmov_optab = init_optab (UNKNOWN);
529490075Sobrien  cstore_optab = init_optab (UNKNOWN);
529590075Sobrien  push_optab = init_optab (UNKNOWN);
529618334Speter
5297169689Skan  reduc_smax_optab = init_optab (UNKNOWN);
5298169689Skan  reduc_umax_optab = init_optab (UNKNOWN);
5299169689Skan  reduc_smin_optab = init_optab (UNKNOWN);
5300169689Skan  reduc_umin_optab = init_optab (UNKNOWN);
5301169689Skan  reduc_splus_optab = init_optab (UNKNOWN);
5302169689Skan  reduc_uplus_optab = init_optab (UNKNOWN);
5303169689Skan
5304169689Skan  ssum_widen_optab = init_optab (UNKNOWN);
5305169689Skan  usum_widen_optab = init_optab (UNKNOWN);
5306169689Skan  sdot_prod_optab = init_optab (UNKNOWN);
5307169689Skan  udot_prod_optab = init_optab (UNKNOWN);
5308169689Skan
5309132718Skan  vec_extract_optab = init_optab (UNKNOWN);
5310132718Skan  vec_set_optab = init_optab (UNKNOWN);
5311132718Skan  vec_init_optab = init_optab (UNKNOWN);
5312169689Skan  vec_shl_optab = init_optab (UNKNOWN);
5313169689Skan  vec_shr_optab = init_optab (UNKNOWN);
5314169689Skan  vec_realign_load_optab = init_optab (UNKNOWN);
5315169689Skan  movmisalign_optab = init_optab (UNKNOWN);
5316169689Skan
5317169689Skan  powi_optab = init_optab (UNKNOWN);
5318169689Skan
5319132718Skan  /* Conversions.  */
5320132718Skan  sext_optab = init_convert_optab (SIGN_EXTEND);
5321132718Skan  zext_optab = init_convert_optab (ZERO_EXTEND);
5322132718Skan  trunc_optab = init_convert_optab (TRUNCATE);
5323132718Skan  sfix_optab = init_convert_optab (FIX);
5324132718Skan  ufix_optab = init_convert_optab (UNSIGNED_FIX);
5325132718Skan  sfixtrunc_optab = init_convert_optab (UNKNOWN);
5326132718Skan  ufixtrunc_optab = init_convert_optab (UNKNOWN);
5327132718Skan  sfloat_optab = init_convert_optab (FLOAT);
5328132718Skan  ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
5329132718Skan
533018334Speter  for (i = 0; i < NUM_MACHINE_MODES; i++)
533118334Speter    {
5332169689Skan      movmem_optab[i] = CODE_FOR_nothing;
5333132718Skan      cmpstr_optab[i] = CODE_FOR_nothing;
5334169689Skan      cmpstrn_optab[i] = CODE_FOR_nothing;
5335132718Skan      cmpmem_optab[i] = CODE_FOR_nothing;
5336169689Skan      setmem_optab[i] = CODE_FOR_nothing;
533718334Speter
5338169689Skan      sync_add_optab[i] = CODE_FOR_nothing;
5339169689Skan      sync_sub_optab[i] = CODE_FOR_nothing;
5340169689Skan      sync_ior_optab[i] = CODE_FOR_nothing;
5341169689Skan      sync_and_optab[i] = CODE_FOR_nothing;
5342169689Skan      sync_xor_optab[i] = CODE_FOR_nothing;
5343169689Skan      sync_nand_optab[i] = CODE_FOR_nothing;
5344169689Skan      sync_old_add_optab[i] = CODE_FOR_nothing;
5345169689Skan      sync_old_sub_optab[i] = CODE_FOR_nothing;
5346169689Skan      sync_old_ior_optab[i] = CODE_FOR_nothing;
5347169689Skan      sync_old_and_optab[i] = CODE_FOR_nothing;
5348169689Skan      sync_old_xor_optab[i] = CODE_FOR_nothing;
5349169689Skan      sync_old_nand_optab[i] = CODE_FOR_nothing;
5350169689Skan      sync_new_add_optab[i] = CODE_FOR_nothing;
5351169689Skan      sync_new_sub_optab[i] = CODE_FOR_nothing;
5352169689Skan      sync_new_ior_optab[i] = CODE_FOR_nothing;
5353169689Skan      sync_new_and_optab[i] = CODE_FOR_nothing;
5354169689Skan      sync_new_xor_optab[i] = CODE_FOR_nothing;
5355169689Skan      sync_new_nand_optab[i] = CODE_FOR_nothing;
5356169689Skan      sync_compare_and_swap[i] = CODE_FOR_nothing;
5357169689Skan      sync_compare_and_swap_cc[i] = CODE_FOR_nothing;
5358169689Skan      sync_lock_test_and_set[i] = CODE_FOR_nothing;
5359169689Skan      sync_lock_release[i] = CODE_FOR_nothing;
5360169689Skan
536118334Speter      reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
536218334Speter    }
536318334Speter
536418334Speter  /* Fill in the optabs with the insns we support.  */
536518334Speter  init_all_optabs ();
536618334Speter
536718334Speter  /* Initialize the optabs with the names of the library functions.  */
536818334Speter  init_integral_libfuncs (add_optab, "add", '3');
536918334Speter  init_floating_libfuncs (add_optab, "add", '3');
537090075Sobrien  init_integral_libfuncs (addv_optab, "addv", '3');
537190075Sobrien  init_floating_libfuncs (addv_optab, "add", '3');
537218334Speter  init_integral_libfuncs (sub_optab, "sub", '3');
537318334Speter  init_floating_libfuncs (sub_optab, "sub", '3');
537490075Sobrien  init_integral_libfuncs (subv_optab, "subv", '3');
537590075Sobrien  init_floating_libfuncs (subv_optab, "sub", '3');
537618334Speter  init_integral_libfuncs (smul_optab, "mul", '3');
537718334Speter  init_floating_libfuncs (smul_optab, "mul", '3');
537890075Sobrien  init_integral_libfuncs (smulv_optab, "mulv", '3');
537990075Sobrien  init_floating_libfuncs (smulv_optab, "mul", '3');
538018334Speter  init_integral_libfuncs (sdiv_optab, "div", '3');
538190075Sobrien  init_floating_libfuncs (sdiv_optab, "div", '3');
538290075Sobrien  init_integral_libfuncs (sdivv_optab, "divv", '3');
538318334Speter  init_integral_libfuncs (udiv_optab, "udiv", '3');
538418334Speter  init_integral_libfuncs (sdivmod_optab, "divmod", '4');
538518334Speter  init_integral_libfuncs (udivmod_optab, "udivmod", '4');
538618334Speter  init_integral_libfuncs (smod_optab, "mod", '3');
538718334Speter  init_integral_libfuncs (umod_optab, "umod", '3');
538818334Speter  init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
538918334Speter  init_integral_libfuncs (and_optab, "and", '3');
539018334Speter  init_integral_libfuncs (ior_optab, "ior", '3');
539118334Speter  init_integral_libfuncs (xor_optab, "xor", '3');
539218334Speter  init_integral_libfuncs (ashl_optab, "ashl", '3');
539318334Speter  init_integral_libfuncs (ashr_optab, "ashr", '3');
539418334Speter  init_integral_libfuncs (lshr_optab, "lshr", '3');
539518334Speter  init_integral_libfuncs (smin_optab, "min", '3');
539618334Speter  init_floating_libfuncs (smin_optab, "min", '3');
539718334Speter  init_integral_libfuncs (smax_optab, "max", '3');
539818334Speter  init_floating_libfuncs (smax_optab, "max", '3');
539918334Speter  init_integral_libfuncs (umin_optab, "umin", '3');
540018334Speter  init_integral_libfuncs (umax_optab, "umax", '3');
540118334Speter  init_integral_libfuncs (neg_optab, "neg", '2');
540218334Speter  init_floating_libfuncs (neg_optab, "neg", '2');
540390075Sobrien  init_integral_libfuncs (negv_optab, "negv", '2');
540490075Sobrien  init_floating_libfuncs (negv_optab, "neg", '2');
540518334Speter  init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
540618334Speter  init_integral_libfuncs (ffs_optab, "ffs", '2');
5407132718Skan  init_integral_libfuncs (clz_optab, "clz", '2');
5408132718Skan  init_integral_libfuncs (ctz_optab, "ctz", '2');
5409132718Skan  init_integral_libfuncs (popcount_optab, "popcount", '2');
5410132718Skan  init_integral_libfuncs (parity_optab, "parity", '2');
541118334Speter
5412169689Skan  /* Comparison libcalls for integers MUST come in pairs,
5413169689Skan     signed/unsigned.  */
541418334Speter  init_integral_libfuncs (cmp_optab, "cmp", '2');
541518334Speter  init_integral_libfuncs (ucmp_optab, "ucmp", '2');
541618334Speter  init_floating_libfuncs (cmp_optab, "cmp", '2');
541718334Speter
5418132718Skan  /* EQ etc are floating point only.  */
5419132718Skan  init_floating_libfuncs (eq_optab, "eq", '2');
5420132718Skan  init_floating_libfuncs (ne_optab, "ne", '2');
5421132718Skan  init_floating_libfuncs (gt_optab, "gt", '2');
5422132718Skan  init_floating_libfuncs (ge_optab, "ge", '2');
5423132718Skan  init_floating_libfuncs (lt_optab, "lt", '2');
5424132718Skan  init_floating_libfuncs (le_optab, "le", '2');
5425132718Skan  init_floating_libfuncs (unord_optab, "unord", '2');
542618334Speter
5427169689Skan  init_floating_libfuncs (powi_optab, "powi", '2');
5428169689Skan
5429132718Skan  /* Conversions.  */
5430169689Skan  init_interclass_conv_libfuncs (sfloat_optab, "float",
5431169689Skan				 MODE_INT, MODE_FLOAT);
5432169689Skan  init_interclass_conv_libfuncs (sfloat_optab, "float",
5433169689Skan				 MODE_INT, MODE_DECIMAL_FLOAT);
5434169689Skan  init_interclass_conv_libfuncs (ufloat_optab, "floatun",
5435169689Skan				 MODE_INT, MODE_FLOAT);
5436169689Skan  init_interclass_conv_libfuncs (ufloat_optab, "floatun",
5437169689Skan				 MODE_INT, MODE_DECIMAL_FLOAT);
5438169689Skan  init_interclass_conv_libfuncs (sfix_optab, "fix",
5439169689Skan				 MODE_FLOAT, MODE_INT);
5440169689Skan  init_interclass_conv_libfuncs (sfix_optab, "fix",
5441169689Skan				 MODE_DECIMAL_FLOAT, MODE_INT);
5442169689Skan  init_interclass_conv_libfuncs (ufix_optab, "fixuns",
5443169689Skan				 MODE_FLOAT, MODE_INT);
5444169689Skan  init_interclass_conv_libfuncs (ufix_optab, "fixuns",
5445169689Skan				 MODE_DECIMAL_FLOAT, MODE_INT);
5446169689Skan  init_interclass_conv_libfuncs (ufloat_optab, "floatuns",
5447169689Skan				 MODE_INT, MODE_DECIMAL_FLOAT);
544818334Speter
5449132718Skan  /* sext_optab is also used for FLOAT_EXTEND.  */
5450132718Skan  init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);
5451169689Skan  init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, true);
5452169689Skan  init_interclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, MODE_DECIMAL_FLOAT);
5453169689Skan  init_interclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, MODE_FLOAT);
5454132718Skan  init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false);
5455169689Skan  init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, false);
5456169689Skan  init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, MODE_DECIMAL_FLOAT);
5457169689Skan  init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, MODE_FLOAT);
545818334Speter
5459132718Skan  /* Use cabs for double complex abs, since systems generally have cabs.
5460132718Skan     Don't define any libcall for float complex, so that cabs will be used.  */
5461132718Skan  if (complex_double_type_node)
5462132718Skan    abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc
5463132718Skan      = init_one_libfunc ("cabs");
546418334Speter
546518334Speter  /* The ffs function operates on `int'.  */
546690075Sobrien  ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
546790075Sobrien    = init_one_libfunc ("ffs");
546818334Speter
546996263Sobrien  abort_libfunc = init_one_libfunc ("abort");
547090075Sobrien  memcpy_libfunc = init_one_libfunc ("memcpy");
547190075Sobrien  memmove_libfunc = init_one_libfunc ("memmove");
547290075Sobrien  memcmp_libfunc = init_one_libfunc ("memcmp");
547390075Sobrien  memset_libfunc = init_one_libfunc ("memset");
5474132718Skan  setbits_libfunc = init_one_libfunc ("__setbits");
547518334Speter
547650397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
547790075Sobrien  setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
547890075Sobrien  longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
547950397Sobrien#else
548090075Sobrien  setjmp_libfunc = init_one_libfunc ("setjmp");
548190075Sobrien  longjmp_libfunc = init_one_libfunc ("longjmp");
548250397Sobrien#endif
548390075Sobrien  unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
548490075Sobrien  unwind_sjlj_unregister_libfunc
548590075Sobrien    = init_one_libfunc ("_Unwind_SjLj_Unregister");
548618334Speter
548752284Sobrien  /* For function entry/exit instrumentation.  */
548852284Sobrien  profile_function_entry_libfunc
548990075Sobrien    = init_one_libfunc ("__cyg_profile_func_enter");
549052284Sobrien  profile_function_exit_libfunc
549190075Sobrien    = init_one_libfunc ("__cyg_profile_func_exit");
549252284Sobrien
5493132718Skan  gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
5494132718Skan
5495117395Skan  if (HAVE_conditional_trap)
5496117395Skan    trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
549750397Sobrien
549818334Speter  /* Allow the target to add more libcalls or rename some, etc.  */
5499132718Skan  targetm.init_libfuncs ();
550018334Speter}
5501169689Skan
5502169689Skan#ifdef DEBUG
5503169689Skan
5504169689Skan/* Print information about the current contents of the optabs on
5505169689Skan   STDERR.  */
5506169689Skan
5507169689Skanstatic void
5508169689Skandebug_optab_libfuncs (void)
5509169689Skan{
5510169689Skan  int i;
5511169689Skan  int j;
5512169689Skan  int k;
5513169689Skan
5514169689Skan  /* Dump the arithmetic optabs.  */
5515169689Skan  for (i = 0; i != (int) OTI_MAX; i++)
5516169689Skan    for (j = 0; j < NUM_MACHINE_MODES; ++j)
5517169689Skan      {
5518169689Skan	optab o;
5519169689Skan	struct optab_handlers *h;
5520169689Skan
5521169689Skan	o = optab_table[i];
5522169689Skan	h = &o->handlers[j];
5523169689Skan	if (h->libfunc)
5524169689Skan	  {
5525169689Skan	    gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF);
5526169689Skan	    fprintf (stderr, "%s\t%s:\t%s\n",
5527169689Skan		     GET_RTX_NAME (o->code),
5528169689Skan		     GET_MODE_NAME (j),
5529169689Skan		     XSTR (h->libfunc, 0));
5530169689Skan	  }
5531169689Skan      }
5532169689Skan
5533169689Skan  /* Dump the conversion optabs.  */
5534169689Skan  for (i = 0; i < (int) COI_MAX; ++i)
5535169689Skan    for (j = 0; j < NUM_MACHINE_MODES; ++j)
5536169689Skan      for (k = 0; k < NUM_MACHINE_MODES; ++k)
5537169689Skan	{
5538169689Skan	  convert_optab o;
5539169689Skan	  struct optab_handlers *h;
5540169689Skan
5541169689Skan	  o = &convert_optab_table[i];
5542169689Skan	  h = &o->handlers[j][k];
5543169689Skan	  if (h->libfunc)
5544169689Skan	    {
5545169689Skan	      gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF);
5546169689Skan	      fprintf (stderr, "%s\t%s\t%s:\t%s\n",
5547169689Skan		       GET_RTX_NAME (o->code),
5548169689Skan		       GET_MODE_NAME (j),
5549169689Skan		       GET_MODE_NAME (k),
5550169689Skan		       XSTR (h->libfunc, 0));
5551169689Skan	    }
5552169689Skan	}
5553169689Skan}
5554169689Skan
5555169689Skan#endif /* DEBUG */
5556169689Skan
555750397Sobrien
555850397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
555950397Sobrien   CODE.  Return 0 on failure.  */
556050397Sobrien
556150397Sobrienrtx
5562132718Skangen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1,
5563132718Skan	       rtx op2 ATTRIBUTE_UNUSED, rtx tcode ATTRIBUTE_UNUSED)
556450397Sobrien{
556550397Sobrien  enum machine_mode mode = GET_MODE (op1);
5566117395Skan  enum insn_code icode;
5567117395Skan  rtx insn;
556850397Sobrien
5569117395Skan  if (!HAVE_conditional_trap)
5570117395Skan    return 0;
5571117395Skan
557250397Sobrien  if (mode == VOIDmode)
557350397Sobrien    return 0;
557450397Sobrien
5575117395Skan  icode = cmp_optab->handlers[(int) mode].insn_code;
5576117395Skan  if (icode == CODE_FOR_nothing)
5577117395Skan    return 0;
5578117395Skan
5579117395Skan  start_sequence ();
5580117395Skan  op1 = prepare_operand (icode, op1, 0, mode, mode, 0);
5581119256Skan  op2 = prepare_operand (icode, op2, 1, mode, mode, 0);
5582119256Skan  if (!op1 || !op2)
5583119256Skan    {
5584119256Skan      end_sequence ();
5585119256Skan      return 0;
5586119256Skan    }
5587117395Skan  emit_insn (GEN_FCN (icode) (op1, op2));
5588117395Skan
5589117395Skan  PUT_CODE (trap_rtx, code);
5590169689Skan  gcc_assert (HAVE_conditional_trap);
5591117395Skan  insn = gen_conditional_trap (trap_rtx, tcode);
5592117395Skan  if (insn)
559350397Sobrien    {
5594117395Skan      emit_insn (insn);
5595117395Skan      insn = get_insns ();
559650397Sobrien    }
5597117395Skan  end_sequence ();
559850397Sobrien
5599117395Skan  return insn;
560050397Sobrien}
5601117395Skan
5602169689Skan/* Return rtx code for TCODE. Use UNSIGNEDP to select signed
5603169689Skan   or unsigned operation code.  */
5604169689Skan
5605169689Skanstatic enum rtx_code
5606169689Skanget_rtx_code (enum tree_code tcode, bool unsignedp)
5607169689Skan{
5608169689Skan  enum rtx_code code;
5609169689Skan  switch (tcode)
5610169689Skan    {
5611169689Skan    case EQ_EXPR:
5612169689Skan      code = EQ;
5613169689Skan      break;
5614169689Skan    case NE_EXPR:
5615169689Skan      code = NE;
5616169689Skan      break;
5617169689Skan    case LT_EXPR:
5618169689Skan      code = unsignedp ? LTU : LT;
5619169689Skan      break;
5620169689Skan    case LE_EXPR:
5621169689Skan      code = unsignedp ? LEU : LE;
5622169689Skan      break;
5623169689Skan    case GT_EXPR:
5624169689Skan      code = unsignedp ? GTU : GT;
5625169689Skan      break;
5626169689Skan    case GE_EXPR:
5627169689Skan      code = unsignedp ? GEU : GE;
5628169689Skan      break;
5629169689Skan
5630169689Skan    case UNORDERED_EXPR:
5631169689Skan      code = UNORDERED;
5632169689Skan      break;
5633169689Skan    case ORDERED_EXPR:
5634169689Skan      code = ORDERED;
5635169689Skan      break;
5636169689Skan    case UNLT_EXPR:
5637169689Skan      code = UNLT;
5638169689Skan      break;
5639169689Skan    case UNLE_EXPR:
5640169689Skan      code = UNLE;
5641169689Skan      break;
5642169689Skan    case UNGT_EXPR:
5643169689Skan      code = UNGT;
5644169689Skan      break;
5645169689Skan    case UNGE_EXPR:
5646169689Skan      code = UNGE;
5647169689Skan      break;
5648169689Skan    case UNEQ_EXPR:
5649169689Skan      code = UNEQ;
5650169689Skan      break;
5651169689Skan    case LTGT_EXPR:
5652169689Skan      code = LTGT;
5653169689Skan      break;
5654169689Skan
5655169689Skan    default:
5656169689Skan      gcc_unreachable ();
5657169689Skan    }
5658169689Skan  return code;
5659169689Skan}
5660169689Skan
5661169689Skan/* Return comparison rtx for COND. Use UNSIGNEDP to select signed or
5662169689Skan   unsigned operators. Do not generate compare instruction.  */
5663169689Skan
5664169689Skanstatic rtx
5665169689Skanvector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
5666169689Skan{
5667169689Skan  enum rtx_code rcode;
5668169689Skan  tree t_op0, t_op1;
5669169689Skan  rtx rtx_op0, rtx_op1;
5670169689Skan
5671169689Skan  /* This is unlikely. While generating VEC_COND_EXPR, auto vectorizer
5672169689Skan     ensures that condition is a relational operation.  */
5673169689Skan  gcc_assert (COMPARISON_CLASS_P (cond));
5674169689Skan
5675169689Skan  rcode = get_rtx_code (TREE_CODE (cond), unsignedp);
5676169689Skan  t_op0 = TREE_OPERAND (cond, 0);
5677169689Skan  t_op1 = TREE_OPERAND (cond, 1);
5678169689Skan
5679169689Skan  /* Expand operands.  */
5680169689Skan  rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)), 1);
5681169689Skan  rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), 1);
5682169689Skan
5683169689Skan  if (!insn_data[icode].operand[4].predicate (rtx_op0, GET_MODE (rtx_op0))
5684169689Skan      && GET_MODE (rtx_op0) != VOIDmode)
5685169689Skan    rtx_op0 = force_reg (GET_MODE (rtx_op0), rtx_op0);
5686169689Skan
5687169689Skan  if (!insn_data[icode].operand[5].predicate (rtx_op1, GET_MODE (rtx_op1))
5688169689Skan      && GET_MODE (rtx_op1) != VOIDmode)
5689169689Skan    rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1);
5690169689Skan
5691169689Skan  return gen_rtx_fmt_ee (rcode, VOIDmode, rtx_op0, rtx_op1);
5692169689Skan}
5693169689Skan
5694169689Skan/* Return insn code for VEC_COND_EXPR EXPR.  */
5695169689Skan
5696169689Skanstatic inline enum insn_code
5697169689Skanget_vcond_icode (tree expr, enum machine_mode mode)
5698169689Skan{
5699169689Skan  enum insn_code icode = CODE_FOR_nothing;
5700169689Skan
5701169689Skan  if (TYPE_UNSIGNED (TREE_TYPE (expr)))
5702169689Skan    icode = vcondu_gen_code[mode];
5703169689Skan  else
5704169689Skan    icode = vcond_gen_code[mode];
5705169689Skan  return icode;
5706169689Skan}
5707169689Skan
5708169689Skan/* Return TRUE iff, appropriate vector insns are available
5709169689Skan   for vector cond expr expr in VMODE mode.  */
5710169689Skan
5711169689Skanbool
5712169689Skanexpand_vec_cond_expr_p (tree expr, enum machine_mode vmode)
5713169689Skan{
5714169689Skan  if (get_vcond_icode (expr, vmode) == CODE_FOR_nothing)
5715169689Skan    return false;
5716169689Skan  return true;
5717169689Skan}
5718169689Skan
5719169689Skan/* Generate insns for VEC_COND_EXPR.  */
5720169689Skan
5721169689Skanrtx
5722169689Skanexpand_vec_cond_expr (tree vec_cond_expr, rtx target)
5723169689Skan{
5724169689Skan  enum insn_code icode;
5725169689Skan  rtx comparison, rtx_op1, rtx_op2, cc_op0, cc_op1;
5726169689Skan  enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_cond_expr));
5727169689Skan  bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (vec_cond_expr));
5728169689Skan
5729169689Skan  icode = get_vcond_icode (vec_cond_expr, mode);
5730169689Skan  if (icode == CODE_FOR_nothing)
5731169689Skan    return 0;
5732169689Skan
5733169689Skan  if (!target || !insn_data[icode].operand[0].predicate (target, mode))
5734169689Skan    target = gen_reg_rtx (mode);
5735169689Skan
5736169689Skan  /* Get comparison rtx.  First expand both cond expr operands.  */
5737169689Skan  comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0),
5738169689Skan				   unsignedp, icode);
5739169689Skan  cc_op0 = XEXP (comparison, 0);
5740169689Skan  cc_op1 = XEXP (comparison, 1);
5741169689Skan  /* Expand both operands and force them in reg, if required.  */
5742169689Skan  rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1),
5743169689Skan			 NULL_RTX, VOIDmode, EXPAND_NORMAL);
5744169689Skan  if (!insn_data[icode].operand[1].predicate (rtx_op1, mode)
5745169689Skan      && mode != VOIDmode)
5746169689Skan    rtx_op1 = force_reg (mode, rtx_op1);
5747169689Skan
5748169689Skan  rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2),
5749169689Skan			 NULL_RTX, VOIDmode, EXPAND_NORMAL);
5750169689Skan  if (!insn_data[icode].operand[2].predicate (rtx_op2, mode)
5751169689Skan      && mode != VOIDmode)
5752169689Skan    rtx_op2 = force_reg (mode, rtx_op2);
5753169689Skan
5754169689Skan  /* Emit instruction! */
5755169689Skan  emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2,
5756169689Skan			      comparison, cc_op0,  cc_op1));
5757169689Skan
5758169689Skan  return target;
5759169689Skan}
5760169689Skan
5761169689Skan
5762169689Skan/* This is an internal subroutine of the other compare_and_swap expanders.
5763169689Skan   MEM, OLD_VAL and NEW_VAL are as you'd expect for a compare-and-swap
5764169689Skan   operation.  TARGET is an optional place to store the value result of
5765169689Skan   the operation.  ICODE is the particular instruction to expand.  Return
5766169689Skan   the result of the operation.  */
5767169689Skan
5768169689Skanstatic rtx
5769169689Skanexpand_val_compare_and_swap_1 (rtx mem, rtx old_val, rtx new_val,
5770169689Skan			       rtx target, enum insn_code icode)
5771169689Skan{
5772169689Skan  enum machine_mode mode = GET_MODE (mem);
5773169689Skan  rtx insn;
5774169689Skan
5775169689Skan  if (!target || !insn_data[icode].operand[0].predicate (target, mode))
5776169689Skan    target = gen_reg_rtx (mode);
5777169689Skan
5778169689Skan  if (GET_MODE (old_val) != VOIDmode && GET_MODE (old_val) != mode)
5779169689Skan    old_val = convert_modes (mode, GET_MODE (old_val), old_val, 1);
5780169689Skan  if (!insn_data[icode].operand[2].predicate (old_val, mode))
5781169689Skan    old_val = force_reg (mode, old_val);
5782169689Skan
5783169689Skan  if (GET_MODE (new_val) != VOIDmode && GET_MODE (new_val) != mode)
5784169689Skan    new_val = convert_modes (mode, GET_MODE (new_val), new_val, 1);
5785169689Skan  if (!insn_data[icode].operand[3].predicate (new_val, mode))
5786169689Skan    new_val = force_reg (mode, new_val);
5787169689Skan
5788169689Skan  insn = GEN_FCN (icode) (target, mem, old_val, new_val);
5789169689Skan  if (insn == NULL_RTX)
5790169689Skan    return NULL_RTX;
5791169689Skan  emit_insn (insn);
5792169689Skan
5793169689Skan  return target;
5794169689Skan}
5795169689Skan
5796169689Skan/* Expand a compare-and-swap operation and return its value.  */
5797169689Skan
5798169689Skanrtx
5799169689Skanexpand_val_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
5800169689Skan{
5801169689Skan  enum machine_mode mode = GET_MODE (mem);
5802169689Skan  enum insn_code icode = sync_compare_and_swap[mode];
5803169689Skan
5804169689Skan  if (icode == CODE_FOR_nothing)
5805169689Skan    return NULL_RTX;
5806169689Skan
5807169689Skan  return expand_val_compare_and_swap_1 (mem, old_val, new_val, target, icode);
5808169689Skan}
5809169689Skan
5810169689Skan/* Expand a compare-and-swap operation and store true into the result if
5811169689Skan   the operation was successful and false otherwise.  Return the result.
5812169689Skan   Unlike other routines, TARGET is not optional.  */
5813169689Skan
5814169689Skanrtx
5815169689Skanexpand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
5816169689Skan{
5817169689Skan  enum machine_mode mode = GET_MODE (mem);
5818169689Skan  enum insn_code icode;
5819169689Skan  rtx subtarget, label0, label1;
5820169689Skan
5821169689Skan  /* If the target supports a compare-and-swap pattern that simultaneously
5822169689Skan     sets some flag for success, then use it.  Otherwise use the regular
5823169689Skan     compare-and-swap and follow that immediately with a compare insn.  */
5824169689Skan  icode = sync_compare_and_swap_cc[mode];
5825169689Skan  switch (icode)
5826169689Skan    {
5827169689Skan    default:
5828169689Skan      subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
5829169689Skan						 NULL_RTX, icode);
5830169689Skan      if (subtarget != NULL_RTX)
5831169689Skan	break;
5832169689Skan
5833169689Skan      /* FALLTHRU */
5834169689Skan    case CODE_FOR_nothing:
5835169689Skan      icode = sync_compare_and_swap[mode];
5836169689Skan      if (icode == CODE_FOR_nothing)
5837169689Skan	return NULL_RTX;
5838169689Skan
5839169689Skan      /* Ensure that if old_val == mem, that we're not comparing
5840169689Skan	 against an old value.  */
5841169689Skan      if (MEM_P (old_val))
5842169689Skan	old_val = force_reg (mode, old_val);
5843169689Skan
5844169689Skan      subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
5845169689Skan						 NULL_RTX, icode);
5846169689Skan      if (subtarget == NULL_RTX)
5847169689Skan	return NULL_RTX;
5848169689Skan
5849169689Skan      emit_cmp_insn (subtarget, old_val, EQ, const0_rtx, mode, true);
5850169689Skan    }
5851169689Skan
5852169689Skan  /* If the target has a sane STORE_FLAG_VALUE, then go ahead and use a
5853169689Skan     setcc instruction from the beginning.  We don't work too hard here,
5854169689Skan     but it's nice to not be stupid about initial code gen either.  */
5855169689Skan  if (STORE_FLAG_VALUE == 1)
5856169689Skan    {
5857169689Skan      icode = setcc_gen_code[EQ];
5858169689Skan      if (icode != CODE_FOR_nothing)
5859169689Skan	{
5860169689Skan	  enum machine_mode cmode = insn_data[icode].operand[0].mode;
5861169689Skan	  rtx insn;
5862169689Skan
5863169689Skan	  subtarget = target;
5864169689Skan	  if (!insn_data[icode].operand[0].predicate (target, cmode))
5865169689Skan	    subtarget = gen_reg_rtx (cmode);
5866169689Skan
5867169689Skan	  insn = GEN_FCN (icode) (subtarget);
5868169689Skan	  if (insn)
5869169689Skan	    {
5870169689Skan	      emit_insn (insn);
5871169689Skan	      if (GET_MODE (target) != GET_MODE (subtarget))
5872169689Skan		{
5873169689Skan	          convert_move (target, subtarget, 1);
5874169689Skan		  subtarget = target;
5875169689Skan		}
5876169689Skan	      return subtarget;
5877169689Skan	    }
5878169689Skan	}
5879169689Skan    }
5880169689Skan
5881169689Skan  /* Without an appropriate setcc instruction, use a set of branches to
5882169689Skan     get 1 and 0 stored into target.  Presumably if the target has a
5883169689Skan     STORE_FLAG_VALUE that isn't 1, then this will get cleaned up by ifcvt.  */
5884169689Skan
5885169689Skan  label0 = gen_label_rtx ();
5886169689Skan  label1 = gen_label_rtx ();
5887169689Skan
5888169689Skan  emit_jump_insn (bcc_gen_fctn[EQ] (label0));
5889169689Skan  emit_move_insn (target, const0_rtx);
5890169689Skan  emit_jump_insn (gen_jump (label1));
5891169689Skan  emit_barrier ();
5892169689Skan  emit_label (label0);
5893169689Skan  emit_move_insn (target, const1_rtx);
5894169689Skan  emit_label (label1);
5895169689Skan
5896169689Skan  return target;
5897169689Skan}
5898169689Skan
5899169689Skan/* This is a helper function for the other atomic operations.  This function
5900169689Skan   emits a loop that contains SEQ that iterates until a compare-and-swap
5901169689Skan   operation at the end succeeds.  MEM is the memory to be modified.  SEQ is
5902169689Skan   a set of instructions that takes a value from OLD_REG as an input and
5903169689Skan   produces a value in NEW_REG as an output.  Before SEQ, OLD_REG will be
5904169689Skan   set to the current contents of MEM.  After SEQ, a compare-and-swap will
5905169689Skan   attempt to update MEM with NEW_REG.  The function returns true when the
5906169689Skan   loop was generated successfully.  */
5907169689Skan
5908169689Skanstatic bool
5909169689Skanexpand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
5910169689Skan{
5911169689Skan  enum machine_mode mode = GET_MODE (mem);
5912169689Skan  enum insn_code icode;
5913169689Skan  rtx label, cmp_reg, subtarget;
5914169689Skan
5915169689Skan  /* The loop we want to generate looks like
5916169689Skan
5917169689Skan	cmp_reg = mem;
5918169689Skan      label:
5919169689Skan        old_reg = cmp_reg;
5920169689Skan	seq;
5921169689Skan	cmp_reg = compare-and-swap(mem, old_reg, new_reg)
5922169689Skan	if (cmp_reg != old_reg)
5923169689Skan	  goto label;
5924169689Skan
5925169689Skan     Note that we only do the plain load from memory once.  Subsequent
5926169689Skan     iterations use the value loaded by the compare-and-swap pattern.  */
5927169689Skan
5928169689Skan  label = gen_label_rtx ();
5929169689Skan  cmp_reg = gen_reg_rtx (mode);
5930169689Skan
5931169689Skan  emit_move_insn (cmp_reg, mem);
5932169689Skan  emit_label (label);
5933169689Skan  emit_move_insn (old_reg, cmp_reg);
5934169689Skan  if (seq)
5935169689Skan    emit_insn (seq);
5936169689Skan
5937169689Skan  /* If the target supports a compare-and-swap pattern that simultaneously
5938169689Skan     sets some flag for success, then use it.  Otherwise use the regular
5939169689Skan     compare-and-swap and follow that immediately with a compare insn.  */
5940169689Skan  icode = sync_compare_and_swap_cc[mode];
5941169689Skan  switch (icode)
5942169689Skan    {
5943169689Skan    default:
5944169689Skan      subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
5945169689Skan						 cmp_reg, icode);
5946169689Skan      if (subtarget != NULL_RTX)
5947169689Skan	{
5948169689Skan	  gcc_assert (subtarget == cmp_reg);
5949169689Skan	  break;
5950169689Skan	}
5951169689Skan
5952169689Skan      /* FALLTHRU */
5953169689Skan    case CODE_FOR_nothing:
5954169689Skan      icode = sync_compare_and_swap[mode];
5955169689Skan      if (icode == CODE_FOR_nothing)
5956169689Skan	return false;
5957169689Skan
5958169689Skan      subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
5959169689Skan						 cmp_reg, icode);
5960169689Skan      if (subtarget == NULL_RTX)
5961169689Skan	return false;
5962169689Skan      if (subtarget != cmp_reg)
5963169689Skan	emit_move_insn (cmp_reg, subtarget);
5964169689Skan
5965169689Skan      emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true);
5966169689Skan    }
5967169689Skan
5968169689Skan  /* ??? Mark this jump predicted not taken?  */
5969169689Skan  emit_jump_insn (bcc_gen_fctn[NE] (label));
5970169689Skan
5971169689Skan  return true;
5972169689Skan}
5973169689Skan
5974169689Skan/* This function generates the atomic operation MEM CODE= VAL.  In this
5975169689Skan   case, we do not care about any resulting value.  Returns NULL if we
5976169689Skan   cannot generate the operation.  */
5977169689Skan
5978169689Skanrtx
5979169689Skanexpand_sync_operation (rtx mem, rtx val, enum rtx_code code)
5980169689Skan{
5981169689Skan  enum machine_mode mode = GET_MODE (mem);
5982169689Skan  enum insn_code icode;
5983169689Skan  rtx insn;
5984169689Skan
5985169689Skan  /* Look to see if the target supports the operation directly.  */
5986169689Skan  switch (code)
5987169689Skan    {
5988169689Skan    case PLUS:
5989169689Skan      icode = sync_add_optab[mode];
5990169689Skan      break;
5991169689Skan    case IOR:
5992169689Skan      icode = sync_ior_optab[mode];
5993169689Skan      break;
5994169689Skan    case XOR:
5995169689Skan      icode = sync_xor_optab[mode];
5996169689Skan      break;
5997169689Skan    case AND:
5998169689Skan      icode = sync_and_optab[mode];
5999169689Skan      break;
6000169689Skan    case NOT:
6001169689Skan      icode = sync_nand_optab[mode];
6002169689Skan      break;
6003169689Skan
6004169689Skan    case MINUS:
6005169689Skan      icode = sync_sub_optab[mode];
6006169689Skan      if (icode == CODE_FOR_nothing)
6007169689Skan	{
6008169689Skan	  icode = sync_add_optab[mode];
6009169689Skan	  if (icode != CODE_FOR_nothing)
6010169689Skan	    {
6011169689Skan	      val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1);
6012169689Skan	      code = PLUS;
6013169689Skan	    }
6014169689Skan	}
6015169689Skan      break;
6016169689Skan
6017169689Skan    default:
6018169689Skan      gcc_unreachable ();
6019169689Skan    }
6020169689Skan
6021169689Skan  /* Generate the direct operation, if present.  */
6022169689Skan  if (icode != CODE_FOR_nothing)
6023169689Skan    {
6024169689Skan      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
6025169689Skan	val = convert_modes (mode, GET_MODE (val), val, 1);
6026169689Skan      if (!insn_data[icode].operand[1].predicate (val, mode))
6027169689Skan	val = force_reg (mode, val);
6028169689Skan
6029169689Skan      insn = GEN_FCN (icode) (mem, val);
6030169689Skan      if (insn)
6031169689Skan	{
6032169689Skan	  emit_insn (insn);
6033169689Skan	  return const0_rtx;
6034169689Skan	}
6035169689Skan    }
6036169689Skan
6037169689Skan  /* Failing that, generate a compare-and-swap loop in which we perform the
6038169689Skan     operation with normal arithmetic instructions.  */
6039169689Skan  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
6040169689Skan    {
6041169689Skan      rtx t0 = gen_reg_rtx (mode), t1;
6042169689Skan
6043169689Skan      start_sequence ();
6044169689Skan
6045169689Skan      t1 = t0;
6046169689Skan      if (code == NOT)
6047169689Skan	{
6048169689Skan	  t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true);
6049169689Skan	  code = AND;
6050169689Skan	}
6051169689Skan      t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX,
6052169689Skan				true, OPTAB_LIB_WIDEN);
6053169689Skan
6054169689Skan      insn = get_insns ();
6055169689Skan      end_sequence ();
6056169689Skan
6057169689Skan      if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn))
6058169689Skan	return const0_rtx;
6059169689Skan    }
6060169689Skan
6061169689Skan  return NULL_RTX;
6062169689Skan}
6063169689Skan
6064169689Skan/* This function generates the atomic operation MEM CODE= VAL.  In this
6065169689Skan   case, we do care about the resulting value: if AFTER is true then
6066169689Skan   return the value MEM holds after the operation, if AFTER is false
6067169689Skan   then return the value MEM holds before the operation.  TARGET is an
6068169689Skan   optional place for the result value to be stored.  */
6069169689Skan
6070169689Skanrtx
6071169689Skanexpand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code,
6072169689Skan			     bool after, rtx target)
6073169689Skan{
6074169689Skan  enum machine_mode mode = GET_MODE (mem);
6075169689Skan  enum insn_code old_code, new_code, icode;
6076169689Skan  bool compensate;
6077169689Skan  rtx insn;
6078169689Skan
6079169689Skan  /* Look to see if the target supports the operation directly.  */
6080169689Skan  switch (code)
6081169689Skan    {
6082169689Skan    case PLUS:
6083169689Skan      old_code = sync_old_add_optab[mode];
6084169689Skan      new_code = sync_new_add_optab[mode];
6085169689Skan      break;
6086169689Skan    case IOR:
6087169689Skan      old_code = sync_old_ior_optab[mode];
6088169689Skan      new_code = sync_new_ior_optab[mode];
6089169689Skan      break;
6090169689Skan    case XOR:
6091169689Skan      old_code = sync_old_xor_optab[mode];
6092169689Skan      new_code = sync_new_xor_optab[mode];
6093169689Skan      break;
6094169689Skan    case AND:
6095169689Skan      old_code = sync_old_and_optab[mode];
6096169689Skan      new_code = sync_new_and_optab[mode];
6097169689Skan      break;
6098169689Skan    case NOT:
6099169689Skan      old_code = sync_old_nand_optab[mode];
6100169689Skan      new_code = sync_new_nand_optab[mode];
6101169689Skan      break;
6102169689Skan
6103169689Skan    case MINUS:
6104169689Skan      old_code = sync_old_sub_optab[mode];
6105169689Skan      new_code = sync_new_sub_optab[mode];
6106169689Skan      if (old_code == CODE_FOR_nothing && new_code == CODE_FOR_nothing)
6107169689Skan	{
6108169689Skan	  old_code = sync_old_add_optab[mode];
6109169689Skan	  new_code = sync_new_add_optab[mode];
6110169689Skan	  if (old_code != CODE_FOR_nothing || new_code != CODE_FOR_nothing)
6111169689Skan	    {
6112169689Skan	      val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1);
6113169689Skan	      code = PLUS;
6114169689Skan	    }
6115169689Skan	}
6116169689Skan      break;
6117169689Skan
6118169689Skan    default:
6119169689Skan      gcc_unreachable ();
6120169689Skan    }
6121169689Skan
6122169689Skan  /* If the target does supports the proper new/old operation, great.  But
6123169689Skan     if we only support the opposite old/new operation, check to see if we
6124169689Skan     can compensate.  In the case in which the old value is supported, then
6125169689Skan     we can always perform the operation again with normal arithmetic.  In
6126169689Skan     the case in which the new value is supported, then we can only handle
6127169689Skan     this in the case the operation is reversible.  */
6128169689Skan  compensate = false;
6129169689Skan  if (after)
6130169689Skan    {
6131169689Skan      icode = new_code;
6132169689Skan      if (icode == CODE_FOR_nothing)
6133169689Skan	{
6134169689Skan	  icode = old_code;
6135169689Skan	  if (icode != CODE_FOR_nothing)
6136169689Skan	    compensate = true;
6137169689Skan	}
6138169689Skan    }
6139169689Skan  else
6140169689Skan    {
6141169689Skan      icode = old_code;
6142169689Skan      if (icode == CODE_FOR_nothing
6143169689Skan	  && (code == PLUS || code == MINUS || code == XOR))
6144169689Skan	{
6145169689Skan	  icode = new_code;
6146169689Skan	  if (icode != CODE_FOR_nothing)
6147169689Skan	    compensate = true;
6148169689Skan	}
6149169689Skan    }
6150169689Skan
6151169689Skan  /* If we found something supported, great.  */
6152169689Skan  if (icode != CODE_FOR_nothing)
6153169689Skan    {
6154169689Skan      if (!target || !insn_data[icode].operand[0].predicate (target, mode))
6155169689Skan	target = gen_reg_rtx (mode);
6156169689Skan
6157169689Skan      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
6158169689Skan	val = convert_modes (mode, GET_MODE (val), val, 1);
6159169689Skan      if (!insn_data[icode].operand[2].predicate (val, mode))
6160169689Skan	val = force_reg (mode, val);
6161169689Skan
6162169689Skan      insn = GEN_FCN (icode) (target, mem, val);
6163169689Skan      if (insn)
6164169689Skan	{
6165169689Skan	  emit_insn (insn);
6166169689Skan
6167169689Skan	  /* If we need to compensate for using an operation with the
6168169689Skan	     wrong return value, do so now.  */
6169169689Skan	  if (compensate)
6170169689Skan	    {
6171169689Skan	      if (!after)
6172169689Skan		{
6173169689Skan		  if (code == PLUS)
6174169689Skan		    code = MINUS;
6175169689Skan		  else if (code == MINUS)
6176169689Skan		    code = PLUS;
6177169689Skan		}
6178169689Skan
6179169689Skan	      if (code == NOT)
6180169689Skan		target = expand_simple_unop (mode, NOT, target, NULL_RTX, true);
6181169689Skan	      target = expand_simple_binop (mode, code, target, val, NULL_RTX,
6182169689Skan					    true, OPTAB_LIB_WIDEN);
6183169689Skan	    }
6184169689Skan
6185169689Skan	  return target;
6186169689Skan	}
6187169689Skan    }
6188169689Skan
6189169689Skan  /* Failing that, generate a compare-and-swap loop in which we perform the
6190169689Skan     operation with normal arithmetic instructions.  */
6191169689Skan  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
6192169689Skan    {
6193169689Skan      rtx t0 = gen_reg_rtx (mode), t1;
6194169689Skan
6195169689Skan      if (!target || !register_operand (target, mode))
6196169689Skan	target = gen_reg_rtx (mode);
6197169689Skan
6198169689Skan      start_sequence ();
6199169689Skan
6200169689Skan      if (!after)
6201169689Skan	emit_move_insn (target, t0);
6202169689Skan      t1 = t0;
6203169689Skan      if (code == NOT)
6204169689Skan	{
6205169689Skan	  t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true);
6206169689Skan	  code = AND;
6207169689Skan	}
6208169689Skan      t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX,
6209169689Skan				true, OPTAB_LIB_WIDEN);
6210169689Skan      if (after)
6211169689Skan	emit_move_insn (target, t1);
6212169689Skan
6213169689Skan      insn = get_insns ();
6214169689Skan      end_sequence ();
6215169689Skan
6216169689Skan      if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn))
6217169689Skan	return target;
6218169689Skan    }
6219169689Skan
6220169689Skan  return NULL_RTX;
6221169689Skan}
6222169689Skan
6223169689Skan/* This function expands a test-and-set operation.  Ideally we atomically
6224169689Skan   store VAL in MEM and return the previous value in MEM.  Some targets
6225169689Skan   may not support this operation and only support VAL with the constant 1;
6226169689Skan   in this case while the return value will be 0/1, but the exact value
6227169689Skan   stored in MEM is target defined.  TARGET is an option place to stick
6228169689Skan   the return value.  */
6229169689Skan
6230169689Skanrtx
6231169689Skanexpand_sync_lock_test_and_set (rtx mem, rtx val, rtx target)
6232169689Skan{
6233169689Skan  enum machine_mode mode = GET_MODE (mem);
6234169689Skan  enum insn_code icode;
6235169689Skan  rtx insn;
6236169689Skan
6237169689Skan  /* If the target supports the test-and-set directly, great.  */
6238169689Skan  icode = sync_lock_test_and_set[mode];
6239169689Skan  if (icode != CODE_FOR_nothing)
6240169689Skan    {
6241169689Skan      if (!target || !insn_data[icode].operand[0].predicate (target, mode))
6242169689Skan	target = gen_reg_rtx (mode);
6243169689Skan
6244169689Skan      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
6245169689Skan	val = convert_modes (mode, GET_MODE (val), val, 1);
6246169689Skan      if (!insn_data[icode].operand[2].predicate (val, mode))
6247169689Skan	val = force_reg (mode, val);
6248169689Skan
6249169689Skan      insn = GEN_FCN (icode) (target, mem, val);
6250169689Skan      if (insn)
6251169689Skan	{
6252169689Skan	  emit_insn (insn);
6253169689Skan	  return target;
6254169689Skan	}
6255169689Skan    }
6256169689Skan
6257169689Skan  /* Otherwise, use a compare-and-swap loop for the exchange.  */
6258169689Skan  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
6259169689Skan    {
6260169689Skan      if (!target || !register_operand (target, mode))
6261169689Skan	target = gen_reg_rtx (mode);
6262169689Skan      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
6263169689Skan	val = convert_modes (mode, GET_MODE (val), val, 1);
6264169689Skan      if (expand_compare_and_swap_loop (mem, target, val, NULL_RTX))
6265169689Skan	return target;
6266169689Skan    }
6267169689Skan
6268169689Skan  return NULL_RTX;
6269169689Skan}
6270169689Skan
6271117395Skan#include "gt-optabs.h"
6272