190075Sobrien/* RTL simplification functions for GNU compiler.
290075Sobrien   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3169689Skan   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
4169689Skan   Free Software Foundation, Inc.
590075Sobrien
690075SobrienThis file is part of GCC.
790075Sobrien
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.
1290075Sobrien
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.
1790075Sobrien
1890075SobrienYou 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.  */
2290075Sobrien
2390075Sobrien
2490075Sobrien#include "config.h"
2590075Sobrien#include "system.h"
26132718Skan#include "coretypes.h"
27132718Skan#include "tm.h"
2890075Sobrien#include "rtl.h"
29117395Skan#include "tree.h"
3090075Sobrien#include "tm_p.h"
3190075Sobrien#include "regs.h"
3290075Sobrien#include "hard-reg-set.h"
3390075Sobrien#include "flags.h"
3490075Sobrien#include "real.h"
3590075Sobrien#include "insn-config.h"
3690075Sobrien#include "recog.h"
3790075Sobrien#include "function.h"
3890075Sobrien#include "expr.h"
3990075Sobrien#include "toplev.h"
4090075Sobrien#include "output.h"
4190075Sobrien#include "ggc.h"
42132718Skan#include "target.h"
4390075Sobrien
4490075Sobrien/* Simplification and canonicalization of RTL.  */
4590075Sobrien
4690075Sobrien/* Much code operates on (low, high) pairs; the low value is an
4790075Sobrien   unsigned wide int, the high value a signed wide int.  We
4890075Sobrien   occasionally need to sign extend from low to high as if low were a
4990075Sobrien   signed wide int.  */
5090075Sobrien#define HWI_SIGN_EXTEND(low) \
5190075Sobrien ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
5290075Sobrien
53132718Skanstatic rtx neg_const_int (enum machine_mode, rtx);
54169689Skanstatic bool plus_minus_operand_p (rtx);
55132718Skanstatic int simplify_plus_minus_op_data_cmp (const void *, const void *);
56169689Skanstatic rtx simplify_plus_minus (enum rtx_code, enum machine_mode, rtx, rtx);
57132718Skanstatic rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode,
58132718Skan				  unsigned int);
59132718Skanstatic rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
60132718Skan					   rtx, rtx);
61169689Skanstatic rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
62169689Skan					    enum machine_mode, rtx, rtx);
63169689Skanstatic rtx simplify_unary_operation_1 (enum rtx_code, enum machine_mode, rtx);
64169689Skanstatic rtx simplify_binary_operation_1 (enum rtx_code, enum machine_mode,
65169689Skan					rtx, rtx, rtx, rtx);
6690075Sobrien
6790075Sobrien/* Negate a CONST_INT rtx, truncating (because a conversion from a
6890075Sobrien   maximally negative number can overflow).  */
6990075Sobrienstatic rtx
70132718Skanneg_const_int (enum machine_mode mode, rtx i)
7190075Sobrien{
72117395Skan  return gen_int_mode (- INTVAL (i), mode);
7390075Sobrien}
7490075Sobrien
75169689Skan/* Test whether expression, X, is an immediate constant that represents
76169689Skan   the most significant bit of machine mode MODE.  */
77169689Skan
78169689Skanbool
79169689Skanmode_signbit_p (enum machine_mode mode, rtx x)
80169689Skan{
81169689Skan  unsigned HOST_WIDE_INT val;
82169689Skan  unsigned int width;
83169689Skan
84169689Skan  if (GET_MODE_CLASS (mode) != MODE_INT)
85169689Skan    return false;
86169689Skan
87169689Skan  width = GET_MODE_BITSIZE (mode);
88169689Skan  if (width == 0)
89169689Skan    return false;
90169689Skan
91169689Skan  if (width <= HOST_BITS_PER_WIDE_INT
92169689Skan      && GET_CODE (x) == CONST_INT)
93169689Skan    val = INTVAL (x);
94169689Skan  else if (width <= 2 * HOST_BITS_PER_WIDE_INT
95169689Skan	   && GET_CODE (x) == CONST_DOUBLE
96169689Skan	   && CONST_DOUBLE_LOW (x) == 0)
97169689Skan    {
98169689Skan      val = CONST_DOUBLE_HIGH (x);
99169689Skan      width -= HOST_BITS_PER_WIDE_INT;
100169689Skan    }
101169689Skan  else
102169689Skan    return false;
103169689Skan
104169689Skan  if (width < HOST_BITS_PER_WIDE_INT)
105169689Skan    val &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
106169689Skan  return val == ((unsigned HOST_WIDE_INT) 1 << (width - 1));
107169689Skan}
10890075Sobrien
109117395Skan/* Make a binary operation by properly ordering the operands and
11090075Sobrien   seeing if the expression folds.  */
11190075Sobrien
11290075Sobrienrtx
113132718Skansimplify_gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0,
114132718Skan		     rtx op1)
11590075Sobrien{
11690075Sobrien  rtx tem;
11790075Sobrien
11890075Sobrien  /* If this simplifies, do it.  */
11990075Sobrien  tem = simplify_binary_operation (code, mode, op0, op1);
12090075Sobrien  if (tem)
12190075Sobrien    return tem;
12290075Sobrien
123169689Skan  /* Put complex operands first and constants second if commutative.  */
124169689Skan  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
125169689Skan      && swap_commutative_operands_p (op0, op1))
126169689Skan    tem = op0, op0 = op1, op1 = tem;
12790075Sobrien
12896263Sobrien  return gen_rtx_fmt_ee (code, mode, op0, op1);
12990075Sobrien}
13090075Sobrien
13190075Sobrien/* If X is a MEM referencing the constant pool, return the real value.
13290075Sobrien   Otherwise return X.  */
13390075Sobrienrtx
134132718Skanavoid_constant_pool_reference (rtx x)
13590075Sobrien{
136132718Skan  rtx c, tmp, addr;
13790075Sobrien  enum machine_mode cmode;
138169689Skan  HOST_WIDE_INT offset = 0;
13990075Sobrien
140132718Skan  switch (GET_CODE (x))
141132718Skan    {
142132718Skan    case MEM:
143132718Skan      break;
144132718Skan
145132718Skan    case FLOAT_EXTEND:
146132718Skan      /* Handle float extensions of constant pool references.  */
147132718Skan      tmp = XEXP (x, 0);
148132718Skan      c = avoid_constant_pool_reference (tmp);
149132718Skan      if (c != tmp && GET_CODE (c) == CONST_DOUBLE)
150132718Skan	{
151132718Skan	  REAL_VALUE_TYPE d;
152132718Skan
153132718Skan	  REAL_VALUE_FROM_CONST_DOUBLE (d, c);
154132718Skan	  return CONST_DOUBLE_FROM_REAL_VALUE (d, GET_MODE (x));
155132718Skan	}
156132718Skan      return x;
157132718Skan
158132718Skan    default:
159132718Skan      return x;
160132718Skan    }
161132718Skan
16290075Sobrien  addr = XEXP (x, 0);
16390075Sobrien
164132718Skan  /* Call target hook to avoid the effects of -fpic etc....  */
165169689Skan  addr = targetm.delegitimize_address (addr);
166132718Skan
167169689Skan  /* Split the address into a base and integer offset.  */
168169689Skan  if (GET_CODE (addr) == CONST
169169689Skan      && GET_CODE (XEXP (addr, 0)) == PLUS
170169689Skan      && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
171169689Skan    {
172169689Skan      offset = INTVAL (XEXP (XEXP (addr, 0), 1));
173169689Skan      addr = XEXP (XEXP (addr, 0), 0);
174169689Skan    }
175169689Skan
176117395Skan  if (GET_CODE (addr) == LO_SUM)
177117395Skan    addr = XEXP (addr, 1);
178117395Skan
179169689Skan  /* If this is a constant pool reference, we can turn it into its
180169689Skan     constant and hope that simplifications happen.  */
181169689Skan  if (GET_CODE (addr) == SYMBOL_REF
182169689Skan      && CONSTANT_POOL_ADDRESS_P (addr))
183169689Skan    {
184169689Skan      c = get_pool_constant (addr);
185169689Skan      cmode = get_pool_mode (addr);
18690075Sobrien
187169689Skan      /* If we're accessing the constant in a different mode than it was
188169689Skan         originally stored, attempt to fix that up via subreg simplifications.
189169689Skan         If that fails we have no choice but to return the original memory.  */
190169689Skan      if (offset != 0 || cmode != GET_MODE (x))
191169689Skan        {
192169689Skan          rtx tem = simplify_subreg (GET_MODE (x), c, cmode, offset);
193169689Skan          if (tem && CONSTANT_P (tem))
194169689Skan            return tem;
195169689Skan        }
196169689Skan      else
197169689Skan        return c;
19890075Sobrien    }
19990075Sobrien
200169689Skan  return x;
20190075Sobrien}
202169689Skan
203169689Skan/* Return true if X is a MEM referencing the constant pool.  */
204169689Skan
205169689Skanbool
206169689Skanconstant_pool_reference_p (rtx x)
207169689Skan{
208169689Skan  return avoid_constant_pool_reference (x) != x;
209169689Skan}
21090075Sobrien
21190075Sobrien/* Make a unary operation by first seeing if it folds and otherwise making
21290075Sobrien   the specified operation.  */
21390075Sobrien
21490075Sobrienrtx
215132718Skansimplify_gen_unary (enum rtx_code code, enum machine_mode mode, rtx op,
216132718Skan		    enum machine_mode op_mode)
21790075Sobrien{
21890075Sobrien  rtx tem;
21990075Sobrien
22090075Sobrien  /* If this simplifies, use it.  */
22190075Sobrien  if ((tem = simplify_unary_operation (code, mode, op, op_mode)) != 0)
22290075Sobrien    return tem;
22390075Sobrien
22490075Sobrien  return gen_rtx_fmt_e (code, mode, op);
22590075Sobrien}
22690075Sobrien
22790075Sobrien/* Likewise for ternary operations.  */
22890075Sobrien
22990075Sobrienrtx
230132718Skansimplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
231132718Skan		      enum machine_mode op0_mode, rtx op0, rtx op1, rtx op2)
23290075Sobrien{
23390075Sobrien  rtx tem;
23490075Sobrien
23590075Sobrien  /* If this simplifies, use it.  */
23690075Sobrien  if (0 != (tem = simplify_ternary_operation (code, mode, op0_mode,
23790075Sobrien					      op0, op1, op2)))
23890075Sobrien    return tem;
23990075Sobrien
24090075Sobrien  return gen_rtx_fmt_eee (code, mode, op0, op1, op2);
24190075Sobrien}
242161651Skan
24390075Sobrien/* Likewise, for relational operations.
244169689Skan   CMP_MODE specifies mode comparison is done in.  */
24590075Sobrien
24690075Sobrienrtx
247132718Skansimplify_gen_relational (enum rtx_code code, enum machine_mode mode,
248132718Skan			 enum machine_mode cmp_mode, rtx op0, rtx op1)
24990075Sobrien{
25090075Sobrien  rtx tem;
25190075Sobrien
252169689Skan  if (0 != (tem = simplify_relational_operation (code, mode, cmp_mode,
253169689Skan						 op0, op1)))
254169689Skan    return tem;
25590075Sobrien
25690075Sobrien  return gen_rtx_fmt_ee (code, mode, op0, op1);
25790075Sobrien}
25890075Sobrien
259169689Skan/* Replace all occurrences of OLD_RTX in X with NEW_RTX and try to simplify the
26090075Sobrien   resulting RTX.  Return a new RTX which is as simplified as possible.  */
26190075Sobrien
26290075Sobrienrtx
263169689Skansimplify_replace_rtx (rtx x, rtx old_rtx, rtx new_rtx)
26490075Sobrien{
26590075Sobrien  enum rtx_code code = GET_CODE (x);
26690075Sobrien  enum machine_mode mode = GET_MODE (x);
267132718Skan  enum machine_mode op_mode;
268132718Skan  rtx op0, op1, op2;
26990075Sobrien
270169689Skan  /* If X is OLD_RTX, return NEW_RTX.  Otherwise, if this is an expression, try
27190075Sobrien     to build a new expression substituting recursively.  If we can't do
27290075Sobrien     anything, return our input.  */
27390075Sobrien
274169689Skan  if (x == old_rtx)
275169689Skan    return new_rtx;
27690075Sobrien
27790075Sobrien  switch (GET_RTX_CLASS (code))
27890075Sobrien    {
279169689Skan    case RTX_UNARY:
280132718Skan      op0 = XEXP (x, 0);
281132718Skan      op_mode = GET_MODE (op0);
282169689Skan      op0 = simplify_replace_rtx (op0, old_rtx, new_rtx);
283132718Skan      if (op0 == XEXP (x, 0))
284132718Skan	return x;
285132718Skan      return simplify_gen_unary (code, mode, op0, op_mode);
28690075Sobrien
287169689Skan    case RTX_BIN_ARITH:
288169689Skan    case RTX_COMM_ARITH:
289169689Skan      op0 = simplify_replace_rtx (XEXP (x, 0), old_rtx, new_rtx);
290169689Skan      op1 = simplify_replace_rtx (XEXP (x, 1), old_rtx, new_rtx);
291132718Skan      if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
292132718Skan	return x;
293132718Skan      return simplify_gen_binary (code, mode, op0, op1);
294132718Skan
295169689Skan    case RTX_COMPARE:
296169689Skan    case RTX_COMM_COMPARE:
297132718Skan      op0 = XEXP (x, 0);
298132718Skan      op1 = XEXP (x, 1);
299132718Skan      op_mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1);
300169689Skan      op0 = simplify_replace_rtx (op0, old_rtx, new_rtx);
301169689Skan      op1 = simplify_replace_rtx (op1, old_rtx, new_rtx);
302132718Skan      if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
303132718Skan	return x;
304132718Skan      return simplify_gen_relational (code, mode, op_mode, op0, op1);
30590075Sobrien
306169689Skan    case RTX_TERNARY:
307169689Skan    case RTX_BITFIELD_OPS:
308132718Skan      op0 = XEXP (x, 0);
309132718Skan      op_mode = GET_MODE (op0);
310169689Skan      op0 = simplify_replace_rtx (op0, old_rtx, new_rtx);
311169689Skan      op1 = simplify_replace_rtx (XEXP (x, 1), old_rtx, new_rtx);
312169689Skan      op2 = simplify_replace_rtx (XEXP (x, 2), old_rtx, new_rtx);
313132718Skan      if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1) && op2 == XEXP (x, 2))
314132718Skan	return x;
315132718Skan      if (op_mode == VOIDmode)
316132718Skan	op_mode = GET_MODE (op0);
317132718Skan      return simplify_gen_ternary (code, mode, op_mode, op0, op1, op2);
31890075Sobrien
319169689Skan    case RTX_EXTRA:
32090075Sobrien      /* The only case we try to handle is a SUBREG.  */
32190075Sobrien      if (code == SUBREG)
32290075Sobrien	{
323169689Skan	  op0 = simplify_replace_rtx (SUBREG_REG (x), old_rtx, new_rtx);
324132718Skan	  if (op0 == SUBREG_REG (x))
325132718Skan	    return x;
326132718Skan	  op0 = simplify_gen_subreg (GET_MODE (x), op0,
32790075Sobrien				     GET_MODE (SUBREG_REG (x)),
32890075Sobrien				     SUBREG_BYTE (x));
329132718Skan	  return op0 ? op0 : x;
33090075Sobrien	}
331132718Skan      break;
33290075Sobrien
333169689Skan    case RTX_OBJ:
334117395Skan      if (code == MEM)
335132718Skan	{
336169689Skan	  op0 = simplify_replace_rtx (XEXP (x, 0), old_rtx, new_rtx);
337132718Skan	  if (op0 == XEXP (x, 0))
338132718Skan	    return x;
339132718Skan	  return replace_equiv_address_nv (x, op0);
340132718Skan	}
341117395Skan      else if (code == LO_SUM)
342117395Skan	{
343169689Skan	  op0 = simplify_replace_rtx (XEXP (x, 0), old_rtx, new_rtx);
344169689Skan	  op1 = simplify_replace_rtx (XEXP (x, 1), old_rtx, new_rtx);
34590075Sobrien
346117395Skan	  /* (lo_sum (high x) x) -> x  */
347117395Skan	  if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
348117395Skan	    return op1;
34990075Sobrien
350132718Skan	  if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
351132718Skan	    return x;
352117395Skan	  return gen_rtx_LO_SUM (mode, op0, op1);
353117395Skan	}
354117395Skan      else if (code == REG)
35590075Sobrien	{
356169689Skan	  if (rtx_equal_p (x, old_rtx))
357169689Skan	    return new_rtx;
35890075Sobrien	}
359132718Skan      break;
36090075Sobrien
361117395Skan    default:
362132718Skan      break;
36390075Sobrien    }
364117395Skan  return x;
36590075Sobrien}
366117395Skan
36790075Sobrien/* Try to simplify a unary operation CODE whose output mode is to be
36890075Sobrien   MODE with input operand OP whose mode was originally OP_MODE.
36990075Sobrien   Return zero if no simplification can be made.  */
37090075Sobrienrtx
371132718Skansimplify_unary_operation (enum rtx_code code, enum machine_mode mode,
372132718Skan			  rtx op, enum machine_mode op_mode)
37390075Sobrien{
374169689Skan  rtx trueop, tem;
375169689Skan
376169689Skan  if (GET_CODE (op) == CONST)
377169689Skan    op = XEXP (op, 0);
378169689Skan
379169689Skan  trueop = avoid_constant_pool_reference (op);
380169689Skan
381169689Skan  tem = simplify_const_unary_operation (code, mode, trueop, op_mode);
382169689Skan  if (tem)
383169689Skan    return tem;
384169689Skan
385169689Skan  return simplify_unary_operation_1 (code, mode, op);
386169689Skan}
387169689Skan
388169689Skan/* Perform some simplifications we can do even if the operands
389169689Skan   aren't constant.  */
390169689Skanstatic rtx
391169689Skansimplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
392169689Skan{
393169689Skan  enum rtx_code reversed;
394169689Skan  rtx temp;
395169689Skan
396169689Skan  switch (code)
397169689Skan    {
398169689Skan    case NOT:
399169689Skan      /* (not (not X)) == X.  */
400169689Skan      if (GET_CODE (op) == NOT)
401169689Skan	return XEXP (op, 0);
402169689Skan
403169689Skan      /* (not (eq X Y)) == (ne X Y), etc. if BImode or the result of the
404169689Skan	 comparison is all ones.   */
405169689Skan      if (COMPARISON_P (op)
406169689Skan	  && (mode == BImode || STORE_FLAG_VALUE == -1)
407169689Skan	  && ((reversed = reversed_comparison_code (op, NULL_RTX)) != UNKNOWN))
408169689Skan	return simplify_gen_relational (reversed, mode, VOIDmode,
409169689Skan					XEXP (op, 0), XEXP (op, 1));
410169689Skan
411169689Skan      /* (not (plus X -1)) can become (neg X).  */
412169689Skan      if (GET_CODE (op) == PLUS
413169689Skan	  && XEXP (op, 1) == constm1_rtx)
414169689Skan	return simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
415169689Skan
416169689Skan      /* Similarly, (not (neg X)) is (plus X -1).  */
417169689Skan      if (GET_CODE (op) == NEG)
418169689Skan	return plus_constant (XEXP (op, 0), -1);
419169689Skan
420169689Skan      /* (not (xor X C)) for C constant is (xor X D) with D = ~C.  */
421169689Skan      if (GET_CODE (op) == XOR
422169689Skan	  && GET_CODE (XEXP (op, 1)) == CONST_INT
423169689Skan	  && (temp = simplify_unary_operation (NOT, mode,
424169689Skan					       XEXP (op, 1), mode)) != 0)
425169689Skan	return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp);
426169689Skan
427169689Skan      /* (not (plus X C)) for signbit C is (xor X D) with D = ~C.  */
428169689Skan      if (GET_CODE (op) == PLUS
429169689Skan	  && GET_CODE (XEXP (op, 1)) == CONST_INT
430169689Skan	  && mode_signbit_p (mode, XEXP (op, 1))
431169689Skan	  && (temp = simplify_unary_operation (NOT, mode,
432169689Skan					       XEXP (op, 1), mode)) != 0)
433169689Skan	return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp);
434169689Skan
435169689Skan
436169689Skan      /* (not (ashift 1 X)) is (rotate ~1 X).  We used to do this for
437169689Skan	 operands other than 1, but that is not valid.  We could do a
438169689Skan	 similar simplification for (not (lshiftrt C X)) where C is
439169689Skan	 just the sign bit, but this doesn't seem common enough to
440169689Skan	 bother with.  */
441169689Skan      if (GET_CODE (op) == ASHIFT
442169689Skan	  && XEXP (op, 0) == const1_rtx)
443169689Skan	{
444169689Skan	  temp = simplify_gen_unary (NOT, mode, const1_rtx, mode);
445169689Skan	  return simplify_gen_binary (ROTATE, mode, temp, XEXP (op, 1));
446169689Skan	}
447169689Skan
448169689Skan      /* (not (ashiftrt foo C)) where C is the number of bits in FOO
449169689Skan	 minus 1 is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1,
450169689Skan	 so we can perform the above simplification.  */
451169689Skan
452169689Skan      if (STORE_FLAG_VALUE == -1
453169689Skan	  && GET_CODE (op) == ASHIFTRT
454169689Skan	  && GET_CODE (XEXP (op, 1)) == CONST_INT
455169689Skan	  && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
456169689Skan	return simplify_gen_relational (GE, mode, VOIDmode,
457169689Skan					XEXP (op, 0), const0_rtx);
458169689Skan
459169689Skan
460169689Skan      if (GET_CODE (op) == SUBREG
461169689Skan	  && subreg_lowpart_p (op)
462169689Skan	  && (GET_MODE_SIZE (GET_MODE (op))
463169689Skan	      < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
464169689Skan	  && GET_CODE (SUBREG_REG (op)) == ASHIFT
465169689Skan	  && XEXP (SUBREG_REG (op), 0) == const1_rtx)
466169689Skan	{
467169689Skan	  enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op));
468169689Skan	  rtx x;
469169689Skan
470169689Skan	  x = gen_rtx_ROTATE (inner_mode,
471169689Skan			      simplify_gen_unary (NOT, inner_mode, const1_rtx,
472169689Skan						  inner_mode),
473169689Skan			      XEXP (SUBREG_REG (op), 1));
474169689Skan	  return rtl_hooks.gen_lowpart_no_emit (mode, x);
475169689Skan	}
476169689Skan
477169689Skan      /* Apply De Morgan's laws to reduce number of patterns for machines
478169689Skan	 with negating logical insns (and-not, nand, etc.).  If result has
479169689Skan	 only one NOT, put it first, since that is how the patterns are
480169689Skan	 coded.  */
481169689Skan
482169689Skan      if (GET_CODE (op) == IOR || GET_CODE (op) == AND)
483169689Skan	{
484169689Skan	  rtx in1 = XEXP (op, 0), in2 = XEXP (op, 1);
485169689Skan	  enum machine_mode op_mode;
486169689Skan
487169689Skan	  op_mode = GET_MODE (in1);
488169689Skan	  in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
489169689Skan
490169689Skan	  op_mode = GET_MODE (in2);
491169689Skan	  if (op_mode == VOIDmode)
492169689Skan	    op_mode = mode;
493169689Skan	  in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
494169689Skan
495169689Skan	  if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
496169689Skan	    {
497169689Skan	      rtx tem = in2;
498169689Skan	      in2 = in1; in1 = tem;
499169689Skan	    }
500169689Skan
501169689Skan	  return gen_rtx_fmt_ee (GET_CODE (op) == IOR ? AND : IOR,
502169689Skan				 mode, in1, in2);
503169689Skan	}
504169689Skan      break;
505169689Skan
506169689Skan    case NEG:
507169689Skan      /* (neg (neg X)) == X.  */
508169689Skan      if (GET_CODE (op) == NEG)
509169689Skan	return XEXP (op, 0);
510169689Skan
511169689Skan      /* (neg (plus X 1)) can become (not X).  */
512169689Skan      if (GET_CODE (op) == PLUS
513169689Skan	  && XEXP (op, 1) == const1_rtx)
514169689Skan	return simplify_gen_unary (NOT, mode, XEXP (op, 0), mode);
515169689Skan
516169689Skan      /* Similarly, (neg (not X)) is (plus X 1).  */
517169689Skan      if (GET_CODE (op) == NOT)
518169689Skan	return plus_constant (XEXP (op, 0), 1);
519169689Skan
520169689Skan      /* (neg (minus X Y)) can become (minus Y X).  This transformation
521169689Skan	 isn't safe for modes with signed zeros, since if X and Y are
522169689Skan	 both +0, (minus Y X) is the same as (minus X Y).  If the
523169689Skan	 rounding mode is towards +infinity (or -infinity) then the two
524169689Skan	 expressions will be rounded differently.  */
525169689Skan      if (GET_CODE (op) == MINUS
526169689Skan	  && !HONOR_SIGNED_ZEROS (mode)
527169689Skan	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
528169689Skan	return simplify_gen_binary (MINUS, mode, XEXP (op, 1), XEXP (op, 0));
529169689Skan
530169689Skan      if (GET_CODE (op) == PLUS
531169689Skan	  && !HONOR_SIGNED_ZEROS (mode)
532169689Skan	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
533169689Skan	{
534169689Skan	  /* (neg (plus A C)) is simplified to (minus -C A).  */
535169689Skan	  if (GET_CODE (XEXP (op, 1)) == CONST_INT
536169689Skan	      || GET_CODE (XEXP (op, 1)) == CONST_DOUBLE)
537169689Skan	    {
538169689Skan	      temp = simplify_unary_operation (NEG, mode, XEXP (op, 1), mode);
539169689Skan	      if (temp)
540169689Skan		return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 0));
541169689Skan	    }
542169689Skan
543169689Skan	  /* (neg (plus A B)) is canonicalized to (minus (neg A) B).  */
544169689Skan	  temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
545169689Skan	  return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 1));
546169689Skan	}
547169689Skan
548169689Skan      /* (neg (mult A B)) becomes (mult (neg A) B).
549169689Skan	 This works even for floating-point values.  */
550169689Skan      if (GET_CODE (op) == MULT
551169689Skan	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
552169689Skan	{
553169689Skan	  temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
554169689Skan	  return simplify_gen_binary (MULT, mode, temp, XEXP (op, 1));
555169689Skan	}
556169689Skan
557169689Skan      /* NEG commutes with ASHIFT since it is multiplication.  Only do
558169689Skan	 this if we can then eliminate the NEG (e.g., if the operand
559169689Skan	 is a constant).  */
560169689Skan      if (GET_CODE (op) == ASHIFT)
561169689Skan	{
562169689Skan	  temp = simplify_unary_operation (NEG, mode, XEXP (op, 0), mode);
563169689Skan	  if (temp)
564169689Skan	    return simplify_gen_binary (ASHIFT, mode, temp, XEXP (op, 1));
565169689Skan	}
566169689Skan
567169689Skan      /* (neg (ashiftrt X C)) can be replaced by (lshiftrt X C) when
568169689Skan	 C is equal to the width of MODE minus 1.  */
569169689Skan      if (GET_CODE (op) == ASHIFTRT
570169689Skan	  && GET_CODE (XEXP (op, 1)) == CONST_INT
571169689Skan	  && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
572169689Skan	return simplify_gen_binary (LSHIFTRT, mode,
573169689Skan				    XEXP (op, 0), XEXP (op, 1));
574169689Skan
575169689Skan      /* (neg (lshiftrt X C)) can be replaced by (ashiftrt X C) when
576169689Skan	 C is equal to the width of MODE minus 1.  */
577169689Skan      if (GET_CODE (op) == LSHIFTRT
578169689Skan	  && GET_CODE (XEXP (op, 1)) == CONST_INT
579169689Skan	  && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
580169689Skan	return simplify_gen_binary (ASHIFTRT, mode,
581169689Skan				    XEXP (op, 0), XEXP (op, 1));
582169689Skan
583169689Skan      /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1.  */
584169689Skan      if (GET_CODE (op) == XOR
585169689Skan	  && XEXP (op, 1) == const1_rtx
586169689Skan	  && nonzero_bits (XEXP (op, 0), mode) == 1)
587169689Skan	return plus_constant (XEXP (op, 0), -1);
588169689Skan
589169689Skan      /* (neg (lt x 0)) is (ashiftrt X C) if STORE_FLAG_VALUE is 1.  */
590169689Skan      /* (neg (lt x 0)) is (lshiftrt X C) if STORE_FLAG_VALUE is -1.  */
591169689Skan      if (GET_CODE (op) == LT
592220150Smm	  && XEXP (op, 1) == const0_rtx
593220150Smm	  && SCALAR_INT_MODE_P (GET_MODE (XEXP (op, 0))))
594169689Skan	{
595169689Skan	  enum machine_mode inner = GET_MODE (XEXP (op, 0));
596169689Skan	  int isize = GET_MODE_BITSIZE (inner);
597169689Skan	  if (STORE_FLAG_VALUE == 1)
598169689Skan	    {
599169689Skan	      temp = simplify_gen_binary (ASHIFTRT, inner, XEXP (op, 0),
600169689Skan					  GEN_INT (isize - 1));
601169689Skan	      if (mode == inner)
602169689Skan		return temp;
603169689Skan	      if (GET_MODE_BITSIZE (mode) > isize)
604169689Skan		return simplify_gen_unary (SIGN_EXTEND, mode, temp, inner);
605169689Skan	      return simplify_gen_unary (TRUNCATE, mode, temp, inner);
606169689Skan	    }
607169689Skan	  else if (STORE_FLAG_VALUE == -1)
608169689Skan	    {
609169689Skan	      temp = simplify_gen_binary (LSHIFTRT, inner, XEXP (op, 0),
610169689Skan					  GEN_INT (isize - 1));
611169689Skan	      if (mode == inner)
612169689Skan		return temp;
613169689Skan	      if (GET_MODE_BITSIZE (mode) > isize)
614169689Skan		return simplify_gen_unary (ZERO_EXTEND, mode, temp, inner);
615169689Skan	      return simplify_gen_unary (TRUNCATE, mode, temp, inner);
616169689Skan	    }
617169689Skan	}
618169689Skan      break;
619169689Skan
620169689Skan    case TRUNCATE:
621169689Skan      /* We can't handle truncation to a partial integer mode here
622169689Skan         because we don't know the real bitsize of the partial
623169689Skan         integer mode.  */
624169689Skan      if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
625169689Skan        break;
626169689Skan
627169689Skan      /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI.  */
628169689Skan      if ((GET_CODE (op) == SIGN_EXTEND
629169689Skan	   || GET_CODE (op) == ZERO_EXTEND)
630169689Skan	  && GET_MODE (XEXP (op, 0)) == mode)
631169689Skan	return XEXP (op, 0);
632169689Skan
633169689Skan      /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
634169689Skan	 (OP:SI foo:SI) if OP is NEG or ABS.  */
635169689Skan      if ((GET_CODE (op) == ABS
636169689Skan	   || GET_CODE (op) == NEG)
637169689Skan	  && (GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
638169689Skan	      || GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
639169689Skan	  && GET_MODE (XEXP (XEXP (op, 0), 0)) == mode)
640169689Skan	return simplify_gen_unary (GET_CODE (op), mode,
641169689Skan				   XEXP (XEXP (op, 0), 0), mode);
642169689Skan
643169689Skan      /* (truncate:A (subreg:B (truncate:C X) 0)) is
644169689Skan	 (truncate:A X).  */
645169689Skan      if (GET_CODE (op) == SUBREG
646169689Skan	  && GET_CODE (SUBREG_REG (op)) == TRUNCATE
647169689Skan	  && subreg_lowpart_p (op))
648169689Skan	return simplify_gen_unary (TRUNCATE, mode, XEXP (SUBREG_REG (op), 0),
649169689Skan				   GET_MODE (XEXP (SUBREG_REG (op), 0)));
650169689Skan
651169689Skan      /* If we know that the value is already truncated, we can
652169689Skan         replace the TRUNCATE with a SUBREG.  Note that this is also
653169689Skan         valid if TRULY_NOOP_TRUNCATION is false for the corresponding
654169689Skan         modes we just have to apply a different definition for
655169689Skan         truncation.  But don't do this for an (LSHIFTRT (MULT ...))
656169689Skan         since this will cause problems with the umulXi3_highpart
657169689Skan         patterns.  */
658169689Skan      if ((TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
659169689Skan				 GET_MODE_BITSIZE (GET_MODE (op)))
660169689Skan	   ? (num_sign_bit_copies (op, GET_MODE (op))
661169689Skan	      > (unsigned int) (GET_MODE_BITSIZE (GET_MODE (op))
662169689Skan				- GET_MODE_BITSIZE (mode)))
663169689Skan	   : truncated_to_mode (mode, op))
664169689Skan	  && ! (GET_CODE (op) == LSHIFTRT
665169689Skan		&& GET_CODE (XEXP (op, 0)) == MULT))
666169689Skan	return rtl_hooks.gen_lowpart_no_emit (mode, op);
667169689Skan
668169689Skan      /* A truncate of a comparison can be replaced with a subreg if
669169689Skan         STORE_FLAG_VALUE permits.  This is like the previous test,
670169689Skan         but it works even if the comparison is done in a mode larger
671169689Skan         than HOST_BITS_PER_WIDE_INT.  */
672169689Skan      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
673169689Skan	  && COMPARISON_P (op)
674169689Skan	  && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
675169689Skan	return rtl_hooks.gen_lowpart_no_emit (mode, op);
676169689Skan      break;
677169689Skan
678169689Skan    case FLOAT_TRUNCATE:
679169689Skan      if (DECIMAL_FLOAT_MODE_P (mode))
680169689Skan	break;
681169689Skan
682169689Skan      /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF.  */
683169689Skan      if (GET_CODE (op) == FLOAT_EXTEND
684169689Skan	  && GET_MODE (XEXP (op, 0)) == mode)
685169689Skan	return XEXP (op, 0);
686169689Skan
687169689Skan      /* (float_truncate:SF (float_truncate:DF foo:XF))
688169689Skan         = (float_truncate:SF foo:XF).
689169689Skan	 This may eliminate double rounding, so it is unsafe.
690169689Skan
691169689Skan         (float_truncate:SF (float_extend:XF foo:DF))
692169689Skan         = (float_truncate:SF foo:DF).
693169689Skan
694169689Skan         (float_truncate:DF (float_extend:XF foo:SF))
695169689Skan         = (float_extend:SF foo:DF).  */
696169689Skan      if ((GET_CODE (op) == FLOAT_TRUNCATE
697169689Skan	   && flag_unsafe_math_optimizations)
698169689Skan	  || GET_CODE (op) == FLOAT_EXTEND)
699169689Skan	return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (op,
700169689Skan							    0)))
701169689Skan				   > GET_MODE_SIZE (mode)
702169689Skan				   ? FLOAT_TRUNCATE : FLOAT_EXTEND,
703169689Skan				   mode,
704169689Skan				   XEXP (op, 0), mode);
705169689Skan
706169689Skan      /*  (float_truncate (float x)) is (float x)  */
707169689Skan      if (GET_CODE (op) == FLOAT
708169689Skan	  && (flag_unsafe_math_optimizations
709169689Skan	      || ((unsigned)significand_size (GET_MODE (op))
710169689Skan		  >= (GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0)))
711169689Skan		      - num_sign_bit_copies (XEXP (op, 0),
712169689Skan					     GET_MODE (XEXP (op, 0)))))))
713169689Skan	return simplify_gen_unary (FLOAT, mode,
714169689Skan				   XEXP (op, 0),
715169689Skan				   GET_MODE (XEXP (op, 0)));
716169689Skan
717169689Skan      /* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is
718169689Skan	 (OP:SF foo:SF) if OP is NEG or ABS.  */
719169689Skan      if ((GET_CODE (op) == ABS
720169689Skan	   || GET_CODE (op) == NEG)
721169689Skan	  && GET_CODE (XEXP (op, 0)) == FLOAT_EXTEND
722169689Skan	  && GET_MODE (XEXP (XEXP (op, 0), 0)) == mode)
723169689Skan	return simplify_gen_unary (GET_CODE (op), mode,
724169689Skan				   XEXP (XEXP (op, 0), 0), mode);
725169689Skan
726169689Skan      /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0))
727169689Skan	 is (float_truncate:SF x).  */
728169689Skan      if (GET_CODE (op) == SUBREG
729169689Skan	  && subreg_lowpart_p (op)
730169689Skan	  && GET_CODE (SUBREG_REG (op)) == FLOAT_TRUNCATE)
731169689Skan	return SUBREG_REG (op);
732169689Skan      break;
733169689Skan
734169689Skan    case FLOAT_EXTEND:
735169689Skan      if (DECIMAL_FLOAT_MODE_P (mode))
736169689Skan	break;
737169689Skan
738169689Skan      /*  (float_extend (float_extend x)) is (float_extend x)
739169689Skan
740169689Skan	  (float_extend (float x)) is (float x) assuming that double
741169689Skan	  rounding can't happen.
742169689Skan          */
743169689Skan      if (GET_CODE (op) == FLOAT_EXTEND
744169689Skan	  || (GET_CODE (op) == FLOAT
745169689Skan	      && ((unsigned)significand_size (GET_MODE (op))
746169689Skan		  >= (GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0)))
747169689Skan		      - num_sign_bit_copies (XEXP (op, 0),
748169689Skan					     GET_MODE (XEXP (op, 0)))))))
749169689Skan	return simplify_gen_unary (GET_CODE (op), mode,
750169689Skan				   XEXP (op, 0),
751169689Skan				   GET_MODE (XEXP (op, 0)));
752169689Skan
753169689Skan      break;
754169689Skan
755169689Skan    case ABS:
756169689Skan      /* (abs (neg <foo>)) -> (abs <foo>) */
757169689Skan      if (GET_CODE (op) == NEG)
758169689Skan	return simplify_gen_unary (ABS, mode, XEXP (op, 0),
759169689Skan				   GET_MODE (XEXP (op, 0)));
760169689Skan
761169689Skan      /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS),
762169689Skan         do nothing.  */
763169689Skan      if (GET_MODE (op) == VOIDmode)
764169689Skan	break;
765169689Skan
766169689Skan      /* If operand is something known to be positive, ignore the ABS.  */
767169689Skan      if (GET_CODE (op) == FFS || GET_CODE (op) == ABS
768169689Skan	  || ((GET_MODE_BITSIZE (GET_MODE (op))
769169689Skan	       <= HOST_BITS_PER_WIDE_INT)
770169689Skan	      && ((nonzero_bits (op, GET_MODE (op))
771169689Skan		   & ((HOST_WIDE_INT) 1
772169689Skan		      << (GET_MODE_BITSIZE (GET_MODE (op)) - 1)))
773169689Skan		  == 0)))
774169689Skan	return op;
775169689Skan
776169689Skan      /* If operand is known to be only -1 or 0, convert ABS to NEG.  */
777169689Skan      if (num_sign_bit_copies (op, mode) == GET_MODE_BITSIZE (mode))
778169689Skan	return gen_rtx_NEG (mode, op);
779169689Skan
780169689Skan      break;
781169689Skan
782169689Skan    case FFS:
783169689Skan      /* (ffs (*_extend <X>)) = (ffs <X>) */
784169689Skan      if (GET_CODE (op) == SIGN_EXTEND
785169689Skan	  || GET_CODE (op) == ZERO_EXTEND)
786169689Skan	return simplify_gen_unary (FFS, mode, XEXP (op, 0),
787169689Skan				   GET_MODE (XEXP (op, 0)));
788169689Skan      break;
789169689Skan
790169689Skan    case POPCOUNT:
791169689Skan    case PARITY:
792169689Skan      /* (pop* (zero_extend <X>)) = (pop* <X>) */
793169689Skan      if (GET_CODE (op) == ZERO_EXTEND)
794169689Skan	return simplify_gen_unary (code, mode, XEXP (op, 0),
795169689Skan				   GET_MODE (XEXP (op, 0)));
796169689Skan      break;
797169689Skan
798169689Skan    case FLOAT:
799169689Skan      /* (float (sign_extend <X>)) = (float <X>).  */
800169689Skan      if (GET_CODE (op) == SIGN_EXTEND)
801169689Skan	return simplify_gen_unary (FLOAT, mode, XEXP (op, 0),
802169689Skan				   GET_MODE (XEXP (op, 0)));
803169689Skan      break;
804169689Skan
805169689Skan    case SIGN_EXTEND:
806169689Skan      /* (sign_extend (truncate (minus (label_ref L1) (label_ref L2))))
807169689Skan	 becomes just the MINUS if its mode is MODE.  This allows
808169689Skan	 folding switch statements on machines using casesi (such as
809169689Skan	 the VAX).  */
810169689Skan      if (GET_CODE (op) == TRUNCATE
811169689Skan	  && GET_MODE (XEXP (op, 0)) == mode
812169689Skan	  && GET_CODE (XEXP (op, 0)) == MINUS
813169689Skan	  && GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF
814169689Skan	  && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
815169689Skan	return XEXP (op, 0);
816169689Skan
817169689Skan      /* Check for a sign extension of a subreg of a promoted
818169689Skan	 variable, where the promotion is sign-extended, and the
819169689Skan	 target mode is the same as the variable's promotion.  */
820169689Skan      if (GET_CODE (op) == SUBREG
821169689Skan	  && SUBREG_PROMOTED_VAR_P (op)
822169689Skan	  && ! SUBREG_PROMOTED_UNSIGNED_P (op)
823169689Skan	  && GET_MODE (XEXP (op, 0)) == mode)
824169689Skan	return XEXP (op, 0);
825169689Skan
826169689Skan#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
827169689Skan      if (! POINTERS_EXTEND_UNSIGNED
828169689Skan	  && mode == Pmode && GET_MODE (op) == ptr_mode
829169689Skan	  && (CONSTANT_P (op)
830169689Skan	      || (GET_CODE (op) == SUBREG
831169689Skan		  && REG_P (SUBREG_REG (op))
832169689Skan		  && REG_POINTER (SUBREG_REG (op))
833169689Skan		  && GET_MODE (SUBREG_REG (op)) == Pmode)))
834169689Skan	return convert_memory_address (Pmode, op);
835169689Skan#endif
836169689Skan      break;
837169689Skan
838169689Skan    case ZERO_EXTEND:
839169689Skan      /* Check for a zero extension of a subreg of a promoted
840169689Skan	 variable, where the promotion is zero-extended, and the
841169689Skan	 target mode is the same as the variable's promotion.  */
842169689Skan      if (GET_CODE (op) == SUBREG
843169689Skan	  && SUBREG_PROMOTED_VAR_P (op)
844169689Skan	  && SUBREG_PROMOTED_UNSIGNED_P (op) > 0
845169689Skan	  && GET_MODE (XEXP (op, 0)) == mode)
846169689Skan	return XEXP (op, 0);
847169689Skan
848169689Skan#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
849169689Skan      if (POINTERS_EXTEND_UNSIGNED > 0
850169689Skan	  && mode == Pmode && GET_MODE (op) == ptr_mode
851169689Skan	  && (CONSTANT_P (op)
852169689Skan	      || (GET_CODE (op) == SUBREG
853169689Skan		  && REG_P (SUBREG_REG (op))
854169689Skan		  && REG_POINTER (SUBREG_REG (op))
855169689Skan		  && GET_MODE (SUBREG_REG (op)) == Pmode)))
856169689Skan	return convert_memory_address (Pmode, op);
857169689Skan#endif
858169689Skan      break;
859169689Skan
860169689Skan    default:
861169689Skan      break;
862169689Skan    }
863169689Skan
864169689Skan  return 0;
865169689Skan}
866169689Skan
867169689Skan/* Try to compute the value of a unary operation CODE whose output mode is to
868169689Skan   be MODE with input operand OP whose mode was originally OP_MODE.
869169689Skan   Return zero if the value cannot be computed.  */
870169689Skanrtx
871169689Skansimplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
872169689Skan				rtx op, enum machine_mode op_mode)
873169689Skan{
87490075Sobrien  unsigned int width = GET_MODE_BITSIZE (mode);
87590075Sobrien
876117395Skan  if (code == VEC_DUPLICATE)
877117395Skan    {
878169689Skan      gcc_assert (VECTOR_MODE_P (mode));
879169689Skan      if (GET_MODE (op) != VOIDmode)
880169689Skan      {
881169689Skan	if (!VECTOR_MODE_P (GET_MODE (op)))
882169689Skan	  gcc_assert (GET_MODE_INNER (mode) == GET_MODE (op));
883169689Skan	else
884169689Skan	  gcc_assert (GET_MODE_INNER (mode) == GET_MODE_INNER
885169689Skan						(GET_MODE (op)));
886169689Skan      }
887169689Skan      if (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE
888169689Skan	  || GET_CODE (op) == CONST_VECTOR)
889117395Skan	{
890117395Skan          int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
891117395Skan          unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
892117395Skan	  rtvec v = rtvec_alloc (n_elts);
893117395Skan	  unsigned int i;
894117395Skan
895169689Skan	  if (GET_CODE (op) != CONST_VECTOR)
896117395Skan	    for (i = 0; i < n_elts; i++)
897169689Skan	      RTVEC_ELT (v, i) = op;
898117395Skan	  else
899117395Skan	    {
900169689Skan	      enum machine_mode inmode = GET_MODE (op);
901117395Skan              int in_elt_size = GET_MODE_SIZE (GET_MODE_INNER (inmode));
902117395Skan              unsigned in_n_elts = (GET_MODE_SIZE (inmode) / in_elt_size);
903117395Skan
904169689Skan	      gcc_assert (in_n_elts < n_elts);
905169689Skan	      gcc_assert ((n_elts % in_n_elts) == 0);
906117395Skan	      for (i = 0; i < n_elts; i++)
907169689Skan	        RTVEC_ELT (v, i) = CONST_VECTOR_ELT (op, i % in_n_elts);
908117395Skan	    }
909117395Skan	  return gen_rtx_CONST_VECTOR (mode, v);
910117395Skan	}
911117395Skan    }
912117395Skan
913169689Skan  if (VECTOR_MODE_P (mode) && GET_CODE (op) == CONST_VECTOR)
914132718Skan    {
915132718Skan      int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
916132718Skan      unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
917169689Skan      enum machine_mode opmode = GET_MODE (op);
918132718Skan      int op_elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
919132718Skan      unsigned op_n_elts = (GET_MODE_SIZE (opmode) / op_elt_size);
920132718Skan      rtvec v = rtvec_alloc (n_elts);
921132718Skan      unsigned int i;
922132718Skan
923169689Skan      gcc_assert (op_n_elts == n_elts);
924132718Skan      for (i = 0; i < n_elts; i++)
925132718Skan	{
926132718Skan	  rtx x = simplify_unary_operation (code, GET_MODE_INNER (mode),
927169689Skan					    CONST_VECTOR_ELT (op, i),
928132718Skan					    GET_MODE_INNER (opmode));
929132718Skan	  if (!x)
930132718Skan	    return 0;
931132718Skan	  RTVEC_ELT (v, i) = x;
932132718Skan	}
933132718Skan      return gen_rtx_CONST_VECTOR (mode, v);
934132718Skan    }
935132718Skan
93690075Sobrien  /* The order of these tests is critical so that, for example, we don't
93790075Sobrien     check the wrong mode (input vs. output) for a conversion operation,
93890075Sobrien     such as FIX.  At some point, this should be simplified.  */
93990075Sobrien
940169689Skan  if (code == FLOAT && GET_MODE (op) == VOIDmode
941169689Skan      && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
94290075Sobrien    {
94390075Sobrien      HOST_WIDE_INT hv, lv;
94490075Sobrien      REAL_VALUE_TYPE d;
94590075Sobrien
946169689Skan      if (GET_CODE (op) == CONST_INT)
947169689Skan	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
94890075Sobrien      else
949169689Skan	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
95090075Sobrien
95190075Sobrien      REAL_VALUE_FROM_INT (d, lv, hv, mode);
95290075Sobrien      d = real_value_truncate (mode, d);
95390075Sobrien      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
95490075Sobrien    }
955169689Skan  else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode
956169689Skan	   && (GET_CODE (op) == CONST_DOUBLE
957169689Skan	       || GET_CODE (op) == CONST_INT))
95890075Sobrien    {
95990075Sobrien      HOST_WIDE_INT hv, lv;
96090075Sobrien      REAL_VALUE_TYPE d;
96190075Sobrien
962169689Skan      if (GET_CODE (op) == CONST_INT)
963169689Skan	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
96490075Sobrien      else
965169689Skan	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
96690075Sobrien
96790075Sobrien      if (op_mode == VOIDmode)
96890075Sobrien	{
96990075Sobrien	  /* We don't know how to interpret negative-looking numbers in
97090075Sobrien	     this case, so don't try to fold those.  */
97190075Sobrien	  if (hv < 0)
97290075Sobrien	    return 0;
97390075Sobrien	}
97490075Sobrien      else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
97590075Sobrien	;
97690075Sobrien      else
97790075Sobrien	hv = 0, lv &= GET_MODE_MASK (op_mode);
97890075Sobrien
97990075Sobrien      REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
98090075Sobrien      d = real_value_truncate (mode, d);
98190075Sobrien      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
98290075Sobrien    }
98390075Sobrien
984169689Skan  if (GET_CODE (op) == CONST_INT
98590075Sobrien      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
98690075Sobrien    {
987169689Skan      HOST_WIDE_INT arg0 = INTVAL (op);
98890075Sobrien      HOST_WIDE_INT val;
98990075Sobrien
99090075Sobrien      switch (code)
99190075Sobrien	{
99290075Sobrien	case NOT:
99390075Sobrien	  val = ~ arg0;
99490075Sobrien	  break;
99590075Sobrien
99690075Sobrien	case NEG:
99790075Sobrien	  val = - arg0;
99890075Sobrien	  break;
99990075Sobrien
100090075Sobrien	case ABS:
100190075Sobrien	  val = (arg0 >= 0 ? arg0 : - arg0);
100290075Sobrien	  break;
100390075Sobrien
100490075Sobrien	case FFS:
100590075Sobrien	  /* Don't use ffs here.  Instead, get low order bit and then its
100690075Sobrien	     number.  If arg0 is zero, this will return 0, as desired.  */
100790075Sobrien	  arg0 &= GET_MODE_MASK (mode);
100890075Sobrien	  val = exact_log2 (arg0 & (- arg0)) + 1;
100990075Sobrien	  break;
101090075Sobrien
1011132718Skan	case CLZ:
1012132718Skan	  arg0 &= GET_MODE_MASK (mode);
1013132718Skan	  if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
1014132718Skan	    ;
1015132718Skan	  else
1016132718Skan	    val = GET_MODE_BITSIZE (mode) - floor_log2 (arg0) - 1;
1017132718Skan	  break;
1018132718Skan
1019132718Skan	case CTZ:
1020132718Skan	  arg0 &= GET_MODE_MASK (mode);
1021132718Skan	  if (arg0 == 0)
1022132718Skan	    {
1023132718Skan	      /* Even if the value at zero is undefined, we have to come
1024132718Skan		 up with some replacement.  Seems good enough.  */
1025132718Skan	      if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
1026132718Skan		val = GET_MODE_BITSIZE (mode);
1027132718Skan	    }
1028132718Skan	  else
1029132718Skan	    val = exact_log2 (arg0 & -arg0);
1030132718Skan	  break;
1031132718Skan
1032132718Skan	case POPCOUNT:
1033132718Skan	  arg0 &= GET_MODE_MASK (mode);
1034132718Skan	  val = 0;
1035132718Skan	  while (arg0)
1036132718Skan	    val++, arg0 &= arg0 - 1;
1037132718Skan	  break;
1038132718Skan
1039132718Skan	case PARITY:
1040132718Skan	  arg0 &= GET_MODE_MASK (mode);
1041132718Skan	  val = 0;
1042132718Skan	  while (arg0)
1043132718Skan	    val++, arg0 &= arg0 - 1;
1044132718Skan	  val &= 1;
1045132718Skan	  break;
1046132718Skan
1047259563Spfg	case BSWAP:
1048259563Spfg	  return 0;
1049259563Spfg
105090075Sobrien	case TRUNCATE:
105190075Sobrien	  val = arg0;
105290075Sobrien	  break;
105390075Sobrien
105490075Sobrien	case ZERO_EXTEND:
105596263Sobrien	  /* When zero-extending a CONST_INT, we need to know its
105696263Sobrien             original mode.  */
1057169689Skan	  gcc_assert (op_mode != VOIDmode);
105890075Sobrien	  if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
105990075Sobrien	    {
106090075Sobrien	      /* If we were really extending the mode,
106190075Sobrien		 we would have to distinguish between zero-extension
106290075Sobrien		 and sign-extension.  */
1063169689Skan	      gcc_assert (width == GET_MODE_BITSIZE (op_mode));
106490075Sobrien	      val = arg0;
106590075Sobrien	    }
106690075Sobrien	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
106790075Sobrien	    val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
106890075Sobrien	  else
106990075Sobrien	    return 0;
107090075Sobrien	  break;
107190075Sobrien
107290075Sobrien	case SIGN_EXTEND:
107390075Sobrien	  if (op_mode == VOIDmode)
107490075Sobrien	    op_mode = mode;
107590075Sobrien	  if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
107690075Sobrien	    {
107790075Sobrien	      /* If we were really extending the mode,
107890075Sobrien		 we would have to distinguish between zero-extension
107990075Sobrien		 and sign-extension.  */
1080169689Skan	      gcc_assert (width == GET_MODE_BITSIZE (op_mode));
108190075Sobrien	      val = arg0;
108290075Sobrien	    }
108390075Sobrien	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
108490075Sobrien	    {
108590075Sobrien	      val
108690075Sobrien		= arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
108790075Sobrien	      if (val
108890075Sobrien		  & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1)))
108990075Sobrien		val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
109090075Sobrien	    }
109190075Sobrien	  else
109290075Sobrien	    return 0;
109390075Sobrien	  break;
109490075Sobrien
109590075Sobrien	case SQRT:
109690075Sobrien	case FLOAT_EXTEND:
109790075Sobrien	case FLOAT_TRUNCATE:
109890075Sobrien	case SS_TRUNCATE:
109990075Sobrien	case US_TRUNCATE:
1100169689Skan	case SS_NEG:
110190075Sobrien	  return 0;
110290075Sobrien
110390075Sobrien	default:
1104169689Skan	  gcc_unreachable ();
110590075Sobrien	}
110690075Sobrien
1107169689Skan      return gen_int_mode (val, mode);
110890075Sobrien    }
110990075Sobrien
111090075Sobrien  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
111190075Sobrien     for a DImode operation on a CONST_INT.  */
1112169689Skan  else if (GET_MODE (op) == VOIDmode
111396263Sobrien	   && width <= HOST_BITS_PER_WIDE_INT * 2
1114169689Skan	   && (GET_CODE (op) == CONST_DOUBLE
1115169689Skan	       || GET_CODE (op) == CONST_INT))
111690075Sobrien    {
111790075Sobrien      unsigned HOST_WIDE_INT l1, lv;
111890075Sobrien      HOST_WIDE_INT h1, hv;
111990075Sobrien
1120169689Skan      if (GET_CODE (op) == CONST_DOUBLE)
1121169689Skan	l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
112290075Sobrien      else
1123169689Skan	l1 = INTVAL (op), h1 = HWI_SIGN_EXTEND (l1);
112490075Sobrien
112590075Sobrien      switch (code)
112690075Sobrien	{
112790075Sobrien	case NOT:
112890075Sobrien	  lv = ~ l1;
112990075Sobrien	  hv = ~ h1;
113090075Sobrien	  break;
113190075Sobrien
113290075Sobrien	case NEG:
113390075Sobrien	  neg_double (l1, h1, &lv, &hv);
113490075Sobrien	  break;
113590075Sobrien
113690075Sobrien	case ABS:
113790075Sobrien	  if (h1 < 0)
113890075Sobrien	    neg_double (l1, h1, &lv, &hv);
113990075Sobrien	  else
114090075Sobrien	    lv = l1, hv = h1;
114190075Sobrien	  break;
114290075Sobrien
114390075Sobrien	case FFS:
114490075Sobrien	  hv = 0;
114590075Sobrien	  if (l1 == 0)
1146132718Skan	    {
1147132718Skan	      if (h1 == 0)
1148132718Skan		lv = 0;
1149132718Skan	      else
1150132718Skan		lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & -h1) + 1;
1151132718Skan	    }
115290075Sobrien	  else
1153132718Skan	    lv = exact_log2 (l1 & -l1) + 1;
115490075Sobrien	  break;
115590075Sobrien
1156132718Skan	case CLZ:
1157132718Skan	  hv = 0;
1158132718Skan	  if (h1 != 0)
1159132718Skan	    lv = GET_MODE_BITSIZE (mode) - floor_log2 (h1) - 1
1160132718Skan	      - HOST_BITS_PER_WIDE_INT;
1161132718Skan	  else if (l1 != 0)
1162132718Skan	    lv = GET_MODE_BITSIZE (mode) - floor_log2 (l1) - 1;
1163132718Skan	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, lv))
1164132718Skan	    lv = GET_MODE_BITSIZE (mode);
1165132718Skan	  break;
1166132718Skan
1167132718Skan	case CTZ:
1168132718Skan	  hv = 0;
1169132718Skan	  if (l1 != 0)
1170132718Skan	    lv = exact_log2 (l1 & -l1);
1171132718Skan	  else if (h1 != 0)
1172132718Skan	    lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & -h1);
1173132718Skan	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, lv))
1174132718Skan	    lv = GET_MODE_BITSIZE (mode);
1175132718Skan	  break;
1176132718Skan
1177132718Skan	case POPCOUNT:
1178132718Skan	  hv = 0;
1179132718Skan	  lv = 0;
1180132718Skan	  while (l1)
1181132718Skan	    lv++, l1 &= l1 - 1;
1182132718Skan	  while (h1)
1183132718Skan	    lv++, h1 &= h1 - 1;
1184132718Skan	  break;
1185132718Skan
1186132718Skan	case PARITY:
1187132718Skan	  hv = 0;
1188132718Skan	  lv = 0;
1189132718Skan	  while (l1)
1190132718Skan	    lv++, l1 &= l1 - 1;
1191132718Skan	  while (h1)
1192132718Skan	    lv++, h1 &= h1 - 1;
1193132718Skan	  lv &= 1;
1194132718Skan	  break;
1195132718Skan
119690075Sobrien	case TRUNCATE:
119790075Sobrien	  /* This is just a change-of-mode, so do nothing.  */
119890075Sobrien	  lv = l1, hv = h1;
119990075Sobrien	  break;
120090075Sobrien
120190075Sobrien	case ZERO_EXTEND:
1202169689Skan	  gcc_assert (op_mode != VOIDmode);
120396263Sobrien
120496263Sobrien	  if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
120590075Sobrien	    return 0;
120690075Sobrien
120790075Sobrien	  hv = 0;
120890075Sobrien	  lv = l1 & GET_MODE_MASK (op_mode);
120990075Sobrien	  break;
121090075Sobrien
121190075Sobrien	case SIGN_EXTEND:
121290075Sobrien	  if (op_mode == VOIDmode
121390075Sobrien	      || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
121490075Sobrien	    return 0;
121590075Sobrien	  else
121690075Sobrien	    {
121790075Sobrien	      lv = l1 & GET_MODE_MASK (op_mode);
121890075Sobrien	      if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
121990075Sobrien		  && (lv & ((HOST_WIDE_INT) 1
122090075Sobrien			    << (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
122190075Sobrien		lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
122290075Sobrien
122390075Sobrien	      hv = HWI_SIGN_EXTEND (lv);
122490075Sobrien	    }
122590075Sobrien	  break;
122690075Sobrien
122790075Sobrien	case SQRT:
122890075Sobrien	  return 0;
122990075Sobrien
123090075Sobrien	default:
123190075Sobrien	  return 0;
123290075Sobrien	}
123390075Sobrien
123490075Sobrien      return immed_double_const (lv, hv, mode);
123590075Sobrien    }
123690075Sobrien
1237169689Skan  else if (GET_CODE (op) == CONST_DOUBLE
1238169689Skan	   && SCALAR_FLOAT_MODE_P (mode))
123990075Sobrien    {
1240132718Skan      REAL_VALUE_TYPE d, t;
1241169689Skan      REAL_VALUE_FROM_CONST_DOUBLE (d, op);
124290075Sobrien
1243117395Skan      switch (code)
1244117395Skan	{
1245117395Skan	case SQRT:
1246132718Skan	  if (HONOR_SNANS (mode) && real_isnan (&d))
1247132718Skan	    return 0;
1248132718Skan	  real_sqrt (&t, mode, &d);
1249132718Skan	  d = t;
1250132718Skan	  break;
1251117395Skan	case ABS:
1252117395Skan	  d = REAL_VALUE_ABS (d);
1253117395Skan	  break;
1254117395Skan	case NEG:
1255117395Skan	  d = REAL_VALUE_NEGATE (d);
1256117395Skan	  break;
1257117395Skan	case FLOAT_TRUNCATE:
1258117395Skan	  d = real_value_truncate (mode, d);
1259117395Skan	  break;
1260117395Skan	case FLOAT_EXTEND:
1261117395Skan	  /* All this does is change the mode.  */
1262117395Skan	  break;
1263117395Skan	case FIX:
1264117395Skan	  real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
1265117395Skan	  break;
1266146895Skan	case NOT:
1267146895Skan	  {
1268146895Skan	    long tmp[4];
1269146895Skan	    int i;
1270117395Skan
1271169689Skan	    real_to_target (tmp, &d, GET_MODE (op));
1272146895Skan	    for (i = 0; i < 4; i++)
1273146895Skan	      tmp[i] = ~tmp[i];
1274146895Skan	    real_from_target (&d, tmp, mode);
1275146895Skan	    break;
1276146895Skan	  }
1277117395Skan	default:
1278169689Skan	  gcc_unreachable ();
1279117395Skan	}
1280117395Skan      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
128190075Sobrien    }
128290075Sobrien
1283169689Skan  else if (GET_CODE (op) == CONST_DOUBLE
1284169689Skan	   && SCALAR_FLOAT_MODE_P (GET_MODE (op))
128590075Sobrien	   && GET_MODE_CLASS (mode) == MODE_INT
1286132718Skan	   && width <= 2*HOST_BITS_PER_WIDE_INT && width > 0)
128790075Sobrien    {
1288132718Skan      /* Although the overflow semantics of RTL's FIX and UNSIGNED_FIX
1289132718Skan	 operators are intentionally left unspecified (to ease implementation
1290132718Skan	 by target backends), for consistency, this routine implements the
1291132718Skan	 same semantics for constant folding as used by the middle-end.  */
1292132718Skan
1293169689Skan      /* This was formerly used only for non-IEEE float.
1294169689Skan	 eggert@twinsun.com says it is safe for IEEE also.  */
1295132718Skan      HOST_WIDE_INT xh, xl, th, tl;
1296132718Skan      REAL_VALUE_TYPE x, t;
1297169689Skan      REAL_VALUE_FROM_CONST_DOUBLE (x, op);
1298117395Skan      switch (code)
1299117395Skan	{
1300132718Skan	case FIX:
1301132718Skan	  if (REAL_VALUE_ISNAN (x))
1302132718Skan	    return const0_rtx;
1303132718Skan
1304132718Skan	  /* Test against the signed upper bound.  */
1305132718Skan	  if (width > HOST_BITS_PER_WIDE_INT)
1306132718Skan	    {
1307132718Skan	      th = ((unsigned HOST_WIDE_INT) 1
1308132718Skan		    << (width - HOST_BITS_PER_WIDE_INT - 1)) - 1;
1309132718Skan	      tl = -1;
1310132718Skan	    }
1311132718Skan	  else
1312132718Skan	    {
1313132718Skan	      th = 0;
1314132718Skan	      tl = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1;
1315132718Skan	    }
1316132718Skan	  real_from_integer (&t, VOIDmode, tl, th, 0);
1317132718Skan	  if (REAL_VALUES_LESS (t, x))
1318132718Skan	    {
1319132718Skan	      xh = th;
1320132718Skan	      xl = tl;
1321132718Skan	      break;
1322132718Skan	    }
1323132718Skan
1324132718Skan	  /* Test against the signed lower bound.  */
1325132718Skan	  if (width > HOST_BITS_PER_WIDE_INT)
1326132718Skan	    {
1327132718Skan	      th = (HOST_WIDE_INT) -1 << (width - HOST_BITS_PER_WIDE_INT - 1);
1328132718Skan	      tl = 0;
1329132718Skan	    }
1330132718Skan	  else
1331132718Skan	    {
1332132718Skan	      th = -1;
1333132718Skan	      tl = (HOST_WIDE_INT) -1 << (width - 1);
1334132718Skan	    }
1335132718Skan	  real_from_integer (&t, VOIDmode, tl, th, 0);
1336132718Skan	  if (REAL_VALUES_LESS (x, t))
1337132718Skan	    {
1338132718Skan	      xh = th;
1339132718Skan	      xl = tl;
1340132718Skan	      break;
1341132718Skan	    }
1342132718Skan	  REAL_VALUE_TO_INT (&xl, &xh, x);
1343132718Skan	  break;
1344132718Skan
1345132718Skan	case UNSIGNED_FIX:
1346132718Skan	  if (REAL_VALUE_ISNAN (x) || REAL_VALUE_NEGATIVE (x))
1347132718Skan	    return const0_rtx;
1348132718Skan
1349132718Skan	  /* Test against the unsigned upper bound.  */
1350132718Skan	  if (width == 2*HOST_BITS_PER_WIDE_INT)
1351132718Skan	    {
1352132718Skan	      th = -1;
1353132718Skan	      tl = -1;
1354132718Skan	    }
1355132718Skan	  else if (width >= HOST_BITS_PER_WIDE_INT)
1356132718Skan	    {
1357132718Skan	      th = ((unsigned HOST_WIDE_INT) 1
1358132718Skan		    << (width - HOST_BITS_PER_WIDE_INT)) - 1;
1359132718Skan	      tl = -1;
1360132718Skan	    }
1361132718Skan	  else
1362132718Skan	    {
1363132718Skan	      th = 0;
1364132718Skan	      tl = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
1365132718Skan	    }
1366132718Skan	  real_from_integer (&t, VOIDmode, tl, th, 1);
1367132718Skan	  if (REAL_VALUES_LESS (t, x))
1368132718Skan	    {
1369132718Skan	      xh = th;
1370132718Skan	      xl = tl;
1371132718Skan	      break;
1372132718Skan	    }
1373132718Skan
1374132718Skan	  REAL_VALUE_TO_INT (&xl, &xh, x);
1375132718Skan	  break;
1376132718Skan
1377117395Skan	default:
1378169689Skan	  gcc_unreachable ();
1379117395Skan	}
1380132718Skan      return immed_double_const (xl, xh, mode);
1381117395Skan    }
138290075Sobrien
1383169689Skan  return NULL_RTX;
1384169689Skan}
1385169689Skan
1386169689Skan/* Subroutine of simplify_binary_operation to simplify a commutative,
1387169689Skan   associative binary operation CODE with result mode MODE, operating
1388169689Skan   on OP0 and OP1.  CODE is currently one of PLUS, MULT, AND, IOR, XOR,
1389169689Skan   SMIN, SMAX, UMIN or UMAX.  Return zero if no simplification or
1390169689Skan   canonicalization is possible.  */
1391169689Skan
1392169689Skanstatic rtx
1393169689Skansimplify_associative_operation (enum rtx_code code, enum machine_mode mode,
1394169689Skan				rtx op0, rtx op1)
1395169689Skan{
1396169689Skan  rtx tem;
1397169689Skan
1398169689Skan  /* Linearize the operator to the left.  */
1399169689Skan  if (GET_CODE (op1) == code)
140090075Sobrien    {
1401169689Skan      /* "(a op b) op (c op d)" becomes "((a op b) op c) op d)".  */
1402169689Skan      if (GET_CODE (op0) == code)
1403169689Skan	{
1404169689Skan	  tem = simplify_gen_binary (code, mode, op0, XEXP (op1, 0));
1405169689Skan	  return simplify_gen_binary (code, mode, tem, XEXP (op1, 1));
1406169689Skan	}
1407132718Skan
1408169689Skan      /* "a op (b op c)" becomes "(b op c) op a".  */
1409169689Skan      if (! swap_commutative_operands_p (op1, op0))
1410169689Skan	return simplify_gen_binary (code, mode, op1, op0);
1411169689Skan
1412169689Skan      tem = op0;
1413169689Skan      op0 = op1;
1414169689Skan      op1 = tem;
1415169689Skan    }
1416169689Skan
1417169689Skan  if (GET_CODE (op0) == code)
1418169689Skan    {
1419169689Skan      /* Canonicalize "(x op c) op y" as "(x op y) op c".  */
1420169689Skan      if (swap_commutative_operands_p (XEXP (op0, 1), op1))
142190075Sobrien	{
1422169689Skan	  tem = simplify_gen_binary (code, mode, XEXP (op0, 0), op1);
1423169689Skan	  return simplify_gen_binary (code, mode, tem, XEXP (op0, 1));
1424169689Skan	}
142590075Sobrien
1426169689Skan      /* Attempt to simplify "(a op b) op c" as "a op (b op c)".  */
1427169689Skan      tem = swap_commutative_operands_p (XEXP (op0, 1), op1)
1428169689Skan	    ? simplify_binary_operation (code, mode, op1, XEXP (op0, 1))
1429169689Skan	    : simplify_binary_operation (code, mode, XEXP (op0, 1), op1);
1430169689Skan      if (tem != 0)
1431169689Skan        return simplify_gen_binary (code, mode, XEXP (op0, 0), tem);
1432132718Skan
1433169689Skan      /* Attempt to simplify "(a op b) op c" as "(a op c) op b".  */
1434169689Skan      tem = swap_commutative_operands_p (XEXP (op0, 0), op1)
1435169689Skan	    ? simplify_binary_operation (code, mode, op1, XEXP (op0, 0))
1436169689Skan	    : simplify_binary_operation (code, mode, XEXP (op0, 0), op1);
1437169689Skan      if (tem != 0)
1438169689Skan        return simplify_gen_binary (code, mode, tem, XEXP (op0, 1));
1439169689Skan    }
1440132718Skan
1441169689Skan  return 0;
1442169689Skan}
1443132718Skan
1444132718Skan
1445169689Skan/* Simplify a binary operation CODE with result mode MODE, operating on OP0
1446169689Skan   and OP1.  Return 0 if no simplification is possible.
1447132718Skan
1448169689Skan   Don't use this for relational operations such as EQ or LT.
1449169689Skan   Use simplify_relational_operation instead.  */
1450169689Skanrtx
1451169689Skansimplify_binary_operation (enum rtx_code code, enum machine_mode mode,
1452169689Skan			   rtx op0, rtx op1)
1453169689Skan{
1454169689Skan  rtx trueop0, trueop1;
1455169689Skan  rtx tem;
1456169689Skan
1457169689Skan  /* Relational operations don't work here.  We must know the mode
1458169689Skan     of the operands in order to do the comparison correctly.
1459169689Skan     Assuming a full word can give incorrect results.
1460169689Skan     Consider comparing 128 with -128 in QImode.  */
1461169689Skan  gcc_assert (GET_RTX_CLASS (code) != RTX_COMPARE);
1462169689Skan  gcc_assert (GET_RTX_CLASS (code) != RTX_COMM_COMPARE);
1463169689Skan
1464169689Skan  /* Make sure the constant is second.  */
1465169689Skan  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
1466169689Skan      && swap_commutative_operands_p (op0, op1))
1467169689Skan    {
1468169689Skan      tem = op0, op0 = op1, op1 = tem;
1469169689Skan    }
1470169689Skan
1471169689Skan  trueop0 = avoid_constant_pool_reference (op0);
1472169689Skan  trueop1 = avoid_constant_pool_reference (op1);
1473169689Skan
1474169689Skan  tem = simplify_const_binary_operation (code, mode, trueop0, trueop1);
1475169689Skan  if (tem)
1476169689Skan    return tem;
1477169689Skan  return simplify_binary_operation_1 (code, mode, op0, op1, trueop0, trueop1);
1478169689Skan}
1479169689Skan
1480169689Skan/* Subroutine of simplify_binary_operation.  Simplify a binary operation
1481169689Skan   CODE with result mode MODE, operating on OP0 and OP1.  If OP0 and/or
1482169689Skan   OP1 are constant pool references, TRUEOP0 and TRUEOP1 represent the
1483169689Skan   actual constants.  */
1484169689Skan
1485169689Skanstatic rtx
1486169689Skansimplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
1487169689Skan			     rtx op0, rtx op1, rtx trueop0, rtx trueop1)
1488169689Skan{
1489169689Skan  rtx tem, reversed, opleft, opright;
1490169689Skan  HOST_WIDE_INT val;
1491169689Skan  unsigned int width = GET_MODE_BITSIZE (mode);
1492169689Skan
1493169689Skan  /* Even if we can't compute a constant result,
1494169689Skan     there are some cases worth simplifying.  */
1495169689Skan
1496169689Skan  switch (code)
1497169689Skan    {
1498169689Skan    case PLUS:
1499169689Skan      /* Maybe simplify x + 0 to x.  The two expressions are equivalent
1500169689Skan	 when x is NaN, infinite, or finite and nonzero.  They aren't
1501169689Skan	 when x is -0 and the rounding mode is not towards -infinity,
1502169689Skan	 since (-0) + 0 is then 0.  */
1503169689Skan      if (!HONOR_SIGNED_ZEROS (mode) && trueop1 == CONST0_RTX (mode))
1504169689Skan	return op0;
1505169689Skan
1506169689Skan      /* ((-a) + b) -> (b - a) and similarly for (a + (-b)).  These
1507169689Skan	 transformations are safe even for IEEE.  */
1508169689Skan      if (GET_CODE (op0) == NEG)
1509169689Skan	return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
1510169689Skan      else if (GET_CODE (op1) == NEG)
1511169689Skan	return simplify_gen_binary (MINUS, mode, op0, XEXP (op1, 0));
1512169689Skan
1513169689Skan      /* (~a) + 1 -> -a */
1514169689Skan      if (INTEGRAL_MODE_P (mode)
1515169689Skan	  && GET_CODE (op0) == NOT
1516169689Skan	  && trueop1 == const1_rtx)
1517169689Skan	return simplify_gen_unary (NEG, mode, XEXP (op0, 0), mode);
1518169689Skan
1519169689Skan      /* Handle both-operands-constant cases.  We can only add
1520169689Skan	 CONST_INTs to constants since the sum of relocatable symbols
1521169689Skan	 can't be handled by most assemblers.  Don't add CONST_INT
1522169689Skan	 to CONST_INT since overflow won't be computed properly if wider
1523169689Skan	 than HOST_BITS_PER_WIDE_INT.  */
1524169689Skan
1525169689Skan      if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode
1526169689Skan	  && GET_CODE (op1) == CONST_INT)
1527169689Skan	return plus_constant (op0, INTVAL (op1));
1528169689Skan      else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode
1529169689Skan	       && GET_CODE (op0) == CONST_INT)
1530169689Skan	return plus_constant (op1, INTVAL (op0));
1531169689Skan
1532169689Skan      /* See if this is something like X * C - X or vice versa or
1533169689Skan	 if the multiplication is written as a shift.  If so, we can
1534169689Skan	 distribute and make a new multiply, shift, or maybe just
1535169689Skan	 have X (if C is 2 in the example above).  But don't make
1536169689Skan	 something more expensive than we had before.  */
1537169689Skan
1538169689Skan      if (SCALAR_INT_MODE_P (mode))
1539169689Skan	{
1540169689Skan	  HOST_WIDE_INT coeff0h = 0, coeff1h = 0;
1541169689Skan	  unsigned HOST_WIDE_INT coeff0l = 1, coeff1l = 1;
1542169689Skan	  rtx lhs = op0, rhs = op1;
1543169689Skan
1544169689Skan	  if (GET_CODE (lhs) == NEG)
1545132718Skan	    {
1546169689Skan	      coeff0l = -1;
1547169689Skan	      coeff0h = -1;
1548169689Skan	      lhs = XEXP (lhs, 0);
1549132718Skan	    }
1550169689Skan	  else if (GET_CODE (lhs) == MULT
1551169689Skan		   && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
1552169689Skan	    {
1553169689Skan	      coeff0l = INTVAL (XEXP (lhs, 1));
1554169689Skan	      coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
1555169689Skan	      lhs = XEXP (lhs, 0);
1556169689Skan	    }
1557169689Skan	  else if (GET_CODE (lhs) == ASHIFT
1558169689Skan		   && GET_CODE (XEXP (lhs, 1)) == CONST_INT
1559169689Skan		   && INTVAL (XEXP (lhs, 1)) >= 0
1560169689Skan		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
1561169689Skan	    {
1562169689Skan	      coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
1563169689Skan	      coeff0h = 0;
1564169689Skan	      lhs = XEXP (lhs, 0);
1565169689Skan	    }
1566132718Skan
1567169689Skan	  if (GET_CODE (rhs) == NEG)
1568169689Skan	    {
1569169689Skan	      coeff1l = -1;
1570169689Skan	      coeff1h = -1;
1571169689Skan	      rhs = XEXP (rhs, 0);
1572169689Skan	    }
1573169689Skan	  else if (GET_CODE (rhs) == MULT
1574169689Skan		   && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
1575169689Skan	    {
1576169689Skan	      coeff1l = INTVAL (XEXP (rhs, 1));
1577169689Skan	      coeff1h = INTVAL (XEXP (rhs, 1)) < 0 ? -1 : 0;
1578169689Skan	      rhs = XEXP (rhs, 0);
1579169689Skan	    }
1580169689Skan	  else if (GET_CODE (rhs) == ASHIFT
1581169689Skan		   && GET_CODE (XEXP (rhs, 1)) == CONST_INT
1582169689Skan		   && INTVAL (XEXP (rhs, 1)) >= 0
1583169689Skan		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
1584169689Skan	    {
1585169689Skan	      coeff1l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
1586169689Skan	      coeff1h = 0;
1587169689Skan	      rhs = XEXP (rhs, 0);
1588169689Skan	    }
1589132718Skan
1590169689Skan	  if (rtx_equal_p (lhs, rhs))
1591169689Skan	    {
1592169689Skan	      rtx orig = gen_rtx_PLUS (mode, op0, op1);
1593169689Skan	      rtx coeff;
1594169689Skan	      unsigned HOST_WIDE_INT l;
1595169689Skan	      HOST_WIDE_INT h;
1596132718Skan
1597169689Skan	      add_double (coeff0l, coeff0h, coeff1l, coeff1h, &l, &h);
1598169689Skan	      coeff = immed_double_const (l, h, mode);
1599132718Skan
1600169689Skan	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
1601169689Skan	      return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
1602169689Skan		? tem : 0;
1603169689Skan	    }
1604169689Skan	}
160590075Sobrien
1606169689Skan      /* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit.  */
1607169689Skan      if ((GET_CODE (op1) == CONST_INT
1608169689Skan	   || GET_CODE (op1) == CONST_DOUBLE)
1609169689Skan	  && GET_CODE (op0) == XOR
1610169689Skan	  && (GET_CODE (XEXP (op0, 1)) == CONST_INT
1611169689Skan	      || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)
1612169689Skan	  && mode_signbit_p (mode, op1))
1613169689Skan	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
1614169689Skan				    simplify_gen_binary (XOR, mode, op1,
1615169689Skan							 XEXP (op0, 1)));
1616132718Skan
1617169689Skan      /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).  */
1618169689Skan      if (GET_CODE (op0) == MULT
1619169689Skan	  && GET_CODE (XEXP (op0, 0)) == NEG)
1620169689Skan	{
1621169689Skan	  rtx in1, in2;
1622132718Skan
1623169689Skan	  in1 = XEXP (XEXP (op0, 0), 0);
1624169689Skan	  in2 = XEXP (op0, 1);
1625169689Skan	  return simplify_gen_binary (MINUS, mode, op1,
1626169689Skan				      simplify_gen_binary (MULT, mode,
1627169689Skan							   in1, in2));
1628169689Skan	}
1629132718Skan
1630169689Skan      /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
1631169689Skan	 C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
1632169689Skan	 is 1.  */
1633169689Skan      if (COMPARISON_P (op0)
1634169689Skan	  && ((STORE_FLAG_VALUE == -1 && trueop1 == const1_rtx)
1635169689Skan	      || (STORE_FLAG_VALUE == 1 && trueop1 == constm1_rtx))
1636169689Skan	  && (reversed = reversed_comparison (op0, mode)))
1637169689Skan	return
1638169689Skan	  simplify_gen_unary (NEG, mode, reversed, mode);
1639132718Skan
1640169689Skan      /* If one of the operands is a PLUS or a MINUS, see if we can
1641169689Skan	 simplify this by the associative law.
1642169689Skan	 Don't use the associative law for floating point.
1643169689Skan	 The inaccuracy makes it nonassociative,
1644169689Skan	 and subtle programs can break if operations are associated.  */
1645169689Skan
1646169689Skan      if (INTEGRAL_MODE_P (mode)
1647169689Skan	  && (plus_minus_operand_p (op0)
1648169689Skan	      || plus_minus_operand_p (op1))
1649169689Skan	  && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
1650169689Skan	return tem;
1651169689Skan
1652169689Skan      /* Reassociate floating point addition only when the user
1653169689Skan	 specifies unsafe math optimizations.  */
1654169689Skan      if (FLOAT_MODE_P (mode)
1655169689Skan	  && flag_unsafe_math_optimizations)
1656169689Skan	{
1657169689Skan	  tem = simplify_associative_operation (code, mode, op0, op1);
1658169689Skan	  if (tem)
1659169689Skan	    return tem;
1660169689Skan	}
1661169689Skan      break;
1662169689Skan
1663169689Skan    case COMPARE:
1664169689Skan#ifdef HAVE_cc0
1665169689Skan      /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
1666169689Skan	 using cc0, in which case we want to leave it as a COMPARE
1667169689Skan	 so we can distinguish it from a register-register-copy.
1668169689Skan
1669169689Skan	 In IEEE floating point, x-0 is not the same as x.  */
1670169689Skan
1671169689Skan      if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
1672169689Skan	   || ! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
1673169689Skan	  && trueop1 == CONST0_RTX (mode))
1674169689Skan	return op0;
1675169689Skan#endif
1676169689Skan
1677169689Skan      /* Convert (compare (gt (flags) 0) (lt (flags) 0)) to (flags).  */
1678169689Skan      if (((GET_CODE (op0) == GT && GET_CODE (op1) == LT)
1679169689Skan	   || (GET_CODE (op0) == GTU && GET_CODE (op1) == LTU))
1680169689Skan	  && XEXP (op0, 1) == const0_rtx && XEXP (op1, 1) == const0_rtx)
1681169689Skan	{
1682169689Skan	  rtx xop00 = XEXP (op0, 0);
1683169689Skan	  rtx xop10 = XEXP (op1, 0);
1684169689Skan
1685169689Skan#ifdef HAVE_cc0
1686169689Skan	  if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
1687169689Skan#else
1688169689Skan	    if (REG_P (xop00) && REG_P (xop10)
1689169689Skan		&& GET_MODE (xop00) == GET_MODE (xop10)
1690169689Skan		&& REGNO (xop00) == REGNO (xop10)
1691169689Skan		&& GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
1692169689Skan		&& GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
1693169689Skan#endif
1694169689Skan	      return xop00;
1695169689Skan	}
1696169689Skan      break;
1697169689Skan
1698169689Skan    case MINUS:
1699169689Skan      /* We can't assume x-x is 0 even with non-IEEE floating point,
1700169689Skan	 but since it is zero except in very strange circumstances, we
1701169689Skan	 will treat it as zero with -funsafe-math-optimizations.  */
1702169689Skan      if (rtx_equal_p (trueop0, trueop1)
1703169689Skan	  && ! side_effects_p (op0)
1704169689Skan	  && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations))
1705169689Skan	return CONST0_RTX (mode);
1706169689Skan
1707169689Skan      /* Change subtraction from zero into negation.  (0 - x) is the
1708169689Skan	 same as -x when x is NaN, infinite, or finite and nonzero.
1709169689Skan	 But if the mode has signed zeros, and does not round towards
1710169689Skan	 -infinity, then 0 - 0 is 0, not -0.  */
1711169689Skan      if (!HONOR_SIGNED_ZEROS (mode) && trueop0 == CONST0_RTX (mode))
1712169689Skan	return simplify_gen_unary (NEG, mode, op1, mode);
1713169689Skan
1714169689Skan      /* (-1 - a) is ~a.  */
1715169689Skan      if (trueop0 == constm1_rtx)
1716169689Skan	return simplify_gen_unary (NOT, mode, op1, mode);
1717169689Skan
1718169689Skan      /* Subtracting 0 has no effect unless the mode has signed zeros
1719169689Skan	 and supports rounding towards -infinity.  In such a case,
1720169689Skan	 0 - 0 is -0.  */
1721169689Skan      if (!(HONOR_SIGNED_ZEROS (mode)
1722169689Skan	    && HONOR_SIGN_DEPENDENT_ROUNDING (mode))
1723169689Skan	  && trueop1 == CONST0_RTX (mode))
1724169689Skan	return op0;
1725169689Skan
1726169689Skan      /* See if this is something like X * C - X or vice versa or
1727169689Skan	 if the multiplication is written as a shift.  If so, we can
1728169689Skan	 distribute and make a new multiply, shift, or maybe just
1729169689Skan	 have X (if C is 2 in the example above).  But don't make
1730169689Skan	 something more expensive than we had before.  */
1731169689Skan
1732169689Skan      if (SCALAR_INT_MODE_P (mode))
1733169689Skan	{
1734169689Skan	  HOST_WIDE_INT coeff0h = 0, negcoeff1h = -1;
1735169689Skan	  unsigned HOST_WIDE_INT coeff0l = 1, negcoeff1l = -1;
1736169689Skan	  rtx lhs = op0, rhs = op1;
1737169689Skan
1738169689Skan	  if (GET_CODE (lhs) == NEG)
1739132718Skan	    {
1740169689Skan	      coeff0l = -1;
1741169689Skan	      coeff0h = -1;
1742169689Skan	      lhs = XEXP (lhs, 0);
1743169689Skan	    }
1744169689Skan	  else if (GET_CODE (lhs) == MULT
1745169689Skan		   && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
1746169689Skan	    {
1747169689Skan	      coeff0l = INTVAL (XEXP (lhs, 1));
1748169689Skan	      coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
1749169689Skan	      lhs = XEXP (lhs, 0);
1750169689Skan	    }
1751169689Skan	  else if (GET_CODE (lhs) == ASHIFT
1752169689Skan		   && GET_CODE (XEXP (lhs, 1)) == CONST_INT
1753169689Skan		   && INTVAL (XEXP (lhs, 1)) >= 0
1754169689Skan		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
1755169689Skan	    {
1756169689Skan	      coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
1757169689Skan	      coeff0h = 0;
1758169689Skan	      lhs = XEXP (lhs, 0);
1759169689Skan	    }
1760169689Skan
1761169689Skan	  if (GET_CODE (rhs) == NEG)
1762169689Skan	    {
1763169689Skan	      negcoeff1l = 1;
1764169689Skan	      negcoeff1h = 0;
1765169689Skan	      rhs = XEXP (rhs, 0);
1766169689Skan	    }
1767169689Skan	  else if (GET_CODE (rhs) == MULT
1768169689Skan		   && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
1769169689Skan	    {
1770169689Skan	      negcoeff1l = -INTVAL (XEXP (rhs, 1));
1771169689Skan	      negcoeff1h = INTVAL (XEXP (rhs, 1)) <= 0 ? 0 : -1;
1772169689Skan	      rhs = XEXP (rhs, 0);
1773169689Skan	    }
1774169689Skan	  else if (GET_CODE (rhs) == ASHIFT
1775169689Skan		   && GET_CODE (XEXP (rhs, 1)) == CONST_INT
1776169689Skan		   && INTVAL (XEXP (rhs, 1)) >= 0
1777169689Skan		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
1778169689Skan	    {
1779169689Skan	      negcoeff1l = -(((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)));
1780169689Skan	      negcoeff1h = -1;
1781169689Skan	      rhs = XEXP (rhs, 0);
1782169689Skan	    }
1783169689Skan
1784169689Skan	  if (rtx_equal_p (lhs, rhs))
1785169689Skan	    {
1786169689Skan	      rtx orig = gen_rtx_MINUS (mode, op0, op1);
1787169689Skan	      rtx coeff;
1788169689Skan	      unsigned HOST_WIDE_INT l;
1789169689Skan	      HOST_WIDE_INT h;
1790169689Skan
1791169689Skan	      add_double (coeff0l, coeff0h, negcoeff1l, negcoeff1h, &l, &h);
1792169689Skan	      coeff = immed_double_const (l, h, mode);
1793169689Skan
1794169689Skan	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
1795169689Skan	      return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
1796169689Skan		? tem : 0;
1797169689Skan	    }
1798169689Skan	}
1799169689Skan
1800169689Skan      /* (a - (-b)) -> (a + b).  True even for IEEE.  */
1801169689Skan      if (GET_CODE (op1) == NEG)
1802169689Skan	return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
1803169689Skan
1804169689Skan      /* (-x - c) may be simplified as (-c - x).  */
1805169689Skan      if (GET_CODE (op0) == NEG
1806169689Skan	  && (GET_CODE (op1) == CONST_INT
1807169689Skan	      || GET_CODE (op1) == CONST_DOUBLE))
1808169689Skan	{
1809169689Skan	  tem = simplify_unary_operation (NEG, mode, op1, mode);
1810169689Skan	  if (tem)
1811169689Skan	    return simplify_gen_binary (MINUS, mode, tem, XEXP (op0, 0));
1812169689Skan	}
1813169689Skan
1814169689Skan      /* Don't let a relocatable value get a negative coeff.  */
1815169689Skan      if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode)
1816169689Skan	return simplify_gen_binary (PLUS, mode,
1817169689Skan				    op0,
1818169689Skan				    neg_const_int (mode, op1));
1819169689Skan
1820169689Skan      /* (x - (x & y)) -> (x & ~y) */
1821169689Skan      if (GET_CODE (op1) == AND)
1822169689Skan	{
1823169689Skan	  if (rtx_equal_p (op0, XEXP (op1, 0)))
1824169689Skan	    {
1825169689Skan	      tem = simplify_gen_unary (NOT, mode, XEXP (op1, 1),
1826169689Skan					GET_MODE (XEXP (op1, 1)));
1827169689Skan	      return simplify_gen_binary (AND, mode, op0, tem);
1828169689Skan	    }
1829169689Skan	  if (rtx_equal_p (op0, XEXP (op1, 1)))
1830169689Skan	    {
1831169689Skan	      tem = simplify_gen_unary (NOT, mode, XEXP (op1, 0),
1832169689Skan					GET_MODE (XEXP (op1, 0)));
1833169689Skan	      return simplify_gen_binary (AND, mode, op0, tem);
1834169689Skan	    }
1835169689Skan	}
1836169689Skan
1837169689Skan      /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
1838169689Skan	 by reversing the comparison code if valid.  */
1839169689Skan      if (STORE_FLAG_VALUE == 1
1840169689Skan	  && trueop0 == const1_rtx
1841169689Skan	  && COMPARISON_P (op1)
1842169689Skan	  && (reversed = reversed_comparison (op1, mode)))
1843169689Skan	return reversed;
1844169689Skan
1845169689Skan      /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).  */
1846169689Skan      if (GET_CODE (op1) == MULT
1847169689Skan	  && GET_CODE (XEXP (op1, 0)) == NEG)
1848169689Skan	{
1849169689Skan	  rtx in1, in2;
1850169689Skan
1851169689Skan	  in1 = XEXP (XEXP (op1, 0), 0);
1852169689Skan	  in2 = XEXP (op1, 1);
1853169689Skan	  return simplify_gen_binary (PLUS, mode,
1854169689Skan				      simplify_gen_binary (MULT, mode,
1855169689Skan							   in1, in2),
1856169689Skan				      op0);
1857169689Skan	}
1858169689Skan
1859169689Skan      /* Canonicalize (minus (neg A) (mult B C)) to
1860169689Skan	 (minus (mult (neg B) C) A).  */
1861169689Skan      if (GET_CODE (op1) == MULT
1862169689Skan	  && GET_CODE (op0) == NEG)
1863169689Skan	{
1864169689Skan	  rtx in1, in2;
1865169689Skan
1866169689Skan	  in1 = simplify_gen_unary (NEG, mode, XEXP (op1, 0), mode);
1867169689Skan	  in2 = XEXP (op1, 1);
1868169689Skan	  return simplify_gen_binary (MINUS, mode,
1869169689Skan				      simplify_gen_binary (MULT, mode,
1870169689Skan							   in1, in2),
1871169689Skan				      XEXP (op0, 0));
1872169689Skan	}
1873169689Skan
1874169689Skan      /* If one of the operands is a PLUS or a MINUS, see if we can
1875169689Skan	 simplify this by the associative law.  This will, for example,
1876169689Skan         canonicalize (minus A (plus B C)) to (minus (minus A B) C).
1877169689Skan	 Don't use the associative law for floating point.
1878169689Skan	 The inaccuracy makes it nonassociative,
1879169689Skan	 and subtle programs can break if operations are associated.  */
1880169689Skan
1881169689Skan      if (INTEGRAL_MODE_P (mode)
1882169689Skan	  && (plus_minus_operand_p (op0)
1883169689Skan	      || plus_minus_operand_p (op1))
1884169689Skan	  && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
1885169689Skan	return tem;
1886169689Skan      break;
1887169689Skan
1888169689Skan    case MULT:
1889169689Skan      if (trueop1 == constm1_rtx)
1890169689Skan	return simplify_gen_unary (NEG, mode, op0, mode);
1891169689Skan
1892169689Skan      /* Maybe simplify x * 0 to 0.  The reduction is not valid if
1893169689Skan	 x is NaN, since x * 0 is then also NaN.  Nor is it valid
1894169689Skan	 when the mode has signed zeros, since multiplying a negative
1895169689Skan	 number by 0 will give -0, not 0.  */
1896169689Skan      if (!HONOR_NANS (mode)
1897169689Skan	  && !HONOR_SIGNED_ZEROS (mode)
1898169689Skan	  && trueop1 == CONST0_RTX (mode)
1899169689Skan	  && ! side_effects_p (op0))
1900169689Skan	return op1;
1901169689Skan
1902169689Skan      /* In IEEE floating point, x*1 is not equivalent to x for
1903169689Skan	 signalling NaNs.  */
1904169689Skan      if (!HONOR_SNANS (mode)
1905169689Skan	  && trueop1 == CONST1_RTX (mode))
1906169689Skan	return op0;
1907169689Skan
1908169689Skan      /* Convert multiply by constant power of two into shift unless
1909169689Skan	 we are still generating RTL.  This test is a kludge.  */
1910169689Skan      if (GET_CODE (trueop1) == CONST_INT
1911169689Skan	  && (val = exact_log2 (INTVAL (trueop1))) >= 0
1912169689Skan	  /* If the mode is larger than the host word size, and the
1913169689Skan	     uppermost bit is set, then this isn't a power of two due
1914169689Skan	     to implicit sign extension.  */
1915169689Skan	  && (width <= HOST_BITS_PER_WIDE_INT
1916169689Skan	      || val != HOST_BITS_PER_WIDE_INT - 1))
1917169689Skan	return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
1918169689Skan
1919169689Skan      /* Likewise for multipliers wider than a word.  */
1920169689Skan      if (GET_CODE (trueop1) == CONST_DOUBLE
1921169689Skan	  && (GET_MODE (trueop1) == VOIDmode
1922169689Skan	      || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
1923169689Skan	  && GET_MODE (op0) == mode
1924169689Skan	  && CONST_DOUBLE_LOW (trueop1) == 0
1925169689Skan	  && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
1926169689Skan	return simplify_gen_binary (ASHIFT, mode, op0,
1927169689Skan				    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
1928169689Skan
1929169689Skan      /* x*2 is x+x and x*(-1) is -x */
1930169689Skan      if (GET_CODE (trueop1) == CONST_DOUBLE
1931169689Skan	  && SCALAR_FLOAT_MODE_P (GET_MODE (trueop1))
1932169689Skan	  && GET_MODE (op0) == mode)
1933169689Skan	{
1934169689Skan	  REAL_VALUE_TYPE d;
1935169689Skan	  REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
1936169689Skan
1937169689Skan	  if (REAL_VALUES_EQUAL (d, dconst2))
1938169689Skan	    return simplify_gen_binary (PLUS, mode, op0, copy_rtx (op0));
1939169689Skan
1940169689Skan	  if (!HONOR_SNANS (mode)
1941169689Skan	      && REAL_VALUES_EQUAL (d, dconstm1))
1942169689Skan	    return simplify_gen_unary (NEG, mode, op0, mode);
1943169689Skan	}
1944169689Skan
1945169689Skan      /* Optimize -x * -x as x * x.  */
1946169689Skan      if (FLOAT_MODE_P (mode)
1947169689Skan	  && GET_CODE (op0) == NEG
1948169689Skan	  && GET_CODE (op1) == NEG
1949169689Skan	  && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
1950169689Skan	  && !side_effects_p (XEXP (op0, 0)))
1951169689Skan	return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0));
1952169689Skan
1953169689Skan      /* Likewise, optimize abs(x) * abs(x) as x * x.  */
1954169689Skan      if (SCALAR_FLOAT_MODE_P (mode)
1955169689Skan	  && GET_CODE (op0) == ABS
1956169689Skan	  && GET_CODE (op1) == ABS
1957169689Skan	  && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
1958169689Skan	  && !side_effects_p (XEXP (op0, 0)))
1959169689Skan	return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0));
1960169689Skan
1961169689Skan      /* Reassociate multiplication, but for floating point MULTs
1962169689Skan	 only when the user specifies unsafe math optimizations.  */
1963169689Skan      if (! FLOAT_MODE_P (mode)
1964169689Skan	  || flag_unsafe_math_optimizations)
1965169689Skan	{
1966169689Skan	  tem = simplify_associative_operation (code, mode, op0, op1);
1967169689Skan	  if (tem)
1968169689Skan	    return tem;
1969169689Skan	}
1970169689Skan      break;
1971169689Skan
1972169689Skan    case IOR:
1973169689Skan      if (trueop1 == const0_rtx)
1974169689Skan	return op0;
1975169689Skan      if (GET_CODE (trueop1) == CONST_INT
1976169689Skan	  && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
1977169689Skan	      == GET_MODE_MASK (mode)))
1978169689Skan	return op1;
1979169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
1980169689Skan	return op0;
1981169689Skan      /* A | (~A) -> -1 */
1982169689Skan      if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
1983169689Skan	   || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
1984169689Skan	  && ! side_effects_p (op0)
1985169689Skan	  && SCALAR_INT_MODE_P (mode))
1986169689Skan	return constm1_rtx;
1987169689Skan
1988169689Skan      /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
1989169689Skan      if (GET_CODE (op1) == CONST_INT
1990169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
1991169689Skan	  && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
1992169689Skan	return op1;
1993169689Skan
1994169689Skan      /* Convert (A & B) | A to A.  */
1995169689Skan      if (GET_CODE (op0) == AND
1996169689Skan	  && (rtx_equal_p (XEXP (op0, 0), op1)
1997169689Skan	      || rtx_equal_p (XEXP (op0, 1), op1))
1998169689Skan	  && ! side_effects_p (XEXP (op0, 0))
1999169689Skan	  && ! side_effects_p (XEXP (op0, 1)))
2000169689Skan	return op1;
2001169689Skan
2002169689Skan      /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
2003169689Skan         mode size to (rotate A CX).  */
2004169689Skan
2005169689Skan      if (GET_CODE (op1) == ASHIFT
2006169689Skan          || GET_CODE (op1) == SUBREG)
2007169689Skan        {
2008169689Skan	  opleft = op1;
2009169689Skan	  opright = op0;
2010169689Skan	}
2011169689Skan      else
2012169689Skan        {
2013169689Skan	  opright = op1;
2014169689Skan	  opleft = op0;
2015169689Skan	}
2016169689Skan
2017169689Skan      if (GET_CODE (opleft) == ASHIFT && GET_CODE (opright) == LSHIFTRT
2018169689Skan          && rtx_equal_p (XEXP (opleft, 0), XEXP (opright, 0))
2019169689Skan          && GET_CODE (XEXP (opleft, 1)) == CONST_INT
2020169689Skan          && GET_CODE (XEXP (opright, 1)) == CONST_INT
2021169689Skan          && (INTVAL (XEXP (opleft, 1)) + INTVAL (XEXP (opright, 1))
2022169689Skan              == GET_MODE_BITSIZE (mode)))
2023169689Skan        return gen_rtx_ROTATE (mode, XEXP (opright, 0), XEXP (opleft, 1));
2024169689Skan
2025169689Skan      /* Same, but for ashift that has been "simplified" to a wider mode
2026169689Skan        by simplify_shift_const.  */
2027169689Skan
2028169689Skan      if (GET_CODE (opleft) == SUBREG
2029169689Skan          && GET_CODE (SUBREG_REG (opleft)) == ASHIFT
2030169689Skan          && GET_CODE (opright) == LSHIFTRT
2031169689Skan          && GET_CODE (XEXP (opright, 0)) == SUBREG
2032169689Skan          && GET_MODE (opleft) == GET_MODE (XEXP (opright, 0))
2033169689Skan          && SUBREG_BYTE (opleft) == SUBREG_BYTE (XEXP (opright, 0))
2034169689Skan          && (GET_MODE_SIZE (GET_MODE (opleft))
2035169689Skan              < GET_MODE_SIZE (GET_MODE (SUBREG_REG (opleft))))
2036169689Skan          && rtx_equal_p (XEXP (SUBREG_REG (opleft), 0),
2037169689Skan                          SUBREG_REG (XEXP (opright, 0)))
2038169689Skan          && GET_CODE (XEXP (SUBREG_REG (opleft), 1)) == CONST_INT
2039169689Skan          && GET_CODE (XEXP (opright, 1)) == CONST_INT
2040169689Skan          && (INTVAL (XEXP (SUBREG_REG (opleft), 1)) + INTVAL (XEXP (opright, 1))
2041169689Skan              == GET_MODE_BITSIZE (mode)))
2042169689Skan        return gen_rtx_ROTATE (mode, XEXP (opright, 0),
2043169689Skan                               XEXP (SUBREG_REG (opleft), 1));
2044169689Skan
2045169689Skan      /* If we have (ior (and (X C1) C2)), simplify this by making
2046169689Skan	 C1 as small as possible if C1 actually changes.  */
2047169689Skan      if (GET_CODE (op1) == CONST_INT
2048169689Skan	  && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2049169689Skan	      || INTVAL (op1) > 0)
2050169689Skan	  && GET_CODE (op0) == AND
2051169689Skan	  && GET_CODE (XEXP (op0, 1)) == CONST_INT
2052169689Skan	  && GET_CODE (op1) == CONST_INT
2053169689Skan	  && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
2054169689Skan	return simplify_gen_binary (IOR, mode,
2055169689Skan				    simplify_gen_binary
2056169689Skan					  (AND, mode, XEXP (op0, 0),
2057169689Skan					   GEN_INT (INTVAL (XEXP (op0, 1))
2058169689Skan						    & ~INTVAL (op1))),
2059169689Skan				    op1);
2060169689Skan
2061169689Skan      /* If OP0 is (ashiftrt (plus ...) C), it might actually be
2062169689Skan         a (sign_extend (plus ...)).  Then check if OP1 is a CONST_INT and
2063169689Skan	 the PLUS does not affect any of the bits in OP1: then we can do
2064169689Skan	 the IOR as a PLUS and we can associate.  This is valid if OP1
2065169689Skan         can be safely shifted left C bits.  */
2066169689Skan      if (GET_CODE (trueop1) == CONST_INT && GET_CODE (op0) == ASHIFTRT
2067169689Skan          && GET_CODE (XEXP (op0, 0)) == PLUS
2068169689Skan          && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
2069169689Skan          && GET_CODE (XEXP (op0, 1)) == CONST_INT
2070169689Skan          && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT)
2071169689Skan        {
2072169689Skan          int count = INTVAL (XEXP (op0, 1));
2073169689Skan          HOST_WIDE_INT mask = INTVAL (trueop1) << count;
2074169689Skan
2075169689Skan          if (mask >> count == INTVAL (trueop1)
2076169689Skan              && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
2077169689Skan	    return simplify_gen_binary (ASHIFTRT, mode,
2078169689Skan					plus_constant (XEXP (op0, 0), mask),
2079169689Skan					XEXP (op0, 1));
2080169689Skan        }
2081169689Skan
2082169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2083169689Skan      if (tem)
2084169689Skan	return tem;
2085169689Skan      break;
2086169689Skan
2087169689Skan    case XOR:
2088169689Skan      if (trueop1 == const0_rtx)
2089169689Skan	return op0;
2090169689Skan      if (GET_CODE (trueop1) == CONST_INT
2091169689Skan	  && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
2092169689Skan	      == GET_MODE_MASK (mode)))
2093169689Skan	return simplify_gen_unary (NOT, mode, op0, mode);
2094169689Skan      if (rtx_equal_p (trueop0, trueop1)
2095169689Skan	  && ! side_effects_p (op0)
2096169689Skan	  && GET_MODE_CLASS (mode) != MODE_CC)
2097169689Skan	 return CONST0_RTX (mode);
2098169689Skan
2099169689Skan      /* Canonicalize XOR of the most significant bit to PLUS.  */
2100169689Skan      if ((GET_CODE (op1) == CONST_INT
2101169689Skan	   || GET_CODE (op1) == CONST_DOUBLE)
2102169689Skan	  && mode_signbit_p (mode, op1))
2103169689Skan	return simplify_gen_binary (PLUS, mode, op0, op1);
2104169689Skan      /* (xor (plus X C1) C2) is (xor X (C1^C2)) if C1 is signbit.  */
2105169689Skan      if ((GET_CODE (op1) == CONST_INT
2106169689Skan	   || GET_CODE (op1) == CONST_DOUBLE)
2107169689Skan	  && GET_CODE (op0) == PLUS
2108169689Skan	  && (GET_CODE (XEXP (op0, 1)) == CONST_INT
2109169689Skan	      || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)
2110169689Skan	  && mode_signbit_p (mode, XEXP (op0, 1)))
2111169689Skan	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
2112169689Skan				    simplify_gen_binary (XOR, mode, op1,
2113169689Skan							 XEXP (op0, 1)));
2114169689Skan
2115169689Skan      /* If we are XORing two things that have no bits in common,
2116169689Skan	 convert them into an IOR.  This helps to detect rotation encoded
2117169689Skan	 using those methods and possibly other simplifications.  */
2118169689Skan
2119169689Skan      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2120169689Skan	  && (nonzero_bits (op0, mode)
2121169689Skan	      & nonzero_bits (op1, mode)) == 0)
2122169689Skan	return (simplify_gen_binary (IOR, mode, op0, op1));
2123169689Skan
2124169689Skan      /* Convert (XOR (NOT x) (NOT y)) to (XOR x y).
2125169689Skan	 Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for
2126169689Skan	 (NOT y).  */
2127169689Skan      {
2128169689Skan	int num_negated = 0;
2129169689Skan
2130169689Skan	if (GET_CODE (op0) == NOT)
2131169689Skan	  num_negated++, op0 = XEXP (op0, 0);
2132169689Skan	if (GET_CODE (op1) == NOT)
2133169689Skan	  num_negated++, op1 = XEXP (op1, 0);
2134169689Skan
2135169689Skan	if (num_negated == 2)
2136169689Skan	  return simplify_gen_binary (XOR, mode, op0, op1);
2137169689Skan	else if (num_negated == 1)
2138169689Skan	  return simplify_gen_unary (NOT, mode,
2139169689Skan				     simplify_gen_binary (XOR, mode, op0, op1),
2140169689Skan				     mode);
2141169689Skan      }
2142169689Skan
2143169689Skan      /* Convert (xor (and A B) B) to (and (not A) B).  The latter may
2144169689Skan	 correspond to a machine insn or result in further simplifications
2145169689Skan	 if B is a constant.  */
2146169689Skan
2147169689Skan      if (GET_CODE (op0) == AND
2148169689Skan	  && rtx_equal_p (XEXP (op0, 1), op1)
2149169689Skan	  && ! side_effects_p (op1))
2150169689Skan	return simplify_gen_binary (AND, mode,
2151169689Skan				    simplify_gen_unary (NOT, mode,
2152169689Skan							XEXP (op0, 0), mode),
2153169689Skan				    op1);
2154169689Skan
2155169689Skan      else if (GET_CODE (op0) == AND
2156169689Skan	       && rtx_equal_p (XEXP (op0, 0), op1)
2157169689Skan	       && ! side_effects_p (op1))
2158169689Skan	return simplify_gen_binary (AND, mode,
2159169689Skan				    simplify_gen_unary (NOT, mode,
2160169689Skan							XEXP (op0, 1), mode),
2161169689Skan				    op1);
2162169689Skan
2163169689Skan      /* (xor (comparison foo bar) (const_int 1)) can become the reversed
2164169689Skan	 comparison if STORE_FLAG_VALUE is 1.  */
2165169689Skan      if (STORE_FLAG_VALUE == 1
2166169689Skan	  && trueop1 == const1_rtx
2167169689Skan	  && COMPARISON_P (op0)
2168169689Skan	  && (reversed = reversed_comparison (op0, mode)))
2169169689Skan	return reversed;
2170169689Skan
2171169689Skan      /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
2172169689Skan	 is (lt foo (const_int 0)), so we can perform the above
2173169689Skan	 simplification if STORE_FLAG_VALUE is 1.  */
2174169689Skan
2175169689Skan      if (STORE_FLAG_VALUE == 1
2176169689Skan	  && trueop1 == const1_rtx
2177169689Skan	  && GET_CODE (op0) == LSHIFTRT
2178169689Skan	  && GET_CODE (XEXP (op0, 1)) == CONST_INT
2179169689Skan	  && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
2180169689Skan	return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx);
2181169689Skan
2182169689Skan      /* (xor (comparison foo bar) (const_int sign-bit))
2183169689Skan	 when STORE_FLAG_VALUE is the sign bit.  */
2184169689Skan      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2185169689Skan	  && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
2186169689Skan	      == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
2187169689Skan	  && trueop1 == const_true_rtx
2188169689Skan	  && COMPARISON_P (op0)
2189169689Skan	  && (reversed = reversed_comparison (op0, mode)))
2190169689Skan	return reversed;
2191169689Skan
2192169689Skan      break;
2193169689Skan
2194169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2195169689Skan      if (tem)
2196169689Skan	return tem;
2197169689Skan      break;
2198169689Skan
2199169689Skan    case AND:
2200169689Skan      if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
2201169689Skan	return trueop1;
2202169689Skan      /* If we are turning off bits already known off in OP0, we need
2203169689Skan	 not do an AND.  */
2204169689Skan      if (GET_CODE (trueop1) == CONST_INT
2205169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2206169689Skan	  && (nonzero_bits (trueop0, mode) & ~INTVAL (trueop1)) == 0)
2207169689Skan	return op0;
2208169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)
2209169689Skan	  && GET_MODE_CLASS (mode) != MODE_CC)
2210169689Skan	return op0;
2211169689Skan      /* A & (~A) -> 0 */
2212169689Skan      if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
2213169689Skan	   || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
2214169689Skan	  && ! side_effects_p (op0)
2215169689Skan	  && GET_MODE_CLASS (mode) != MODE_CC)
2216169689Skan	return CONST0_RTX (mode);
2217169689Skan
2218169689Skan      /* Transform (and (extend X) C) into (zero_extend (and X C)) if
2219169689Skan	 there are no nonzero bits of C outside of X's mode.  */
2220169689Skan      if ((GET_CODE (op0) == SIGN_EXTEND
2221169689Skan	   || GET_CODE (op0) == ZERO_EXTEND)
2222169689Skan	  && GET_CODE (trueop1) == CONST_INT
2223169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2224169689Skan	  && (~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))
2225169689Skan	      & INTVAL (trueop1)) == 0)
2226169689Skan	{
2227169689Skan	  enum machine_mode imode = GET_MODE (XEXP (op0, 0));
2228169689Skan	  tem = simplify_gen_binary (AND, imode, XEXP (op0, 0),
2229169689Skan				     gen_int_mode (INTVAL (trueop1),
2230169689Skan						   imode));
2231169689Skan	  return simplify_gen_unary (ZERO_EXTEND, mode, tem, imode);
2232169689Skan	}
2233169689Skan
2234169689Skan      /* Convert (A ^ B) & A to A & (~B) since the latter is often a single
2235169689Skan	 insn (and may simplify more).  */
2236169689Skan      if (GET_CODE (op0) == XOR
2237169689Skan	  && rtx_equal_p (XEXP (op0, 0), op1)
2238169689Skan	  && ! side_effects_p (op1))
2239169689Skan	return simplify_gen_binary (AND, mode,
2240169689Skan				    simplify_gen_unary (NOT, mode,
2241169689Skan							XEXP (op0, 1), mode),
2242169689Skan				    op1);
2243169689Skan
2244169689Skan      if (GET_CODE (op0) == XOR
2245169689Skan	  && rtx_equal_p (XEXP (op0, 1), op1)
2246169689Skan	  && ! side_effects_p (op1))
2247169689Skan	return simplify_gen_binary (AND, mode,
2248169689Skan				    simplify_gen_unary (NOT, mode,
2249169689Skan							XEXP (op0, 0), mode),
2250169689Skan				    op1);
2251169689Skan
2252169689Skan      /* Similarly for (~(A ^ B)) & A.  */
2253169689Skan      if (GET_CODE (op0) == NOT
2254169689Skan	  && GET_CODE (XEXP (op0, 0)) == XOR
2255169689Skan	  && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1)
2256169689Skan	  && ! side_effects_p (op1))
2257169689Skan	return simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
2258169689Skan
2259169689Skan      if (GET_CODE (op0) == NOT
2260169689Skan	  && GET_CODE (XEXP (op0, 0)) == XOR
2261169689Skan	  && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1)
2262169689Skan	  && ! side_effects_p (op1))
2263169689Skan	return simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
2264169689Skan
2265169689Skan      /* Convert (A | B) & A to A.  */
2266169689Skan      if (GET_CODE (op0) == IOR
2267169689Skan	  && (rtx_equal_p (XEXP (op0, 0), op1)
2268169689Skan	      || rtx_equal_p (XEXP (op0, 1), op1))
2269169689Skan	  && ! side_effects_p (XEXP (op0, 0))
2270169689Skan	  && ! side_effects_p (XEXP (op0, 1)))
2271169689Skan	return op1;
2272169689Skan
2273169689Skan      /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
2274169689Skan	 ((A & N) + B) & M -> (A + B) & M
2275169689Skan	 Similarly if (N & M) == 0,
2276169689Skan	 ((A | N) + B) & M -> (A + B) & M
2277169689Skan	 and for - instead of + and/or ^ instead of |.  */
2278169689Skan      if (GET_CODE (trueop1) == CONST_INT
2279169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2280169689Skan	  && ~INTVAL (trueop1)
2281169689Skan	  && (INTVAL (trueop1) & (INTVAL (trueop1) + 1)) == 0
2282169689Skan	  && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS))
2283169689Skan	{
2284169689Skan	  rtx pmop[2];
2285169689Skan	  int which;
2286169689Skan
2287169689Skan	  pmop[0] = XEXP (op0, 0);
2288169689Skan	  pmop[1] = XEXP (op0, 1);
2289169689Skan
2290169689Skan	  for (which = 0; which < 2; which++)
2291169689Skan	    {
2292169689Skan	      tem = pmop[which];
2293169689Skan	      switch (GET_CODE (tem))
2294132718Skan		{
2295169689Skan		case AND:
2296169689Skan		  if (GET_CODE (XEXP (tem, 1)) == CONST_INT
2297169689Skan		      && (INTVAL (XEXP (tem, 1)) & INTVAL (trueop1))
2298169689Skan		      == INTVAL (trueop1))
2299169689Skan		    pmop[which] = XEXP (tem, 0);
2300169689Skan		  break;
2301169689Skan		case IOR:
2302169689Skan		case XOR:
2303169689Skan		  if (GET_CODE (XEXP (tem, 1)) == CONST_INT
2304169689Skan		      && (INTVAL (XEXP (tem, 1)) & INTVAL (trueop1)) == 0)
2305169689Skan		    pmop[which] = XEXP (tem, 0);
2306169689Skan		  break;
2307169689Skan		default:
2308169689Skan		  break;
2309132718Skan		}
2310132718Skan	    }
2311132718Skan
2312169689Skan	  if (pmop[0] != XEXP (op0, 0) || pmop[1] != XEXP (op0, 1))
2313132718Skan	    {
2314169689Skan	      tem = simplify_gen_binary (GET_CODE (op0), mode,
2315169689Skan					 pmop[0], pmop[1]);
2316169689Skan	      return simplify_gen_binary (code, mode, tem, op1);
2317132718Skan	    }
2318169689Skan	}
2319169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2320169689Skan      if (tem)
2321169689Skan	return tem;
2322169689Skan      break;
2323132718Skan
2324169689Skan    case UDIV:
2325169689Skan      /* 0/x is 0 (or x&0 if x has side-effects).  */
2326169689Skan      if (trueop0 == CONST0_RTX (mode))
2327169689Skan	{
2328169689Skan	  if (side_effects_p (op1))
2329169689Skan	    return simplify_gen_binary (AND, mode, op1, trueop0);
2330169689Skan	  return trueop0;
2331169689Skan	}
2332169689Skan      /* x/1 is x.  */
2333169689Skan      if (trueop1 == CONST1_RTX (mode))
2334169689Skan	return rtl_hooks.gen_lowpart_no_emit (mode, op0);
2335169689Skan      /* Convert divide by power of two into shift.  */
2336169689Skan      if (GET_CODE (trueop1) == CONST_INT
2337169689Skan	  && (val = exact_log2 (INTVAL (trueop1))) > 0)
2338169689Skan	return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (val));
2339169689Skan      break;
2340169689Skan
2341169689Skan    case DIV:
2342169689Skan      /* Handle floating point and integers separately.  */
2343169689Skan      if (SCALAR_FLOAT_MODE_P (mode))
2344169689Skan	{
2345169689Skan	  /* Maybe change 0.0 / x to 0.0.  This transformation isn't
2346169689Skan	     safe for modes with NaNs, since 0.0 / 0.0 will then be
2347169689Skan	     NaN rather than 0.0.  Nor is it safe for modes with signed
2348169689Skan	     zeros, since dividing 0 by a negative number gives -0.0  */
2349169689Skan	  if (trueop0 == CONST0_RTX (mode)
2350169689Skan	      && !HONOR_NANS (mode)
2351169689Skan	      && !HONOR_SIGNED_ZEROS (mode)
2352169689Skan	      && ! side_effects_p (op1))
2353169689Skan	    return op0;
2354169689Skan	  /* x/1.0 is x.  */
2355169689Skan	  if (trueop1 == CONST1_RTX (mode)
2356169689Skan	      && !HONOR_SNANS (mode))
2357169689Skan	    return op0;
2358169689Skan
2359169689Skan	  if (GET_CODE (trueop1) == CONST_DOUBLE
2360169689Skan	      && trueop1 != CONST0_RTX (mode))
2361132718Skan	    {
2362169689Skan	      REAL_VALUE_TYPE d;
2363169689Skan	      REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
2364169689Skan
2365169689Skan	      /* x/-1.0 is -x.  */
2366169689Skan	      if (REAL_VALUES_EQUAL (d, dconstm1)
2367169689Skan		  && !HONOR_SNANS (mode))
2368169689Skan		return simplify_gen_unary (NEG, mode, op0, mode);
2369169689Skan
2370169689Skan	      /* Change FP division by a constant into multiplication.
2371169689Skan		 Only do this with -funsafe-math-optimizations.  */
2372169689Skan	      if (flag_unsafe_math_optimizations
2373169689Skan		  && !REAL_VALUES_EQUAL (d, dconst0))
2374169689Skan		{
2375169689Skan		  REAL_ARITHMETIC (d, RDIV_EXPR, dconst1, d);
2376169689Skan		  tem = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
2377169689Skan		  return simplify_gen_binary (MULT, mode, op0, tem);
2378169689Skan		}
2379132718Skan	    }
2380169689Skan	}
2381169689Skan      else
2382169689Skan	{
2383169689Skan	  /* 0/x is 0 (or x&0 if x has side-effects).  */
2384169689Skan	  if (trueop0 == CONST0_RTX (mode))
2385169689Skan	    {
2386169689Skan	      if (side_effects_p (op1))
2387169689Skan		return simplify_gen_binary (AND, mode, op1, trueop0);
2388169689Skan	      return trueop0;
2389169689Skan	    }
2390169689Skan	  /* x/1 is x.  */
2391169689Skan	  if (trueop1 == CONST1_RTX (mode))
2392169689Skan	    return rtl_hooks.gen_lowpart_no_emit (mode, op0);
2393169689Skan	  /* x/-1 is -x.  */
2394169689Skan	  if (trueop1 == constm1_rtx)
2395169689Skan	    {
2396169689Skan	      rtx x = rtl_hooks.gen_lowpart_no_emit (mode, op0);
2397169689Skan	      return simplify_gen_unary (NEG, mode, x, mode);
2398169689Skan	    }
2399169689Skan	}
2400169689Skan      break;
2401132718Skan
2402169689Skan    case UMOD:
2403169689Skan      /* 0%x is 0 (or x&0 if x has side-effects).  */
2404169689Skan      if (trueop0 == CONST0_RTX (mode))
2405169689Skan	{
2406169689Skan	  if (side_effects_p (op1))
2407169689Skan	    return simplify_gen_binary (AND, mode, op1, trueop0);
2408169689Skan	  return trueop0;
2409169689Skan	}
2410169689Skan      /* x%1 is 0 (of x&0 if x has side-effects).  */
2411169689Skan      if (trueop1 == CONST1_RTX (mode))
2412169689Skan	{
2413169689Skan	  if (side_effects_p (op0))
2414169689Skan	    return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode));
2415169689Skan	  return CONST0_RTX (mode);
2416169689Skan	}
2417169689Skan      /* Implement modulus by power of two as AND.  */
2418169689Skan      if (GET_CODE (trueop1) == CONST_INT
2419169689Skan	  && exact_log2 (INTVAL (trueop1)) > 0)
2420169689Skan	return simplify_gen_binary (AND, mode, op0,
2421169689Skan				    GEN_INT (INTVAL (op1) - 1));
2422169689Skan      break;
242390075Sobrien
2424169689Skan    case MOD:
2425169689Skan      /* 0%x is 0 (or x&0 if x has side-effects).  */
2426169689Skan      if (trueop0 == CONST0_RTX (mode))
2427169689Skan	{
2428169689Skan	  if (side_effects_p (op1))
2429169689Skan	    return simplify_gen_binary (AND, mode, op1, trueop0);
2430169689Skan	  return trueop0;
2431169689Skan	}
2432169689Skan      /* x%1 and x%-1 is 0 (or x&0 if x has side-effects).  */
2433169689Skan      if (trueop1 == CONST1_RTX (mode) || trueop1 == constm1_rtx)
2434169689Skan	{
2435169689Skan	  if (side_effects_p (op0))
2436169689Skan	    return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode));
2437169689Skan	  return CONST0_RTX (mode);
2438169689Skan	}
2439169689Skan      break;
244090075Sobrien
2441169689Skan    case ROTATERT:
2442169689Skan    case ROTATE:
2443169689Skan    case ASHIFTRT:
2444169689Skan      if (trueop1 == CONST0_RTX (mode))
2445169689Skan	return op0;
2446169689Skan      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
2447169689Skan	return op0;
2448169689Skan      /* Rotating ~0 always results in ~0.  */
2449169689Skan      if (GET_CODE (trueop0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
2450169689Skan	  && (unsigned HOST_WIDE_INT) INTVAL (trueop0) == GET_MODE_MASK (mode)
2451169689Skan	  && ! side_effects_p (op1))
2452169689Skan	return op0;
2453169689Skan      break;
2454132718Skan
2455169689Skan    case ASHIFT:
2456169689Skan    case SS_ASHIFT:
2457169689Skan      if (trueop1 == CONST0_RTX (mode))
2458169689Skan	return op0;
2459169689Skan      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
2460169689Skan	return op0;
2461169689Skan      break;
246290075Sobrien
2463169689Skan    case LSHIFTRT:
2464169689Skan      if (trueop1 == CONST0_RTX (mode))
2465169689Skan	return op0;
2466169689Skan      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
2467169689Skan	return op0;
2468169689Skan      /* Optimize (lshiftrt (clz X) C) as (eq X 0).  */
2469169689Skan      if (GET_CODE (op0) == CLZ
2470169689Skan	  && GET_CODE (trueop1) == CONST_INT
2471169689Skan	  && STORE_FLAG_VALUE == 1
2472169689Skan	  && INTVAL (trueop1) < (HOST_WIDE_INT)width)
2473169689Skan	{
2474169689Skan	  enum machine_mode imode = GET_MODE (XEXP (op0, 0));
2475169689Skan	  unsigned HOST_WIDE_INT zero_val = 0;
2476132718Skan
2477169689Skan	  if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
2478169689Skan	      && zero_val == GET_MODE_BITSIZE (imode)
2479169689Skan	      && INTVAL (trueop1) == exact_log2 (zero_val))
2480169689Skan	    return simplify_gen_relational (EQ, mode, imode,
2481169689Skan					    XEXP (op0, 0), const0_rtx);
2482169689Skan	}
2483169689Skan      break;
2484117395Skan
2485169689Skan    case SMIN:
2486169689Skan      if (width <= HOST_BITS_PER_WIDE_INT
2487169689Skan	  && GET_CODE (trueop1) == CONST_INT
2488169689Skan	  && INTVAL (trueop1) == (HOST_WIDE_INT) 1 << (width -1)
2489169689Skan	  && ! side_effects_p (op0))
2490169689Skan	return op1;
2491169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2492169689Skan	return op0;
2493169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2494169689Skan      if (tem)
2495169689Skan	return tem;
2496169689Skan      break;
2497169689Skan
2498169689Skan    case SMAX:
2499169689Skan      if (width <= HOST_BITS_PER_WIDE_INT
2500169689Skan	  && GET_CODE (trueop1) == CONST_INT
2501169689Skan	  && ((unsigned HOST_WIDE_INT) INTVAL (trueop1)
2502169689Skan	      == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
2503169689Skan	  && ! side_effects_p (op0))
2504169689Skan	return op1;
2505169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2506169689Skan	return op0;
2507169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2508169689Skan      if (tem)
2509169689Skan	return tem;
2510169689Skan      break;
2511169689Skan
2512169689Skan    case UMIN:
2513169689Skan      if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
2514169689Skan	return op1;
2515169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2516169689Skan	return op0;
2517169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2518169689Skan      if (tem)
2519169689Skan	return tem;
2520169689Skan      break;
2521169689Skan
2522169689Skan    case UMAX:
2523169689Skan      if (trueop1 == constm1_rtx && ! side_effects_p (op0))
2524169689Skan	return op1;
2525169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2526169689Skan	return op0;
2527169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2528169689Skan      if (tem)
2529169689Skan	return tem;
2530169689Skan      break;
2531169689Skan
2532169689Skan    case SS_PLUS:
2533169689Skan    case US_PLUS:
2534169689Skan    case SS_MINUS:
2535169689Skan    case US_MINUS:
2536169689Skan      /* ??? There are simplifications that can be done.  */
2537169689Skan      return 0;
2538169689Skan
2539169689Skan    case VEC_SELECT:
2540169689Skan      if (!VECTOR_MODE_P (mode))
2541169689Skan	{
2542169689Skan	  gcc_assert (VECTOR_MODE_P (GET_MODE (trueop0)));
2543169689Skan	  gcc_assert (mode == GET_MODE_INNER (GET_MODE (trueop0)));
2544169689Skan	  gcc_assert (GET_CODE (trueop1) == PARALLEL);
2545169689Skan	  gcc_assert (XVECLEN (trueop1, 0) == 1);
2546169689Skan	  gcc_assert (GET_CODE (XVECEXP (trueop1, 0, 0)) == CONST_INT);
2547169689Skan
2548169689Skan	  if (GET_CODE (trueop0) == CONST_VECTOR)
2549169689Skan	    return CONST_VECTOR_ELT (trueop0, INTVAL (XVECEXP
2550169689Skan						      (trueop1, 0, 0)));
255190075Sobrien	}
2552169689Skan      else
2553169689Skan	{
2554169689Skan	  gcc_assert (VECTOR_MODE_P (GET_MODE (trueop0)));
2555169689Skan	  gcc_assert (GET_MODE_INNER (mode)
2556169689Skan		      == GET_MODE_INNER (GET_MODE (trueop0)));
2557169689Skan	  gcc_assert (GET_CODE (trueop1) == PARALLEL);
255890075Sobrien
2559169689Skan	  if (GET_CODE (trueop0) == CONST_VECTOR)
2560169689Skan	    {
2561169689Skan	      int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
2562169689Skan	      unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
2563169689Skan	      rtvec v = rtvec_alloc (n_elts);
2564169689Skan	      unsigned int i;
2565169689Skan
2566169689Skan	      gcc_assert (XVECLEN (trueop1, 0) == (int) n_elts);
2567169689Skan	      for (i = 0; i < n_elts; i++)
2568169689Skan		{
2569169689Skan		  rtx x = XVECEXP (trueop1, 0, i);
2570169689Skan
2571169689Skan		  gcc_assert (GET_CODE (x) == CONST_INT);
2572169689Skan		  RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop0,
2573169689Skan						       INTVAL (x));
2574169689Skan		}
2575169689Skan
2576169689Skan	      return gen_rtx_CONST_VECTOR (mode, v);
2577169689Skan	    }
2578169689Skan	}
2579169689Skan
2580169689Skan      if (XVECLEN (trueop1, 0) == 1
2581169689Skan	  && GET_CODE (XVECEXP (trueop1, 0, 0)) == CONST_INT
2582169689Skan	  && GET_CODE (trueop0) == VEC_CONCAT)
2583169689Skan	{
2584169689Skan	  rtx vec = trueop0;
2585169689Skan	  int offset = INTVAL (XVECEXP (trueop1, 0, 0)) * GET_MODE_SIZE (mode);
2586169689Skan
2587169689Skan	  /* Try to find the element in the VEC_CONCAT.  */
2588169689Skan	  while (GET_MODE (vec) != mode
2589169689Skan		 && GET_CODE (vec) == VEC_CONCAT)
2590169689Skan	    {
2591169689Skan	      HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
2592169689Skan	      if (offset < vec_size)
2593169689Skan		vec = XEXP (vec, 0);
2594169689Skan	      else
2595169689Skan		{
2596169689Skan		  offset -= vec_size;
2597169689Skan		  vec = XEXP (vec, 1);
2598169689Skan		}
2599169689Skan	      vec = avoid_constant_pool_reference (vec);
2600169689Skan	    }
2601169689Skan
2602169689Skan	  if (GET_MODE (vec) == mode)
2603169689Skan	    return vec;
2604169689Skan	}
2605169689Skan
260690075Sobrien      return 0;
2607169689Skan    case VEC_CONCAT:
2608169689Skan      {
2609169689Skan	enum machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
2610169689Skan				      ? GET_MODE (trueop0)
2611169689Skan				      : GET_MODE_INNER (mode));
2612169689Skan	enum machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
2613169689Skan				      ? GET_MODE (trueop1)
2614169689Skan				      : GET_MODE_INNER (mode));
2615132718Skan
2616169689Skan	gcc_assert (VECTOR_MODE_P (mode));
2617169689Skan	gcc_assert (GET_MODE_SIZE (op0_mode) + GET_MODE_SIZE (op1_mode)
2618169689Skan		    == GET_MODE_SIZE (mode));
2619132718Skan
2620169689Skan	if (VECTOR_MODE_P (op0_mode))
2621169689Skan	  gcc_assert (GET_MODE_INNER (mode)
2622169689Skan		      == GET_MODE_INNER (op0_mode));
2623169689Skan	else
2624169689Skan	  gcc_assert (GET_MODE_INNER (mode) == op0_mode);
2625132718Skan
2626169689Skan	if (VECTOR_MODE_P (op1_mode))
2627169689Skan	  gcc_assert (GET_MODE_INNER (mode)
2628169689Skan		      == GET_MODE_INNER (op1_mode));
2629169689Skan	else
2630169689Skan	  gcc_assert (GET_MODE_INNER (mode) == op1_mode);
2631132718Skan
2632169689Skan	if ((GET_CODE (trueop0) == CONST_VECTOR
2633169689Skan	     || GET_CODE (trueop0) == CONST_INT
2634169689Skan	     || GET_CODE (trueop0) == CONST_DOUBLE)
2635169689Skan	    && (GET_CODE (trueop1) == CONST_VECTOR
2636169689Skan		|| GET_CODE (trueop1) == CONST_INT
2637169689Skan		|| GET_CODE (trueop1) == CONST_DOUBLE))
2638169689Skan	  {
2639169689Skan	    int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
2640169689Skan	    unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
2641169689Skan	    rtvec v = rtvec_alloc (n_elts);
2642169689Skan	    unsigned int i;
2643169689Skan	    unsigned in_n_elts = 1;
2644132718Skan
2645169689Skan	    if (VECTOR_MODE_P (op0_mode))
2646169689Skan	      in_n_elts = (GET_MODE_SIZE (op0_mode) / elt_size);
2647169689Skan	    for (i = 0; i < n_elts; i++)
2648169689Skan	      {
2649169689Skan		if (i < in_n_elts)
2650169689Skan		  {
2651169689Skan		    if (!VECTOR_MODE_P (op0_mode))
2652169689Skan		      RTVEC_ELT (v, i) = trueop0;
2653169689Skan		    else
2654169689Skan		      RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop0, i);
2655169689Skan		  }
2656169689Skan		else
2657169689Skan		  {
2658169689Skan		    if (!VECTOR_MODE_P (op1_mode))
2659169689Skan		      RTVEC_ELT (v, i) = trueop1;
2660169689Skan		    else
2661169689Skan		      RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop1,
2662169689Skan							   i - in_n_elts);
2663169689Skan		  }
2664169689Skan	      }
2665169689Skan
2666169689Skan	    return gen_rtx_CONST_VECTOR (mode, v);
2667169689Skan	  }
2668169689Skan      }
2669169689Skan      return 0;
2670169689Skan
2671169689Skan    default:
2672169689Skan      gcc_unreachable ();
2673132718Skan    }
2674132718Skan
2675132718Skan  return 0;
2676132718Skan}
2677132718Skan
267890075Sobrienrtx
2679169689Skansimplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
2680169689Skan				 rtx op0, rtx op1)
268190075Sobrien{
268290075Sobrien  HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
268390075Sobrien  HOST_WIDE_INT val;
268490075Sobrien  unsigned int width = GET_MODE_BITSIZE (mode);
268590075Sobrien
2686132718Skan  if (VECTOR_MODE_P (mode)
2687146895Skan      && code != VEC_CONCAT
2688169689Skan      && GET_CODE (op0) == CONST_VECTOR
2689169689Skan      && GET_CODE (op1) == CONST_VECTOR)
2690132718Skan    {
2691169689Skan      unsigned n_elts = GET_MODE_NUNITS (mode);
2692169689Skan      enum machine_mode op0mode = GET_MODE (op0);
2693169689Skan      unsigned op0_n_elts = GET_MODE_NUNITS (op0mode);
2694169689Skan      enum machine_mode op1mode = GET_MODE (op1);
2695169689Skan      unsigned op1_n_elts = GET_MODE_NUNITS (op1mode);
2696132718Skan      rtvec v = rtvec_alloc (n_elts);
2697132718Skan      unsigned int i;
2698132718Skan
2699169689Skan      gcc_assert (op0_n_elts == n_elts);
2700169689Skan      gcc_assert (op1_n_elts == n_elts);
2701132718Skan      for (i = 0; i < n_elts; i++)
2702132718Skan	{
2703132718Skan	  rtx x = simplify_binary_operation (code, GET_MODE_INNER (mode),
2704169689Skan					     CONST_VECTOR_ELT (op0, i),
2705169689Skan					     CONST_VECTOR_ELT (op1, i));
2706132718Skan	  if (!x)
2707132718Skan	    return 0;
2708132718Skan	  RTVEC_ELT (v, i) = x;
2709132718Skan	}
2710132718Skan
2711132718Skan      return gen_rtx_CONST_VECTOR (mode, v);
2712132718Skan    }
2713132718Skan
2714169689Skan  if (VECTOR_MODE_P (mode)
2715169689Skan      && code == VEC_CONCAT
2716169689Skan      && CONSTANT_P (op0) && CONSTANT_P (op1))
2717169689Skan    {
2718169689Skan      unsigned n_elts = GET_MODE_NUNITS (mode);
2719169689Skan      rtvec v = rtvec_alloc (n_elts);
2720169689Skan
2721169689Skan      gcc_assert (n_elts >= 2);
2722169689Skan      if (n_elts == 2)
2723169689Skan	{
2724169689Skan	  gcc_assert (GET_CODE (op0) != CONST_VECTOR);
2725169689Skan	  gcc_assert (GET_CODE (op1) != CONST_VECTOR);
2726169689Skan
2727169689Skan	  RTVEC_ELT (v, 0) = op0;
2728169689Skan	  RTVEC_ELT (v, 1) = op1;
2729169689Skan	}
2730169689Skan      else
2731169689Skan	{
2732169689Skan	  unsigned op0_n_elts = GET_MODE_NUNITS (GET_MODE (op0));
2733169689Skan	  unsigned op1_n_elts = GET_MODE_NUNITS (GET_MODE (op1));
2734169689Skan	  unsigned i;
2735169689Skan
2736169689Skan	  gcc_assert (GET_CODE (op0) == CONST_VECTOR);
2737169689Skan	  gcc_assert (GET_CODE (op1) == CONST_VECTOR);
2738169689Skan	  gcc_assert (op0_n_elts + op1_n_elts == n_elts);
2739169689Skan
2740169689Skan	  for (i = 0; i < op0_n_elts; ++i)
2741169689Skan	    RTVEC_ELT (v, i) = XVECEXP (op0, 0, i);
2742169689Skan	  for (i = 0; i < op1_n_elts; ++i)
2743169689Skan	    RTVEC_ELT (v, op0_n_elts+i) = XVECEXP (op1, 0, i);
2744169689Skan	}
2745169689Skan
2746169689Skan      return gen_rtx_CONST_VECTOR (mode, v);
2747169689Skan    }
2748169689Skan
2749169689Skan  if (SCALAR_FLOAT_MODE_P (mode)
2750169689Skan      && GET_CODE (op0) == CONST_DOUBLE
2751169689Skan      && GET_CODE (op1) == CONST_DOUBLE
275290075Sobrien      && mode == GET_MODE (op0) && mode == GET_MODE (op1))
275390075Sobrien    {
2754146895Skan      if (code == AND
2755146895Skan	  || code == IOR
2756146895Skan	  || code == XOR)
2757146895Skan	{
2758146895Skan	  long tmp0[4];
2759146895Skan	  long tmp1[4];
2760146895Skan	  REAL_VALUE_TYPE r;
2761146895Skan	  int i;
276290075Sobrien
2763146895Skan	  real_to_target (tmp0, CONST_DOUBLE_REAL_VALUE (op0),
2764146895Skan			  GET_MODE (op0));
2765146895Skan	  real_to_target (tmp1, CONST_DOUBLE_REAL_VALUE (op1),
2766146895Skan			  GET_MODE (op1));
2767146895Skan	  for (i = 0; i < 4; i++)
2768146895Skan	    {
2769169689Skan	      switch (code)
2770169689Skan	      {
2771169689Skan	      case AND:
2772146895Skan		tmp0[i] &= tmp1[i];
2773169689Skan		break;
2774169689Skan	      case IOR:
2775146895Skan		tmp0[i] |= tmp1[i];
2776169689Skan		break;
2777169689Skan	      case XOR:
2778146895Skan		tmp0[i] ^= tmp1[i];
2779169689Skan		break;
2780169689Skan	      default:
2781169689Skan		gcc_unreachable ();
2782169689Skan	      }
2783146895Skan	    }
2784146895Skan	   real_from_target (&r, tmp0, mode);
2785146895Skan	   return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
2786146895Skan	}
2787146895Skan      else
2788146895Skan	{
2789169689Skan	  REAL_VALUE_TYPE f0, f1, value, result;
2790169689Skan	  bool inexact;
2791117395Skan
2792169689Skan	  REAL_VALUE_FROM_CONST_DOUBLE (f0, op0);
2793169689Skan	  REAL_VALUE_FROM_CONST_DOUBLE (f1, op1);
2794169689Skan	  real_convert (&f0, mode, &f0);
2795169689Skan	  real_convert (&f1, mode, &f1);
2796132718Skan
2797146895Skan	  if (HONOR_SNANS (mode)
2798146895Skan	      && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
2799146895Skan	    return 0;
2800117395Skan
2801146895Skan	  if (code == DIV
2802146895Skan	      && REAL_VALUES_EQUAL (f1, dconst0)
2803146895Skan	      && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
2804146895Skan	    return 0;
2805132718Skan
2806146895Skan	  if (MODE_HAS_INFINITIES (mode) && HONOR_NANS (mode)
2807146895Skan	      && flag_trapping_math
2808146895Skan	      && REAL_VALUE_ISINF (f0) && REAL_VALUE_ISINF (f1))
2809132718Skan	    {
2810146895Skan	      int s0 = REAL_VALUE_NEGATIVE (f0);
2811146895Skan	      int s1 = REAL_VALUE_NEGATIVE (f1);
2812146895Skan
2813146895Skan	      switch (code)
2814146895Skan		{
2815146895Skan		case PLUS:
2816146895Skan		  /* Inf + -Inf = NaN plus exception.  */
2817146895Skan		  if (s0 != s1)
2818146895Skan		    return 0;
2819146895Skan		  break;
2820146895Skan		case MINUS:
2821146895Skan		  /* Inf - Inf = NaN plus exception.  */
2822146895Skan		  if (s0 == s1)
2823146895Skan		    return 0;
2824146895Skan		  break;
2825146895Skan		case DIV:
2826146895Skan		  /* Inf / Inf = NaN plus exception.  */
2827146895Skan		  return 0;
2828146895Skan		default:
2829146895Skan		  break;
2830146895Skan		}
2831132718Skan	    }
2832132718Skan
2833146895Skan	  if (code == MULT && MODE_HAS_INFINITIES (mode) && HONOR_NANS (mode)
2834146895Skan	      && flag_trapping_math
2835146895Skan	      && ((REAL_VALUE_ISINF (f0) && REAL_VALUES_EQUAL (f1, dconst0))
2836146895Skan		  || (REAL_VALUE_ISINF (f1)
2837146895Skan		      && REAL_VALUES_EQUAL (f0, dconst0))))
2838146895Skan	    /* Inf * 0 = NaN plus exception.  */
2839146895Skan	    return 0;
2840132718Skan
2841169689Skan	  inexact = real_arithmetic (&value, rtx_to_tree_code (code),
2842169689Skan				     &f0, &f1);
2843169689Skan	  real_convert (&result, mode, &value);
2844117395Skan
2845169689Skan	  /* Don't constant fold this floating point operation if
2846169689Skan	     the result has overflowed and flag_trapping_math.  */
2847169689Skan
2848169689Skan	  if (flag_trapping_math
2849169689Skan	      && MODE_HAS_INFINITIES (mode)
2850169689Skan	      && REAL_VALUE_ISINF (result)
2851169689Skan	      && !REAL_VALUE_ISINF (f0)
2852169689Skan	      && !REAL_VALUE_ISINF (f1))
2853169689Skan	    /* Overflow plus exception.  */
2854169689Skan	    return 0;
2855169689Skan
2856169689Skan	  /* Don't constant fold this floating point operation if the
2857169689Skan	     result may dependent upon the run-time rounding mode and
2858169689Skan	     flag_rounding_math is set, or if GCC's software emulation
2859169689Skan	     is unable to accurately represent the result.  */
2860169689Skan
2861169689Skan	  if ((flag_rounding_math
2862169689Skan	       || (REAL_MODE_FORMAT_COMPOSITE_P (mode)
2863169689Skan		   && !flag_unsafe_math_optimizations))
2864169689Skan	      && (inexact || !real_identical (&result, &value)))
2865169689Skan	    return NULL_RTX;
2866169689Skan
2867169689Skan	  return CONST_DOUBLE_FROM_REAL_VALUE (result, mode);
2868146895Skan	}
286990075Sobrien    }
287090075Sobrien
287190075Sobrien  /* We can fold some multi-word operations.  */
287290075Sobrien  if (GET_MODE_CLASS (mode) == MODE_INT
287390075Sobrien      && width == HOST_BITS_PER_WIDE_INT * 2
2874169689Skan      && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
2875169689Skan      && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
287690075Sobrien    {
2877169689Skan      unsigned HOST_WIDE_INT l1, l2, lv, lt;
2878169689Skan      HOST_WIDE_INT h1, h2, hv, ht;
287990075Sobrien
2880169689Skan      if (GET_CODE (op0) == CONST_DOUBLE)
2881169689Skan	l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
288290075Sobrien      else
2883169689Skan	l1 = INTVAL (op0), h1 = HWI_SIGN_EXTEND (l1);
288490075Sobrien
2885169689Skan      if (GET_CODE (op1) == CONST_DOUBLE)
2886169689Skan	l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1);
288790075Sobrien      else
2888169689Skan	l2 = INTVAL (op1), h2 = HWI_SIGN_EXTEND (l2);
288990075Sobrien
289090075Sobrien      switch (code)
289190075Sobrien	{
289290075Sobrien	case MINUS:
289390075Sobrien	  /* A - B == A + (-B).  */
289490075Sobrien	  neg_double (l2, h2, &lv, &hv);
289590075Sobrien	  l2 = lv, h2 = hv;
289690075Sobrien
2897132718Skan	  /* Fall through....  */
289890075Sobrien
289990075Sobrien	case PLUS:
290090075Sobrien	  add_double (l1, h1, l2, h2, &lv, &hv);
290190075Sobrien	  break;
290290075Sobrien
290390075Sobrien	case MULT:
290490075Sobrien	  mul_double (l1, h1, l2, h2, &lv, &hv);
290590075Sobrien	  break;
290690075Sobrien
2907169689Skan	case DIV:
2908169689Skan	  if (div_and_round_double (TRUNC_DIV_EXPR, 0, l1, h1, l2, h2,
2909169689Skan				    &lv, &hv, &lt, &ht))
2910169689Skan	    return 0;
2911169689Skan	  break;
291290075Sobrien
2913169689Skan	case MOD:
2914169689Skan	  if (div_and_round_double (TRUNC_DIV_EXPR, 0, l1, h1, l2, h2,
2915169689Skan				    &lt, &ht, &lv, &hv))
2916169689Skan	    return 0;
2917169689Skan	  break;
2918169689Skan
2919169689Skan	case UDIV:
2920169689Skan	  if (div_and_round_double (TRUNC_DIV_EXPR, 1, l1, h1, l2, h2,
2921169689Skan				    &lv, &hv, &lt, &ht))
2922169689Skan	    return 0;
2923169689Skan	  break;
2924169689Skan
2925169689Skan	case UMOD:
2926169689Skan	  if (div_and_round_double (TRUNC_DIV_EXPR, 1, l1, h1, l2, h2,
2927169689Skan				    &lt, &ht, &lv, &hv))
2928169689Skan	    return 0;
2929169689Skan	  break;
2930169689Skan
293190075Sobrien	case AND:
293290075Sobrien	  lv = l1 & l2, hv = h1 & h2;
293390075Sobrien	  break;
293490075Sobrien
293590075Sobrien	case IOR:
293690075Sobrien	  lv = l1 | l2, hv = h1 | h2;
293790075Sobrien	  break;
293890075Sobrien
293990075Sobrien	case XOR:
294090075Sobrien	  lv = l1 ^ l2, hv = h1 ^ h2;
294190075Sobrien	  break;
294290075Sobrien
294390075Sobrien	case SMIN:
294490075Sobrien	  if (h1 < h2
294590075Sobrien	      || (h1 == h2
294690075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
294790075Sobrien		      < (unsigned HOST_WIDE_INT) l2)))
294890075Sobrien	    lv = l1, hv = h1;
294990075Sobrien	  else
295090075Sobrien	    lv = l2, hv = h2;
295190075Sobrien	  break;
295290075Sobrien
295390075Sobrien	case SMAX:
295490075Sobrien	  if (h1 > h2
295590075Sobrien	      || (h1 == h2
295690075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
295790075Sobrien		      > (unsigned HOST_WIDE_INT) l2)))
295890075Sobrien	    lv = l1, hv = h1;
295990075Sobrien	  else
296090075Sobrien	    lv = l2, hv = h2;
296190075Sobrien	  break;
296290075Sobrien
296390075Sobrien	case UMIN:
296490075Sobrien	  if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2
296590075Sobrien	      || (h1 == h2
296690075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
296790075Sobrien		      < (unsigned HOST_WIDE_INT) l2)))
296890075Sobrien	    lv = l1, hv = h1;
296990075Sobrien	  else
297090075Sobrien	    lv = l2, hv = h2;
297190075Sobrien	  break;
297290075Sobrien
297390075Sobrien	case UMAX:
297490075Sobrien	  if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2
297590075Sobrien	      || (h1 == h2
297690075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
297790075Sobrien		      > (unsigned HOST_WIDE_INT) l2)))
297890075Sobrien	    lv = l1, hv = h1;
297990075Sobrien	  else
298090075Sobrien	    lv = l2, hv = h2;
298190075Sobrien	  break;
298290075Sobrien
298390075Sobrien	case LSHIFTRT:   case ASHIFTRT:
298490075Sobrien	case ASHIFT:
298590075Sobrien	case ROTATE:     case ROTATERT:
298690075Sobrien	  if (SHIFT_COUNT_TRUNCATED)
298790075Sobrien	    l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
298890075Sobrien
298990075Sobrien	  if (h2 != 0 || l2 >= GET_MODE_BITSIZE (mode))
299090075Sobrien	    return 0;
299190075Sobrien
299290075Sobrien	  if (code == LSHIFTRT || code == ASHIFTRT)
299390075Sobrien	    rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
299490075Sobrien			   code == ASHIFTRT);
299590075Sobrien	  else if (code == ASHIFT)
299690075Sobrien	    lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
299790075Sobrien	  else if (code == ROTATE)
299890075Sobrien	    lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
299990075Sobrien	  else /* code == ROTATERT */
300090075Sobrien	    rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
300190075Sobrien	  break;
300290075Sobrien
300390075Sobrien	default:
300490075Sobrien	  return 0;
300590075Sobrien	}
300690075Sobrien
300790075Sobrien      return immed_double_const (lv, hv, mode);
300890075Sobrien    }
300990075Sobrien
3010169689Skan  if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
3011169689Skan      && width <= HOST_BITS_PER_WIDE_INT && width != 0)
301290075Sobrien    {
3013169689Skan      /* Get the integer argument values in two forms:
3014169689Skan         zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
301590075Sobrien
3016169689Skan      arg0 = INTVAL (op0);
3017169689Skan      arg1 = INTVAL (op1);
3018169689Skan
3019169689Skan      if (width < HOST_BITS_PER_WIDE_INT)
3020169689Skan        {
3021169689Skan          arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
3022169689Skan          arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
3023169689Skan
3024169689Skan          arg0s = arg0;
3025169689Skan          if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
3026169689Skan	    arg0s |= ((HOST_WIDE_INT) (-1) << width);
3027169689Skan
3028169689Skan	  arg1s = arg1;
3029169689Skan	  if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
3030169689Skan	    arg1s |= ((HOST_WIDE_INT) (-1) << width);
3031169689Skan	}
3032169689Skan      else
3033169689Skan	{
3034169689Skan	  arg0s = arg0;
3035169689Skan	  arg1s = arg1;
3036169689Skan	}
3037169689Skan
3038169689Skan      /* Compute the value of the arithmetic.  */
3039169689Skan
304090075Sobrien      switch (code)
304190075Sobrien	{
304290075Sobrien	case PLUS:
3043169689Skan	  val = arg0s + arg1s;
304490075Sobrien	  break;
3045169689Skan
304690075Sobrien	case MINUS:
3047169689Skan	  val = arg0s - arg1s;
304890075Sobrien	  break;
3049169689Skan
305090075Sobrien	case MULT:
3051169689Skan	  val = arg0s * arg1s;
305290075Sobrien	  break;
3053169689Skan
3054169689Skan	case DIV:
3055169689Skan	  if (arg1s == 0
3056169689Skan	      || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3057169689Skan		  && arg1s == -1))
3058169689Skan	    return 0;
3059169689Skan	  val = arg0s / arg1s;
306090075Sobrien	  break;
3061169689Skan
3062169689Skan	case MOD:
3063169689Skan	  if (arg1s == 0
3064169689Skan	      || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3065169689Skan		  && arg1s == -1))
3066169689Skan	    return 0;
3067169689Skan	  val = arg0s % arg1s;
306890075Sobrien	  break;
3069169689Skan
307090075Sobrien	case UDIV:
3071169689Skan	  if (arg1 == 0
3072169689Skan	      || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3073169689Skan		  && arg1s == -1))
3074169689Skan	    return 0;
3075169689Skan	  val = (unsigned HOST_WIDE_INT) arg0 / arg1;
307690075Sobrien	  break;
3077169689Skan
307890075Sobrien	case UMOD:
3079169689Skan	  if (arg1 == 0
3080169689Skan	      || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3081169689Skan		  && arg1s == -1))
3082169689Skan	    return 0;
3083169689Skan	  val = (unsigned HOST_WIDE_INT) arg0 % arg1;
308490075Sobrien	  break;
3085169689Skan
3086169689Skan	case AND:
3087169689Skan	  val = arg0 & arg1;
3088169689Skan	  break;
3089169689Skan
3090169689Skan	case IOR:
3091169689Skan	  val = arg0 | arg1;
3092169689Skan	  break;
3093169689Skan
3094169689Skan	case XOR:
3095169689Skan	  val = arg0 ^ arg1;
3096169689Skan	  break;
3097169689Skan
3098169689Skan	case LSHIFTRT:
3099169689Skan	case ASHIFT:
3100169689Skan	case ASHIFTRT:
3101169689Skan	  /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
3102169689Skan	     the value is in range.  We can't return any old value for
3103169689Skan	     out-of-range arguments because either the middle-end (via
3104169689Skan	     shift_truncation_mask) or the back-end might be relying on
3105169689Skan	     target-specific knowledge.  Nor can we rely on
3106169689Skan	     shift_truncation_mask, since the shift might not be part of an
3107169689Skan	     ashlM3, lshrM3 or ashrM3 instruction.  */
3108169689Skan	  if (SHIFT_COUNT_TRUNCATED)
3109169689Skan	    arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
3110169689Skan	  else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
3111169689Skan	    return 0;
3112169689Skan
3113169689Skan	  val = (code == ASHIFT
3114169689Skan		 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
3115169689Skan		 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
3116169689Skan
3117169689Skan	  /* Sign-extend the result for arithmetic right shifts.  */
3118169689Skan	  if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
3119169689Skan	    val |= ((HOST_WIDE_INT) -1) << (width - arg1);
3120169689Skan	  break;
3121169689Skan
312290075Sobrien	case ROTATERT:
3123169689Skan	  if (arg1 < 0)
3124169689Skan	    return 0;
3125169689Skan
3126169689Skan	  arg1 %= width;
3127169689Skan	  val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
3128169689Skan		 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
3129169689Skan	  break;
3130169689Skan
313190075Sobrien	case ROTATE:
3132169689Skan	  if (arg1 < 0)
3133169689Skan	    return 0;
3134169689Skan
3135169689Skan	  arg1 %= width;
3136169689Skan	  val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
3137169689Skan		 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
313890075Sobrien	  break;
3139169689Skan
3140169689Skan	case COMPARE:
3141169689Skan	  /* Do nothing here.  */
3142169689Skan	  return 0;
3143169689Skan
314490075Sobrien	case SMIN:
3145169689Skan	  val = arg0s <= arg1s ? arg0s : arg1s;
314690075Sobrien	  break;
3147169689Skan
3148169689Skan	case UMIN:
3149169689Skan	  val = ((unsigned HOST_WIDE_INT) arg0
3150169689Skan		 <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
3151169689Skan	  break;
3152169689Skan
315390075Sobrien	case SMAX:
3154169689Skan	  val = arg0s > arg1s ? arg0s : arg1s;
315590075Sobrien	  break;
3156169689Skan
315790075Sobrien	case UMAX:
3158169689Skan	  val = ((unsigned HOST_WIDE_INT) arg0
3159169689Skan		 > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
316090075Sobrien	  break;
3161169689Skan
316290075Sobrien	case SS_PLUS:
316390075Sobrien	case US_PLUS:
316490075Sobrien	case SS_MINUS:
316590075Sobrien	case US_MINUS:
3166169689Skan	case SS_ASHIFT:
316790075Sobrien	  /* ??? There are simplifications that can be done.  */
316890075Sobrien	  return 0;
3169169689Skan
317090075Sobrien	default:
3171169689Skan	  gcc_unreachable ();
317290075Sobrien	}
3173117395Skan
3174169689Skan      return gen_int_mode (val, mode);
317590075Sobrien    }
317690075Sobrien
3177169689Skan  return NULL_RTX;
3178169689Skan}
317990075Sobrien
318090075Sobrien
318190075Sobrien
318290075Sobrien/* Simplify a PLUS or MINUS, at least one of whose operands may be another
318390075Sobrien   PLUS or MINUS.
318490075Sobrien
318590075Sobrien   Rather than test for specific case, we do this by a brute-force method
318690075Sobrien   and do all possible simplifications until no more changes occur.  Then
3187169689Skan   we rebuild the operation.  */
318890075Sobrien
318990075Sobrienstruct simplify_plus_minus_op_data
319090075Sobrien{
319190075Sobrien  rtx op;
3192169689Skan  short neg;
319390075Sobrien};
319490075Sobrien
319590075Sobrienstatic int
3196132718Skansimplify_plus_minus_op_data_cmp (const void *p1, const void *p2)
319790075Sobrien{
319890075Sobrien  const struct simplify_plus_minus_op_data *d1 = p1;
319990075Sobrien  const struct simplify_plus_minus_op_data *d2 = p2;
3200169689Skan  int result;
320190075Sobrien
3202169689Skan  result = (commutative_operand_precedence (d2->op)
3203169689Skan	    - commutative_operand_precedence (d1->op));
3204169689Skan  if (result)
3205169689Skan    return result;
3206169689Skan
3207169689Skan  /* Group together equal REGs to do more simplification.  */
3208169689Skan  if (REG_P (d1->op) && REG_P (d2->op))
3209169689Skan    return REGNO (d1->op) - REGNO (d2->op);
3210169689Skan  else
3211169689Skan    return 0;
321290075Sobrien}
321390075Sobrien
321490075Sobrienstatic rtx
3215132718Skansimplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
3216169689Skan		     rtx op1)
321790075Sobrien{
321890075Sobrien  struct simplify_plus_minus_op_data ops[8];
321990075Sobrien  rtx result, tem;
3220169689Skan  int n_ops = 2, input_ops = 2;
3221169689Skan  int changed, n_constants = 0, canonicalized = 0;
322290075Sobrien  int i, j;
322390075Sobrien
3224132718Skan  memset (ops, 0, sizeof ops);
3225117395Skan
322690075Sobrien  /* Set up the two operands and then expand them until nothing has been
322790075Sobrien     changed.  If we run out of room in our array, give up; this should
322890075Sobrien     almost never happen.  */
322990075Sobrien
323090075Sobrien  ops[0].op = op0;
323190075Sobrien  ops[0].neg = 0;
323290075Sobrien  ops[1].op = op1;
323390075Sobrien  ops[1].neg = (code == MINUS);
323490075Sobrien
323590075Sobrien  do
323690075Sobrien    {
323790075Sobrien      changed = 0;
323890075Sobrien
323990075Sobrien      for (i = 0; i < n_ops; i++)
324090075Sobrien	{
324190075Sobrien	  rtx this_op = ops[i].op;
324290075Sobrien	  int this_neg = ops[i].neg;
324390075Sobrien	  enum rtx_code this_code = GET_CODE (this_op);
324490075Sobrien
324590075Sobrien	  switch (this_code)
324690075Sobrien	    {
324790075Sobrien	    case PLUS:
324890075Sobrien	    case MINUS:
324990075Sobrien	      if (n_ops == 7)
325096263Sobrien		return NULL_RTX;
325190075Sobrien
325290075Sobrien	      ops[n_ops].op = XEXP (this_op, 1);
325390075Sobrien	      ops[n_ops].neg = (this_code == MINUS) ^ this_neg;
325490075Sobrien	      n_ops++;
325590075Sobrien
325690075Sobrien	      ops[i].op = XEXP (this_op, 0);
325790075Sobrien	      input_ops++;
325890075Sobrien	      changed = 1;
3259169689Skan	      canonicalized |= this_neg;
326090075Sobrien	      break;
326190075Sobrien
326290075Sobrien	    case NEG:
326390075Sobrien	      ops[i].op = XEXP (this_op, 0);
326490075Sobrien	      ops[i].neg = ! this_neg;
326590075Sobrien	      changed = 1;
3266169689Skan	      canonicalized = 1;
326790075Sobrien	      break;
326890075Sobrien
326990075Sobrien	    case CONST:
327096263Sobrien	      if (n_ops < 7
327196263Sobrien		  && GET_CODE (XEXP (this_op, 0)) == PLUS
327296263Sobrien		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 0))
327396263Sobrien		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 1)))
327496263Sobrien		{
327596263Sobrien		  ops[i].op = XEXP (XEXP (this_op, 0), 0);
327696263Sobrien		  ops[n_ops].op = XEXP (XEXP (this_op, 0), 1);
327796263Sobrien		  ops[n_ops].neg = this_neg;
327896263Sobrien		  n_ops++;
327996263Sobrien		  changed = 1;
3280169689Skan	          canonicalized = 1;
328196263Sobrien		}
328290075Sobrien	      break;
328390075Sobrien
328490075Sobrien	    case NOT:
328590075Sobrien	      /* ~a -> (-a - 1) */
328690075Sobrien	      if (n_ops != 7)
328790075Sobrien		{
328890075Sobrien		  ops[n_ops].op = constm1_rtx;
328990075Sobrien		  ops[n_ops++].neg = this_neg;
329090075Sobrien		  ops[i].op = XEXP (this_op, 0);
329190075Sobrien		  ops[i].neg = !this_neg;
329290075Sobrien		  changed = 1;
3293169689Skan	          canonicalized = 1;
329490075Sobrien		}
329590075Sobrien	      break;
329690075Sobrien
329790075Sobrien	    case CONST_INT:
3298169689Skan	      n_constants++;
329990075Sobrien	      if (this_neg)
330090075Sobrien		{
330190075Sobrien		  ops[i].op = neg_const_int (mode, this_op);
330290075Sobrien		  ops[i].neg = 0;
330390075Sobrien		  changed = 1;
3304169689Skan	          canonicalized = 1;
330590075Sobrien		}
330690075Sobrien	      break;
330790075Sobrien
330890075Sobrien	    default:
330990075Sobrien	      break;
331090075Sobrien	    }
331190075Sobrien	}
331290075Sobrien    }
331390075Sobrien  while (changed);
331490075Sobrien
3315169689Skan  if (n_constants > 1)
3316169689Skan    canonicalized = 1;
331790075Sobrien
3318169689Skan  gcc_assert (n_ops >= 2);
331996263Sobrien
3320169689Skan  /* If we only have two operands, we can avoid the loops.  */
3321169689Skan  if (n_ops == 2)
3322169689Skan    {
3323169689Skan      enum rtx_code code = ops[0].neg || ops[1].neg ? MINUS : PLUS;
3324169689Skan      rtx lhs, rhs;
332590075Sobrien
3326169689Skan      /* Get the two operands.  Be careful with the order, especially for
3327169689Skan	 the cases where code == MINUS.  */
3328169689Skan      if (ops[0].neg && ops[1].neg)
3329169689Skan	{
3330169689Skan	  lhs = gen_rtx_NEG (mode, ops[0].op);
3331169689Skan	  rhs = ops[1].op;
3332169689Skan	}
3333169689Skan      else if (ops[0].neg)
3334169689Skan	{
3335169689Skan	  lhs = ops[1].op;
3336169689Skan	  rhs = ops[0].op;
3337169689Skan	}
3338169689Skan      else
3339169689Skan	{
3340169689Skan	  lhs = ops[0].op;
3341169689Skan	  rhs = ops[1].op;
3342169689Skan	}
3343169689Skan
3344169689Skan      return simplify_const_binary_operation (code, mode, lhs, rhs);
3345169689Skan    }
3346169689Skan
3347169689Skan  /* Now simplify each pair of operands until nothing changes.  */
334890075Sobrien  do
334990075Sobrien    {
3350169689Skan      /* Insertion sort is good enough for an eight-element array.  */
3351169689Skan      for (i = 1; i < n_ops; i++)
3352169689Skan        {
3353169689Skan          struct simplify_plus_minus_op_data save;
3354169689Skan          j = i - 1;
3355169689Skan          if (simplify_plus_minus_op_data_cmp (&ops[j], &ops[i]) < 0)
3356169689Skan	    continue;
335790075Sobrien
3358169689Skan          canonicalized = 1;
3359169689Skan          save = ops[i];
3360169689Skan          do
3361169689Skan	    ops[j + 1] = ops[j];
3362169689Skan          while (j-- && simplify_plus_minus_op_data_cmp (&ops[j], &save) > 0);
3363169689Skan          ops[j + 1] = save;
3364169689Skan        }
3365169689Skan
3366169689Skan      /* This is only useful the first time through.  */
3367169689Skan      if (!canonicalized)
3368169689Skan        return NULL_RTX;
3369169689Skan
3370169689Skan      changed = 0;
3371169689Skan      for (i = n_ops - 1; i > 0; i--)
3372169689Skan	for (j = i - 1; j >= 0; j--)
337390075Sobrien	  {
3374169689Skan	    rtx lhs = ops[j].op, rhs = ops[i].op;
3375169689Skan	    int lneg = ops[j].neg, rneg = ops[i].neg;
337690075Sobrien
3377169689Skan	    if (lhs != 0 && rhs != 0)
337890075Sobrien	      {
337990075Sobrien		enum rtx_code ncode = PLUS;
338090075Sobrien
338190075Sobrien		if (lneg != rneg)
338290075Sobrien		  {
338390075Sobrien		    ncode = MINUS;
338490075Sobrien		    if (lneg)
338590075Sobrien		      tem = lhs, lhs = rhs, rhs = tem;
338690075Sobrien		  }
338790075Sobrien		else if (swap_commutative_operands_p (lhs, rhs))
338890075Sobrien		  tem = lhs, lhs = rhs, rhs = tem;
338990075Sobrien
3390169689Skan		if ((GET_CODE (lhs) == CONST || GET_CODE (lhs) == CONST_INT)
3391169689Skan		    && (GET_CODE (rhs) == CONST || GET_CODE (rhs) == CONST_INT))
3392169689Skan		  {
3393169689Skan		    rtx tem_lhs, tem_rhs;
339490075Sobrien
3395169689Skan		    tem_lhs = GET_CODE (lhs) == CONST ? XEXP (lhs, 0) : lhs;
3396169689Skan		    tem_rhs = GET_CODE (rhs) == CONST ? XEXP (rhs, 0) : rhs;
3397169689Skan		    tem = simplify_binary_operation (ncode, mode, tem_lhs, tem_rhs);
3398169689Skan
3399169689Skan		    if (tem && !CONSTANT_P (tem))
3400169689Skan		      tem = gen_rtx_CONST (GET_MODE (tem), tem);
3401169689Skan		  }
3402169689Skan		else
3403169689Skan		  tem = simplify_binary_operation (ncode, mode, lhs, rhs);
3404169689Skan
3405117395Skan		/* Reject "simplifications" that just wrap the two
340690075Sobrien		   arguments in a CONST.  Failure to do so can result
340790075Sobrien		   in infinite recursion with simplify_binary_operation
340890075Sobrien		   when it calls us to simplify CONST operations.  */
340990075Sobrien		if (tem
341090075Sobrien		    && ! (GET_CODE (tem) == CONST
341190075Sobrien			  && GET_CODE (XEXP (tem, 0)) == ncode
341290075Sobrien			  && XEXP (XEXP (tem, 0), 0) == lhs
3413169689Skan			  && XEXP (XEXP (tem, 0), 1) == rhs))
341490075Sobrien		  {
341590075Sobrien		    lneg &= rneg;
341690075Sobrien		    if (GET_CODE (tem) == NEG)
341790075Sobrien		      tem = XEXP (tem, 0), lneg = !lneg;
341890075Sobrien		    if (GET_CODE (tem) == CONST_INT && lneg)
341990075Sobrien		      tem = neg_const_int (mode, tem), lneg = 0;
342090075Sobrien
342190075Sobrien		    ops[i].op = tem;
342290075Sobrien		    ops[i].neg = lneg;
342390075Sobrien		    ops[j].op = NULL_RTX;
342490075Sobrien		    changed = 1;
342590075Sobrien		  }
342690075Sobrien	      }
342790075Sobrien	  }
342890075Sobrien
3429169689Skan      /* Pack all the operands to the lower-numbered entries.  */
3430169689Skan      for (i = 0, j = 0; j < n_ops; j++)
3431169689Skan        if (ops[j].op)
3432169689Skan          {
3433169689Skan	    ops[i] = ops[j];
3434169689Skan	    i++;
3435169689Skan          }
3436169689Skan      n_ops = i;
343790075Sobrien    }
343890075Sobrien  while (changed);
343990075Sobrien
3440132718Skan  /* Create (minus -C X) instead of (neg (const (plus X C))).  */
3441132718Skan  if (n_ops == 2
3442132718Skan      && GET_CODE (ops[1].op) == CONST_INT
3443132718Skan      && CONSTANT_P (ops[0].op)
3444132718Skan      && ops[0].neg)
3445132718Skan    return gen_rtx_fmt_ee (MINUS, mode, ops[1].op, ops[0].op);
3446132718Skan
344790075Sobrien  /* We suppressed creation of trivial CONST expressions in the
344890075Sobrien     combination loop to avoid recursion.  Create one manually now.
344990075Sobrien     The combination loop should have ensured that there is exactly
345090075Sobrien     one CONST_INT, and the sort will have ensured that it is last
345190075Sobrien     in the array and that any other constant will be next-to-last.  */
345290075Sobrien
345390075Sobrien  if (n_ops > 1
345490075Sobrien      && GET_CODE (ops[n_ops - 1].op) == CONST_INT
345590075Sobrien      && CONSTANT_P (ops[n_ops - 2].op))
345690075Sobrien    {
345790075Sobrien      rtx value = ops[n_ops - 1].op;
345890075Sobrien      if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg)
345990075Sobrien	value = neg_const_int (mode, value);
346090075Sobrien      ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value));
346190075Sobrien      n_ops--;
346290075Sobrien    }
346390075Sobrien
3464132718Skan  /* Put a non-negated operand first, if possible.  */
346590075Sobrien
346690075Sobrien  for (i = 0; i < n_ops && ops[i].neg; i++)
346790075Sobrien    continue;
346890075Sobrien  if (i == n_ops)
3469132718Skan    ops[0].op = gen_rtx_NEG (mode, ops[0].op);
347090075Sobrien  else if (i != 0)
347190075Sobrien    {
347290075Sobrien      tem = ops[0].op;
347390075Sobrien      ops[0] = ops[i];
347490075Sobrien      ops[i].op = tem;
347590075Sobrien      ops[i].neg = 1;
347690075Sobrien    }
347790075Sobrien
347890075Sobrien  /* Now make the result by performing the requested operations.  */
347990075Sobrien  result = ops[0].op;
348090075Sobrien  for (i = 1; i < n_ops; i++)
348190075Sobrien    result = gen_rtx_fmt_ee (ops[i].neg ? MINUS : PLUS,
348290075Sobrien			     mode, result, ops[i].op);
348390075Sobrien
3484132718Skan  return result;
348590075Sobrien}
348690075Sobrien
3487169689Skan/* Check whether an operand is suitable for calling simplify_plus_minus.  */
3488169689Skanstatic bool
3489169689Skanplus_minus_operand_p (rtx x)
3490169689Skan{
3491169689Skan  return GET_CODE (x) == PLUS
3492169689Skan         || GET_CODE (x) == MINUS
3493169689Skan	 || (GET_CODE (x) == CONST
3494169689Skan	     && GET_CODE (XEXP (x, 0)) == PLUS
3495169689Skan	     && CONSTANT_P (XEXP (XEXP (x, 0), 0))
3496169689Skan	     && CONSTANT_P (XEXP (XEXP (x, 0), 1)));
3497169689Skan}
3498169689Skan
349990075Sobrien/* Like simplify_binary_operation except used for relational operators.
3500169689Skan   MODE is the mode of the result. If MODE is VOIDmode, both operands must
3501169689Skan   not also be VOIDmode.
350290075Sobrien
3503169689Skan   CMP_MODE specifies in which mode the comparison is done in, so it is
3504169689Skan   the mode of the operands.  If CMP_MODE is VOIDmode, it is taken from
3505169689Skan   the operands or, if both are VOIDmode, the operands are compared in
3506169689Skan   "infinite precision".  */
350790075Sobrienrtx
3508132718Skansimplify_relational_operation (enum rtx_code code, enum machine_mode mode,
3509169689Skan			       enum machine_mode cmp_mode, rtx op0, rtx op1)
351090075Sobrien{
3511169689Skan  rtx tem, trueop0, trueop1;
3512169689Skan
3513169689Skan  if (cmp_mode == VOIDmode)
3514169689Skan    cmp_mode = GET_MODE (op0);
3515169689Skan  if (cmp_mode == VOIDmode)
3516169689Skan    cmp_mode = GET_MODE (op1);
3517169689Skan
3518169689Skan  tem = simplify_const_relational_operation (code, cmp_mode, op0, op1);
3519169689Skan  if (tem)
3520169689Skan    {
3521169689Skan      if (SCALAR_FLOAT_MODE_P (mode))
3522169689Skan	{
3523169689Skan          if (tem == const0_rtx)
3524169689Skan            return CONST0_RTX (mode);
3525169689Skan#ifdef FLOAT_STORE_FLAG_VALUE
3526169689Skan	  {
3527169689Skan	    REAL_VALUE_TYPE val;
3528169689Skan	    val = FLOAT_STORE_FLAG_VALUE (mode);
3529169689Skan	    return CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
3530169689Skan	  }
3531169689Skan#else
3532169689Skan	  return NULL_RTX;
3533169689Skan#endif
3534169689Skan	}
3535169689Skan      if (VECTOR_MODE_P (mode))
3536169689Skan	{
3537169689Skan	  if (tem == const0_rtx)
3538169689Skan	    return CONST0_RTX (mode);
3539169689Skan#ifdef VECTOR_STORE_FLAG_VALUE
3540169689Skan	  {
3541169689Skan	    int i, units;
3542169689Skan	    rtvec v;
3543169689Skan
3544169689Skan	    rtx val = VECTOR_STORE_FLAG_VALUE (mode);
3545169689Skan	    if (val == NULL_RTX)
3546169689Skan	      return NULL_RTX;
3547169689Skan	    if (val == const1_rtx)
3548169689Skan	      return CONST1_RTX (mode);
3549169689Skan
3550169689Skan	    units = GET_MODE_NUNITS (mode);
3551169689Skan	    v = rtvec_alloc (units);
3552169689Skan	    for (i = 0; i < units; i++)
3553169689Skan	      RTVEC_ELT (v, i) = val;
3554169689Skan	    return gen_rtx_raw_CONST_VECTOR (mode, v);
3555169689Skan	  }
3556169689Skan#else
3557169689Skan	  return NULL_RTX;
3558169689Skan#endif
3559169689Skan	}
3560169689Skan
3561169689Skan      return tem;
3562169689Skan    }
3563169689Skan
3564169689Skan  /* For the following tests, ensure const0_rtx is op1.  */
3565169689Skan  if (swap_commutative_operands_p (op0, op1)
3566169689Skan      || (op0 == const0_rtx && op1 != const0_rtx))
3567169689Skan    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
3568169689Skan
3569169689Skan  /* If op0 is a compare, extract the comparison arguments from it.  */
3570169689Skan  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
3571169689Skan    return simplify_relational_operation (code, mode, VOIDmode,
3572169689Skan				          XEXP (op0, 0), XEXP (op0, 1));
3573169689Skan
3574169689Skan  if (GET_MODE_CLASS (cmp_mode) == MODE_CC
3575169689Skan      || CC0_P (op0))
3576169689Skan    return NULL_RTX;
3577169689Skan
3578169689Skan  trueop0 = avoid_constant_pool_reference (op0);
3579169689Skan  trueop1 = avoid_constant_pool_reference (op1);
3580169689Skan  return simplify_relational_operation_1 (code, mode, cmp_mode,
3581169689Skan		  			  trueop0, trueop1);
3582169689Skan}
3583169689Skan
3584169689Skan/* This part of simplify_relational_operation is only used when CMP_MODE
3585169689Skan   is not in class MODE_CC (i.e. it is a real comparison).
3586169689Skan
3587169689Skan   MODE is the mode of the result, while CMP_MODE specifies in which
3588169689Skan   mode the comparison is done in, so it is the mode of the operands.  */
3589169689Skan
3590169689Skanstatic rtx
3591169689Skansimplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
3592169689Skan				 enum machine_mode cmp_mode, rtx op0, rtx op1)
3593169689Skan{
3594169689Skan  enum rtx_code op0code = GET_CODE (op0);
3595169689Skan
3596169689Skan  if (GET_CODE (op1) == CONST_INT)
3597169689Skan    {
3598169689Skan      if (INTVAL (op1) == 0 && COMPARISON_P (op0))
3599169689Skan	{
3600169689Skan	  /* If op0 is a comparison, extract the comparison arguments
3601169689Skan	     from it.  */
3602169689Skan	  if (code == NE)
3603169689Skan	    {
3604169689Skan	      if (GET_MODE (op0) == mode)
3605169689Skan		return simplify_rtx (op0);
3606169689Skan	      else
3607169689Skan		return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
3608169689Skan					        XEXP (op0, 0), XEXP (op0, 1));
3609169689Skan	    }
3610169689Skan	  else if (code == EQ)
3611169689Skan	    {
3612169689Skan	      enum rtx_code new_code = reversed_comparison_code (op0, NULL_RTX);
3613169689Skan	      if (new_code != UNKNOWN)
3614169689Skan	        return simplify_gen_relational (new_code, mode, VOIDmode,
3615169689Skan					        XEXP (op0, 0), XEXP (op0, 1));
3616169689Skan	    }
3617169689Skan	}
3618169689Skan    }
3619169689Skan
3620169689Skan  /* (eq/ne (plus x cst1) cst2) simplifies to (eq/ne x (cst2 - cst1))  */
3621169689Skan  if ((code == EQ || code == NE)
3622169689Skan      && (op0code == PLUS || op0code == MINUS)
3623169689Skan      && CONSTANT_P (op1)
3624169689Skan      && CONSTANT_P (XEXP (op0, 1))
3625169689Skan      && (INTEGRAL_MODE_P (cmp_mode) || flag_unsafe_math_optimizations))
3626169689Skan    {
3627169689Skan      rtx x = XEXP (op0, 0);
3628169689Skan      rtx c = XEXP (op0, 1);
3629169689Skan
3630169689Skan      c = simplify_gen_binary (op0code == PLUS ? MINUS : PLUS,
3631169689Skan			       cmp_mode, op1, c);
3632169689Skan      return simplify_gen_relational (code, mode, cmp_mode, x, c);
3633169689Skan    }
3634169689Skan
3635169689Skan  /* (ne:SI (zero_extract:SI FOO (const_int 1) BAR) (const_int 0))) is
3636169689Skan     the same as (zero_extract:SI FOO (const_int 1) BAR).  */
3637169689Skan  if (code == NE
3638169689Skan      && op1 == const0_rtx
3639169689Skan      && GET_MODE_CLASS (mode) == MODE_INT
3640169689Skan      && cmp_mode != VOIDmode
3641169689Skan      /* ??? Work-around BImode bugs in the ia64 backend.  */
3642169689Skan      && mode != BImode
3643169689Skan      && cmp_mode != BImode
3644169689Skan      && nonzero_bits (op0, cmp_mode) == 1
3645169689Skan      && STORE_FLAG_VALUE == 1)
3646169689Skan    return GET_MODE_SIZE (mode) > GET_MODE_SIZE (cmp_mode)
3647169689Skan	   ? simplify_gen_unary (ZERO_EXTEND, mode, op0, cmp_mode)
3648169689Skan	   : lowpart_subreg (mode, op0, cmp_mode);
3649169689Skan
3650169689Skan  /* (eq/ne (xor x y) 0) simplifies to (eq/ne x y).  */
3651169689Skan  if ((code == EQ || code == NE)
3652169689Skan      && op1 == const0_rtx
3653169689Skan      && op0code == XOR)
3654169689Skan    return simplify_gen_relational (code, mode, cmp_mode,
3655169689Skan				    XEXP (op0, 0), XEXP (op0, 1));
3656169689Skan
3657169689Skan  /* (eq/ne (xor x y) x) simplifies to (eq/ne y 0).  */
3658169689Skan  if ((code == EQ || code == NE)
3659169689Skan      && op0code == XOR
3660169689Skan      && rtx_equal_p (XEXP (op0, 0), op1)
3661169689Skan      && !side_effects_p (XEXP (op0, 0)))
3662169689Skan    return simplify_gen_relational (code, mode, cmp_mode,
3663169689Skan				    XEXP (op0, 1), const0_rtx);
3664169689Skan
3665169689Skan  /* Likewise (eq/ne (xor x y) y) simplifies to (eq/ne x 0).  */
3666169689Skan  if ((code == EQ || code == NE)
3667169689Skan      && op0code == XOR
3668169689Skan      && rtx_equal_p (XEXP (op0, 1), op1)
3669169689Skan      && !side_effects_p (XEXP (op0, 1)))
3670169689Skan    return simplify_gen_relational (code, mode, cmp_mode,
3671169689Skan				    XEXP (op0, 0), const0_rtx);
3672169689Skan
3673169689Skan  /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
3674169689Skan  if ((code == EQ || code == NE)
3675169689Skan      && op0code == XOR
3676169689Skan      && (GET_CODE (op1) == CONST_INT
3677169689Skan	  || GET_CODE (op1) == CONST_DOUBLE)
3678169689Skan      && (GET_CODE (XEXP (op0, 1)) == CONST_INT
3679169689Skan	  || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE))
3680169689Skan    return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
3681169689Skan				    simplify_gen_binary (XOR, cmp_mode,
3682169689Skan							 XEXP (op0, 1), op1));
3683169689Skan
3684169689Skan  return NULL_RTX;
3685169689Skan}
3686169689Skan
3687169689Skan/* Check if the given comparison (done in the given MODE) is actually a
3688169689Skan   tautology or a contradiction.
3689169689Skan   If no simplification is possible, this function returns zero.
3690169689Skan   Otherwise, it returns either const_true_rtx or const0_rtx.  */
3691169689Skan
3692169689Skanrtx
3693169689Skansimplify_const_relational_operation (enum rtx_code code,
3694169689Skan				     enum machine_mode mode,
3695169689Skan				     rtx op0, rtx op1)
3696169689Skan{
369790075Sobrien  int equal, op0lt, op0ltu, op1lt, op1ltu;
369890075Sobrien  rtx tem;
369990075Sobrien  rtx trueop0;
370090075Sobrien  rtx trueop1;
370190075Sobrien
3702169689Skan  gcc_assert (mode != VOIDmode
3703169689Skan	      || (GET_MODE (op0) == VOIDmode
3704169689Skan		  && GET_MODE (op1) == VOIDmode));
370590075Sobrien
370690075Sobrien  /* If op0 is a compare, extract the comparison arguments from it.  */
370790075Sobrien  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
3708169689Skan    {
3709169689Skan      op1 = XEXP (op0, 1);
3710169689Skan      op0 = XEXP (op0, 0);
371190075Sobrien
3712169689Skan      if (GET_MODE (op0) != VOIDmode)
3713169689Skan	mode = GET_MODE (op0);
3714169689Skan      else if (GET_MODE (op1) != VOIDmode)
3715169689Skan	mode = GET_MODE (op1);
3716169689Skan      else
3717169689Skan	return 0;
3718169689Skan    }
371990075Sobrien
372090075Sobrien  /* We can't simplify MODE_CC values since we don't know what the
372190075Sobrien     actual comparison is.  */
3722132718Skan  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC || CC0_P (op0))
372390075Sobrien    return 0;
372490075Sobrien
372590075Sobrien  /* Make sure the constant is second.  */
3726169689Skan  if (swap_commutative_operands_p (op0, op1))
372790075Sobrien    {
372890075Sobrien      tem = op0, op0 = op1, op1 = tem;
372990075Sobrien      code = swap_condition (code);
373090075Sobrien    }
373190075Sobrien
3732169689Skan  trueop0 = avoid_constant_pool_reference (op0);
3733169689Skan  trueop1 = avoid_constant_pool_reference (op1);
3734169689Skan
373590075Sobrien  /* For integer comparisons of A and B maybe we can simplify A - B and can
373690075Sobrien     then simplify a comparison of that with zero.  If A and B are both either
373790075Sobrien     a register or a CONST_INT, this can't help; testing for these cases will
373890075Sobrien     prevent infinite recursion here and speed things up.
373990075Sobrien
3740169689Skan     We can only do this for EQ and NE comparisons as otherwise we may
3741169689Skan     lose or introduce overflow which we cannot disregard as undefined as
3742169689Skan     we do not know the signedness of the operation on either the left or
3743169689Skan     the right hand side of the comparison.  */
374490075Sobrien
374590075Sobrien  if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
3746169689Skan      && (code == EQ || code == NE)
3747169689Skan      && ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
3748169689Skan	    && (REG_P (op1) || GET_CODE (trueop1) == CONST_INT))
374990075Sobrien      && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
3750169689Skan      /* We cannot do this if tem is a nonzero address.  */
3751169689Skan      && ! nonzero_address_p (tem))
3752169689Skan    return simplify_const_relational_operation (signed_condition (code),
3753169689Skan						mode, tem, const0_rtx);
375490075Sobrien
3755169689Skan  if (! HONOR_NANS (mode) && code == ORDERED)
375690075Sobrien    return const_true_rtx;
375790075Sobrien
3758169689Skan  if (! HONOR_NANS (mode) && code == UNORDERED)
375990075Sobrien    return const0_rtx;
376090075Sobrien
3761117395Skan  /* For modes without NaNs, if the two operands are equal, we know the
3762132718Skan     result except if they have side-effects.  */
3763132718Skan  if (! HONOR_NANS (GET_MODE (trueop0))
3764117395Skan      && rtx_equal_p (trueop0, trueop1)
3765117395Skan      && ! side_effects_p (trueop0))
376690075Sobrien    equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
376790075Sobrien
376890075Sobrien  /* If the operands are floating-point constants, see if we can fold
376990075Sobrien     the result.  */
377090075Sobrien  else if (GET_CODE (trueop0) == CONST_DOUBLE
377190075Sobrien	   && GET_CODE (trueop1) == CONST_DOUBLE
3772169689Skan	   && SCALAR_FLOAT_MODE_P (GET_MODE (trueop0)))
377390075Sobrien    {
3774117395Skan      REAL_VALUE_TYPE d0, d1;
377590075Sobrien
3776117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (d0, trueop0);
3777117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (d1, trueop1);
377890075Sobrien
3779117395Skan      /* Comparisons are unordered iff at least one of the values is NaN.  */
3780117395Skan      if (REAL_VALUE_ISNAN (d0) || REAL_VALUE_ISNAN (d1))
378190075Sobrien	switch (code)
378290075Sobrien	  {
378390075Sobrien	  case UNEQ:
378490075Sobrien	  case UNLT:
378590075Sobrien	  case UNGT:
378690075Sobrien	  case UNLE:
378790075Sobrien	  case UNGE:
378890075Sobrien	  case NE:
378990075Sobrien	  case UNORDERED:
379090075Sobrien	    return const_true_rtx;
379190075Sobrien	  case EQ:
379290075Sobrien	  case LT:
379390075Sobrien	  case GT:
379490075Sobrien	  case LE:
379590075Sobrien	  case GE:
379690075Sobrien	  case LTGT:
379790075Sobrien	  case ORDERED:
379890075Sobrien	    return const0_rtx;
379990075Sobrien	  default:
380090075Sobrien	    return 0;
380190075Sobrien	  }
380290075Sobrien
3803117395Skan      equal = REAL_VALUES_EQUAL (d0, d1);
3804117395Skan      op0lt = op0ltu = REAL_VALUES_LESS (d0, d1);
3805117395Skan      op1lt = op1ltu = REAL_VALUES_LESS (d1, d0);
380690075Sobrien    }
380790075Sobrien
380890075Sobrien  /* Otherwise, see if the operands are both integers.  */
380990075Sobrien  else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
381090075Sobrien	   && (GET_CODE (trueop0) == CONST_DOUBLE
381190075Sobrien	       || GET_CODE (trueop0) == CONST_INT)
381290075Sobrien	   && (GET_CODE (trueop1) == CONST_DOUBLE
381390075Sobrien	       || GET_CODE (trueop1) == CONST_INT))
381490075Sobrien    {
381590075Sobrien      int width = GET_MODE_BITSIZE (mode);
381690075Sobrien      HOST_WIDE_INT l0s, h0s, l1s, h1s;
381790075Sobrien      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
381890075Sobrien
381990075Sobrien      /* Get the two words comprising each integer constant.  */
382090075Sobrien      if (GET_CODE (trueop0) == CONST_DOUBLE)
382190075Sobrien	{
382290075Sobrien	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
382390075Sobrien	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
382490075Sobrien	}
382590075Sobrien      else
382690075Sobrien	{
382790075Sobrien	  l0u = l0s = INTVAL (trueop0);
382890075Sobrien	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
382990075Sobrien	}
3830117395Skan
383190075Sobrien      if (GET_CODE (trueop1) == CONST_DOUBLE)
383290075Sobrien	{
383390075Sobrien	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
383490075Sobrien	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
383590075Sobrien	}
383690075Sobrien      else
383790075Sobrien	{
383890075Sobrien	  l1u = l1s = INTVAL (trueop1);
383990075Sobrien	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
384090075Sobrien	}
384190075Sobrien
384290075Sobrien      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
384390075Sobrien	 we have to sign or zero-extend the values.  */
384490075Sobrien      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
384590075Sobrien	{
384690075Sobrien	  l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
384790075Sobrien	  l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
384890075Sobrien
384990075Sobrien	  if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
385090075Sobrien	    l0s |= ((HOST_WIDE_INT) (-1) << width);
385190075Sobrien
385290075Sobrien	  if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
385390075Sobrien	    l1s |= ((HOST_WIDE_INT) (-1) << width);
385490075Sobrien	}
385590075Sobrien      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
385690075Sobrien	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
385790075Sobrien
385890075Sobrien      equal = (h0u == h1u && l0u == l1u);
385990075Sobrien      op0lt = (h0s < h1s || (h0s == h1s && l0u < l1u));
386090075Sobrien      op1lt = (h1s < h0s || (h1s == h0s && l1u < l0u));
386190075Sobrien      op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
386290075Sobrien      op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
386390075Sobrien    }
386490075Sobrien
386590075Sobrien  /* Otherwise, there are some code-specific tests we can make.  */
386690075Sobrien  else
386790075Sobrien    {
3868169689Skan      /* Optimize comparisons with upper and lower bounds.  */
3869169689Skan      if (SCALAR_INT_MODE_P (mode)
3870169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
3871169689Skan	{
3872169689Skan	  rtx mmin, mmax;
3873169689Skan	  int sign;
3874169689Skan
3875169689Skan	  if (code == GEU
3876169689Skan	      || code == LEU
3877169689Skan	      || code == GTU
3878169689Skan	      || code == LTU)
3879169689Skan	    sign = 0;
3880169689Skan	  else
3881169689Skan	    sign = 1;
3882169689Skan
3883169689Skan	  get_mode_bounds (mode, sign, mode, &mmin, &mmax);
3884169689Skan
3885169689Skan	  tem = NULL_RTX;
3886169689Skan	  switch (code)
3887169689Skan	    {
3888169689Skan	    case GEU:
3889169689Skan	    case GE:
3890169689Skan	      /* x >= min is always true.  */
3891169689Skan	      if (rtx_equal_p (trueop1, mmin))
3892169689Skan		tem = const_true_rtx;
3893169689Skan	      else
3894169689Skan	      break;
3895169689Skan
3896169689Skan	    case LEU:
3897169689Skan	    case LE:
3898169689Skan	      /* x <= max is always true.  */
3899169689Skan	      if (rtx_equal_p (trueop1, mmax))
3900169689Skan		tem = const_true_rtx;
3901169689Skan	      break;
3902169689Skan
3903169689Skan	    case GTU:
3904169689Skan	    case GT:
3905169689Skan	      /* x > max is always false.  */
3906169689Skan	      if (rtx_equal_p (trueop1, mmax))
3907169689Skan		tem = const0_rtx;
3908169689Skan	      break;
3909169689Skan
3910169689Skan	    case LTU:
3911169689Skan	    case LT:
3912169689Skan	      /* x < min is always false.  */
3913169689Skan	      if (rtx_equal_p (trueop1, mmin))
3914169689Skan		tem = const0_rtx;
3915169689Skan	      break;
3916169689Skan
3917169689Skan	    default:
3918169689Skan	      break;
3919169689Skan	    }
3920169689Skan	  if (tem == const0_rtx
3921169689Skan	      || tem == const_true_rtx)
3922169689Skan	    return tem;
3923169689Skan	}
3924169689Skan
392590075Sobrien      switch (code)
392690075Sobrien	{
392790075Sobrien	case EQ:
3928132718Skan	  if (trueop1 == const0_rtx && nonzero_address_p (op0))
392990075Sobrien	    return const0_rtx;
393090075Sobrien	  break;
393190075Sobrien
393290075Sobrien	case NE:
3933132718Skan	  if (trueop1 == const0_rtx && nonzero_address_p (op0))
393490075Sobrien	    return const_true_rtx;
393590075Sobrien	  break;
393690075Sobrien
3937117395Skan	case LT:
3938117395Skan	  /* Optimize abs(x) < 0.0.  */
3939169689Skan	  if (trueop1 == CONST0_RTX (mode)
3940169689Skan	      && !HONOR_SNANS (mode)
3941169689Skan	      && (!INTEGRAL_MODE_P (mode)
3942169689Skan		  || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
3943117395Skan	    {
3944117395Skan	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
3945117395Skan						       : trueop0;
3946117395Skan	      if (GET_CODE (tem) == ABS)
3947169689Skan		{
3948169689Skan		  if (INTEGRAL_MODE_P (mode)
3949169689Skan		      && (issue_strict_overflow_warning
3950169689Skan			  (WARN_STRICT_OVERFLOW_CONDITIONAL)))
3951169689Skan		    warning (OPT_Wstrict_overflow,
3952169689Skan			     ("assuming signed overflow does not occur when "
3953169689Skan			      "assuming abs (x) < 0 is false"));
3954169689Skan		  return const0_rtx;
3955169689Skan		}
3956117395Skan	    }
3957117395Skan	  break;
3958117395Skan
3959117395Skan	case GE:
3960117395Skan	  /* Optimize abs(x) >= 0.0.  */
3961169689Skan	  if (trueop1 == CONST0_RTX (mode)
3962169689Skan	      && !HONOR_NANS (mode)
3963169689Skan	      && (!INTEGRAL_MODE_P (mode)
3964169689Skan		  || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
3965117395Skan	    {
3966117395Skan	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
3967117395Skan						       : trueop0;
3968117395Skan	      if (GET_CODE (tem) == ABS)
3969169689Skan		{
3970169689Skan		  if (INTEGRAL_MODE_P (mode)
3971169689Skan		      && (issue_strict_overflow_warning
3972169689Skan			  (WARN_STRICT_OVERFLOW_CONDITIONAL)))
3973169689Skan		    warning (OPT_Wstrict_overflow,
3974169689Skan			     ("assuming signed overflow does not occur when "
3975169689Skan			      "assuming abs (x) >= 0 is true"));
3976169689Skan		  return const_true_rtx;
3977169689Skan		}
3978117395Skan	    }
3979117395Skan	  break;
3980117395Skan
3981132718Skan	case UNGE:
3982132718Skan	  /* Optimize ! (abs(x) < 0.0).  */
3983132718Skan	  if (trueop1 == CONST0_RTX (mode))
3984132718Skan	    {
3985132718Skan	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
3986132718Skan						       : trueop0;
3987132718Skan	      if (GET_CODE (tem) == ABS)
3988132718Skan		return const_true_rtx;
3989132718Skan	    }
3990132718Skan	  break;
3991132718Skan
399290075Sobrien	default:
399390075Sobrien	  break;
399490075Sobrien	}
399590075Sobrien
399690075Sobrien      return 0;
399790075Sobrien    }
399890075Sobrien
399990075Sobrien  /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
400090075Sobrien     as appropriate.  */
400190075Sobrien  switch (code)
400290075Sobrien    {
400390075Sobrien    case EQ:
400490075Sobrien    case UNEQ:
400590075Sobrien      return equal ? const_true_rtx : const0_rtx;
400690075Sobrien    case NE:
400790075Sobrien    case LTGT:
400890075Sobrien      return ! equal ? const_true_rtx : const0_rtx;
400990075Sobrien    case LT:
401090075Sobrien    case UNLT:
401190075Sobrien      return op0lt ? const_true_rtx : const0_rtx;
401290075Sobrien    case GT:
401390075Sobrien    case UNGT:
401490075Sobrien      return op1lt ? const_true_rtx : const0_rtx;
401590075Sobrien    case LTU:
401690075Sobrien      return op0ltu ? const_true_rtx : const0_rtx;
401790075Sobrien    case GTU:
401890075Sobrien      return op1ltu ? const_true_rtx : const0_rtx;
401990075Sobrien    case LE:
402090075Sobrien    case UNLE:
402190075Sobrien      return equal || op0lt ? const_true_rtx : const0_rtx;
402290075Sobrien    case GE:
402390075Sobrien    case UNGE:
402490075Sobrien      return equal || op1lt ? const_true_rtx : const0_rtx;
402590075Sobrien    case LEU:
402690075Sobrien      return equal || op0ltu ? const_true_rtx : const0_rtx;
402790075Sobrien    case GEU:
402890075Sobrien      return equal || op1ltu ? const_true_rtx : const0_rtx;
402990075Sobrien    case ORDERED:
403090075Sobrien      return const_true_rtx;
403190075Sobrien    case UNORDERED:
403290075Sobrien      return const0_rtx;
403390075Sobrien    default:
4034169689Skan      gcc_unreachable ();
403590075Sobrien    }
403690075Sobrien}
403790075Sobrien
403890075Sobrien/* Simplify CODE, an operation with result mode MODE and three operands,
403990075Sobrien   OP0, OP1, and OP2.  OP0_MODE was the mode of OP0 before it became
404090075Sobrien   a constant.  Return 0 if no simplifications is possible.  */
404190075Sobrien
404290075Sobrienrtx
4043132718Skansimplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
4044132718Skan			    enum machine_mode op0_mode, rtx op0, rtx op1,
4045132718Skan			    rtx op2)
404690075Sobrien{
404790075Sobrien  unsigned int width = GET_MODE_BITSIZE (mode);
404890075Sobrien
404990075Sobrien  /* VOIDmode means "infinite" precision.  */
405090075Sobrien  if (width == 0)
405190075Sobrien    width = HOST_BITS_PER_WIDE_INT;
405290075Sobrien
405390075Sobrien  switch (code)
405490075Sobrien    {
405590075Sobrien    case SIGN_EXTRACT:
405690075Sobrien    case ZERO_EXTRACT:
405790075Sobrien      if (GET_CODE (op0) == CONST_INT
405890075Sobrien	  && GET_CODE (op1) == CONST_INT
405990075Sobrien	  && GET_CODE (op2) == CONST_INT
406090075Sobrien	  && ((unsigned) INTVAL (op1) + (unsigned) INTVAL (op2) <= width)
406190075Sobrien	  && width <= (unsigned) HOST_BITS_PER_WIDE_INT)
406290075Sobrien	{
406390075Sobrien	  /* Extracting a bit-field from a constant */
406490075Sobrien	  HOST_WIDE_INT val = INTVAL (op0);
406590075Sobrien
406690075Sobrien	  if (BITS_BIG_ENDIAN)
406790075Sobrien	    val >>= (GET_MODE_BITSIZE (op0_mode)
406890075Sobrien		     - INTVAL (op2) - INTVAL (op1));
406990075Sobrien	  else
407090075Sobrien	    val >>= INTVAL (op2);
407190075Sobrien
407290075Sobrien	  if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
407390075Sobrien	    {
407490075Sobrien	      /* First zero-extend.  */
407590075Sobrien	      val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
407690075Sobrien	      /* If desired, propagate sign bit.  */
407790075Sobrien	      if (code == SIGN_EXTRACT
407890075Sobrien		  && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1))))
407990075Sobrien		val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
408090075Sobrien	    }
408190075Sobrien
408290075Sobrien	  /* Clear the bits that don't belong in our mode,
408390075Sobrien	     unless they and our sign bit are all one.
408490075Sobrien	     So we get either a reasonable negative value or a reasonable
408590075Sobrien	     unsigned value for this mode.  */
408690075Sobrien	  if (width < HOST_BITS_PER_WIDE_INT
408790075Sobrien	      && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
408890075Sobrien		  != ((HOST_WIDE_INT) (-1) << (width - 1))))
408990075Sobrien	    val &= ((HOST_WIDE_INT) 1 << width) - 1;
409090075Sobrien
4091169689Skan	  return gen_int_mode (val, mode);
409290075Sobrien	}
409390075Sobrien      break;
409490075Sobrien
409590075Sobrien    case IF_THEN_ELSE:
409690075Sobrien      if (GET_CODE (op0) == CONST_INT)
409790075Sobrien	return op0 != const0_rtx ? op1 : op2;
409890075Sobrien
4099132718Skan      /* Convert c ? a : a into "a".  */
4100132718Skan      if (rtx_equal_p (op1, op2) && ! side_effects_p (op0))
410190075Sobrien	return op1;
4102132718Skan
4103132718Skan      /* Convert a != b ? a : b into "a".  */
4104132718Skan      if (GET_CODE (op0) == NE
4105132718Skan	  && ! side_effects_p (op0)
4106132718Skan	  && ! HONOR_NANS (mode)
4107132718Skan	  && ! HONOR_SIGNED_ZEROS (mode)
4108132718Skan	  && ((rtx_equal_p (XEXP (op0, 0), op1)
4109132718Skan	       && rtx_equal_p (XEXP (op0, 1), op2))
4110132718Skan	      || (rtx_equal_p (XEXP (op0, 0), op2)
4111132718Skan		  && rtx_equal_p (XEXP (op0, 1), op1))))
4112132718Skan	return op1;
4113132718Skan
4114132718Skan      /* Convert a == b ? a : b into "b".  */
4115132718Skan      if (GET_CODE (op0) == EQ
4116132718Skan	  && ! side_effects_p (op0)
4117132718Skan	  && ! HONOR_NANS (mode)
4118132718Skan	  && ! HONOR_SIGNED_ZEROS (mode)
4119132718Skan	  && ((rtx_equal_p (XEXP (op0, 0), op1)
4120132718Skan	       && rtx_equal_p (XEXP (op0, 1), op2))
4121132718Skan	      || (rtx_equal_p (XEXP (op0, 0), op2)
4122132718Skan		  && rtx_equal_p (XEXP (op0, 1), op1))))
412390075Sobrien	return op2;
4124132718Skan
4125169689Skan      if (COMPARISON_P (op0) && ! side_effects_p (op0))
412690075Sobrien	{
412790075Sobrien	  enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
412890075Sobrien					? GET_MODE (XEXP (op0, 1))
412990075Sobrien					: GET_MODE (XEXP (op0, 0)));
413090075Sobrien	  rtx temp;
413190075Sobrien
413290075Sobrien	  /* Look for happy constants in op1 and op2.  */
413390075Sobrien	  if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
413490075Sobrien	    {
413590075Sobrien	      HOST_WIDE_INT t = INTVAL (op1);
413690075Sobrien	      HOST_WIDE_INT f = INTVAL (op2);
4137117395Skan
413890075Sobrien	      if (t == STORE_FLAG_VALUE && f == 0)
413990075Sobrien	        code = GET_CODE (op0);
414090075Sobrien	      else if (t == 0 && f == STORE_FLAG_VALUE)
414190075Sobrien		{
414290075Sobrien		  enum rtx_code tmp;
414390075Sobrien		  tmp = reversed_comparison_code (op0, NULL_RTX);
414490075Sobrien		  if (tmp == UNKNOWN)
414590075Sobrien		    break;
414690075Sobrien		  code = tmp;
414790075Sobrien		}
414890075Sobrien	      else
414990075Sobrien		break;
415090075Sobrien
4151169689Skan	      return simplify_gen_relational (code, mode, cmp_mode,
4152169689Skan					      XEXP (op0, 0), XEXP (op0, 1));
415390075Sobrien	    }
4154169689Skan
4155169689Skan	  if (cmp_mode == VOIDmode)
4156169689Skan	    cmp_mode = op0_mode;
4157169689Skan	  temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
4158169689Skan			  			cmp_mode, XEXP (op0, 0),
4159169689Skan						XEXP (op0, 1));
4160169689Skan
4161169689Skan	  /* See if any simplifications were possible.  */
4162169689Skan	  if (temp)
4163169689Skan	    {
4164169689Skan	      if (GET_CODE (temp) == CONST_INT)
4165169689Skan		return temp == const0_rtx ? op2 : op1;
4166169689Skan	      else if (temp)
4167169689Skan	        return gen_rtx_IF_THEN_ELSE (mode, temp, op1, op2);
4168169689Skan	    }
416990075Sobrien	}
417090075Sobrien      break;
4171132718Skan
4172117395Skan    case VEC_MERGE:
4173169689Skan      gcc_assert (GET_MODE (op0) == mode);
4174169689Skan      gcc_assert (GET_MODE (op1) == mode);
4175169689Skan      gcc_assert (VECTOR_MODE_P (mode));
4176117395Skan      op2 = avoid_constant_pool_reference (op2);
4177132718Skan      if (GET_CODE (op2) == CONST_INT)
4178117395Skan	{
4179117395Skan          int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
4180117395Skan	  unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
4181132718Skan	  int mask = (1 << n_elts) - 1;
418290075Sobrien
4183132718Skan	  if (!(INTVAL (op2) & mask))
4184132718Skan	    return op1;
4185132718Skan	  if ((INTVAL (op2) & mask) == mask)
4186132718Skan	    return op0;
4187132718Skan
4188132718Skan	  op0 = avoid_constant_pool_reference (op0);
4189132718Skan	  op1 = avoid_constant_pool_reference (op1);
4190132718Skan	  if (GET_CODE (op0) == CONST_VECTOR
4191132718Skan	      && GET_CODE (op1) == CONST_VECTOR)
4192132718Skan	    {
4193132718Skan	      rtvec v = rtvec_alloc (n_elts);
4194132718Skan	      unsigned int i;
4195132718Skan
4196132718Skan	      for (i = 0; i < n_elts; i++)
4197132718Skan		RTVEC_ELT (v, i) = (INTVAL (op2) & (1 << i)
4198132718Skan				    ? CONST_VECTOR_ELT (op0, i)
4199132718Skan				    : CONST_VECTOR_ELT (op1, i));
4200132718Skan	      return gen_rtx_CONST_VECTOR (mode, v);
4201132718Skan	    }
4202117395Skan	}
4203117395Skan      break;
4204117395Skan
420590075Sobrien    default:
4206169689Skan      gcc_unreachable ();
420790075Sobrien    }
420890075Sobrien
420990075Sobrien  return 0;
421090075Sobrien}
421190075Sobrien
4212132718Skan/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_VECTOR,
4213132718Skan   returning another CONST_INT or CONST_DOUBLE or CONST_VECTOR.
4214132718Skan
4215132718Skan   Works by unpacking OP into a collection of 8-bit values
4216132718Skan   represented as a little-endian array of 'unsigned char', selecting by BYTE,
4217132718Skan   and then repacking them again for OUTERMODE.  */
4218132718Skan
4219132718Skanstatic rtx
4220132718Skansimplify_immed_subreg (enum machine_mode outermode, rtx op,
4221132718Skan		       enum machine_mode innermode, unsigned int byte)
422290075Sobrien{
4223132718Skan  /* We support up to 512-bit values (for V8DFmode).  */
4224132718Skan  enum {
4225132718Skan    max_bitsize = 512,
4226132718Skan    value_bit = 8,
4227132718Skan    value_mask = (1 << value_bit) - 1
4228132718Skan  };
4229132718Skan  unsigned char value[max_bitsize / value_bit];
4230132718Skan  int value_start;
4231132718Skan  int i;
4232132718Skan  int elem;
423390075Sobrien
4234132718Skan  int num_elem;
4235132718Skan  rtx * elems;
4236132718Skan  int elem_bitsize;
4237132718Skan  rtx result_s;
4238132718Skan  rtvec result_v = NULL;
4239132718Skan  enum mode_class outer_class;
4240132718Skan  enum machine_mode outer_submode;
424190075Sobrien
4242132718Skan  /* Some ports misuse CCmode.  */
4243132718Skan  if (GET_MODE_CLASS (outermode) == MODE_CC && GET_CODE (op) == CONST_INT)
424490075Sobrien    return op;
424590075Sobrien
4246169689Skan  /* We have no way to represent a complex constant at the rtl level.  */
4247169689Skan  if (COMPLEX_MODE_P (outermode))
4248169689Skan    return NULL_RTX;
4249169689Skan
4250132718Skan  /* Unpack the value.  */
4251132718Skan
4252117395Skan  if (GET_CODE (op) == CONST_VECTOR)
4253117395Skan    {
4254132718Skan      num_elem = CONST_VECTOR_NUNITS (op);
4255132718Skan      elems = &CONST_VECTOR_ELT (op, 0);
4256132718Skan      elem_bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (innermode));
4257132718Skan    }
4258132718Skan  else
4259132718Skan    {
4260132718Skan      num_elem = 1;
4261132718Skan      elems = &op;
4262132718Skan      elem_bitsize = max_bitsize;
4263132718Skan    }
4264169689Skan  /* If this asserts, it is too complicated; reducing value_bit may help.  */
4265169689Skan  gcc_assert (BITS_PER_UNIT % value_bit == 0);
4266169689Skan  /* I don't know how to handle endianness of sub-units.  */
4267169689Skan  gcc_assert (elem_bitsize % BITS_PER_UNIT == 0);
4268132718Skan
4269132718Skan  for (elem = 0; elem < num_elem; elem++)
4270132718Skan    {
4271132718Skan      unsigned char * vp;
4272132718Skan      rtx el = elems[elem];
4273132718Skan
4274132718Skan      /* Vectors are kept in target memory order.  (This is probably
4275132718Skan	 a mistake.)  */
4276132718Skan      {
4277132718Skan	unsigned byte = (elem * elem_bitsize) / BITS_PER_UNIT;
4278132718Skan	unsigned ibyte = (((num_elem - 1 - elem) * elem_bitsize)
4279132718Skan			  / BITS_PER_UNIT);
4280132718Skan	unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
4281132718Skan	unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
4282132718Skan	unsigned bytele = (subword_byte % UNITS_PER_WORD
4283132718Skan			 + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
4284132718Skan	vp = value + (bytele * BITS_PER_UNIT) / value_bit;
4285132718Skan      }
4286132718Skan
4287132718Skan      switch (GET_CODE (el))
4288117395Skan	{
4289132718Skan	case CONST_INT:
4290132718Skan	  for (i = 0;
4291132718Skan	       i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
4292132718Skan	       i += value_bit)
4293132718Skan	    *vp++ = INTVAL (el) >> i;
4294132718Skan	  /* CONST_INTs are always logically sign-extended.  */
4295132718Skan	  for (; i < elem_bitsize; i += value_bit)
4296132718Skan	    *vp++ = INTVAL (el) < 0 ? -1 : 0;
4297132718Skan	  break;
4298132718Skan
4299132718Skan	case CONST_DOUBLE:
4300132718Skan	  if (GET_MODE (el) == VOIDmode)
4301132718Skan	    {
4302132718Skan	      /* If this triggers, someone should have generated a
4303132718Skan		 CONST_INT instead.  */
4304169689Skan	      gcc_assert (elem_bitsize > HOST_BITS_PER_WIDE_INT);
4305117395Skan
4306132718Skan	      for (i = 0; i < HOST_BITS_PER_WIDE_INT; i += value_bit)
4307132718Skan		*vp++ = CONST_DOUBLE_LOW (el) >> i;
4308132718Skan	      while (i < HOST_BITS_PER_WIDE_INT * 2 && i < elem_bitsize)
4309132718Skan		{
4310132718Skan		  *vp++
4311132718Skan		    = CONST_DOUBLE_HIGH (el) >> (i - HOST_BITS_PER_WIDE_INT);
4312132718Skan		  i += value_bit;
4313132718Skan		}
4314132718Skan	      /* It shouldn't matter what's done here, so fill it with
4315132718Skan		 zero.  */
4316161651Skan	      for (; i < elem_bitsize; i += value_bit)
4317132718Skan		*vp++ = 0;
4318132718Skan	    }
4319169689Skan	  else
4320132718Skan	    {
4321132718Skan	      long tmp[max_bitsize / 32];
4322132718Skan	      int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
4323117395Skan
4324169689Skan	      gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
4325169689Skan	      gcc_assert (bitsize <= elem_bitsize);
4326169689Skan	      gcc_assert (bitsize % value_bit == 0);
4327169689Skan
4328132718Skan	      real_to_target (tmp, CONST_DOUBLE_REAL_VALUE (el),
4329132718Skan			      GET_MODE (el));
4330117395Skan
4331132718Skan	      /* real_to_target produces its result in words affected by
4332132718Skan		 FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
4333132718Skan		 and use WORDS_BIG_ENDIAN instead; see the documentation
4334132718Skan	         of SUBREG in rtl.texi.  */
4335132718Skan	      for (i = 0; i < bitsize; i += value_bit)
4336117395Skan		{
4337132718Skan		  int ibase;
4338132718Skan		  if (WORDS_BIG_ENDIAN)
4339132718Skan		    ibase = bitsize - 1 - i;
4340132718Skan		  else
4341132718Skan		    ibase = i;
4342132718Skan		  *vp++ = tmp[ibase / 32] >> i % 32;
4343117395Skan		}
4344132718Skan
4345132718Skan	      /* It shouldn't matter what's done here, so fill it with
4346132718Skan		 zero.  */
4347132718Skan	      for (; i < elem_bitsize; i += value_bit)
4348132718Skan		*vp++ = 0;
4349117395Skan	    }
4350132718Skan	  break;
4351132718Skan
4352132718Skan	default:
4353169689Skan	  gcc_unreachable ();
4354117395Skan	}
4355117395Skan    }
4356117395Skan
4357132718Skan  /* Now, pick the right byte to start with.  */
4358132718Skan  /* Renumber BYTE so that the least-significant byte is byte 0.  A special
4359132718Skan     case is paradoxical SUBREGs, which shouldn't be adjusted since they
4360132718Skan     will already have offset 0.  */
4361132718Skan  if (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode))
436290075Sobrien    {
4363132718Skan      unsigned ibyte = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)
4364132718Skan			- byte);
4365132718Skan      unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
4366132718Skan      unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
4367132718Skan      byte = (subword_byte % UNITS_PER_WORD
4368132718Skan	      + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
4369132718Skan    }
437090075Sobrien
4371132718Skan  /* BYTE should still be inside OP.  (Note that BYTE is unsigned,
4372132718Skan     so if it's become negative it will instead be very large.)  */
4373169689Skan  gcc_assert (byte < GET_MODE_SIZE (innermode));
4374117395Skan
4375132718Skan  /* Convert from bytes to chunks of size value_bit.  */
4376132718Skan  value_start = byte * (BITS_PER_UNIT / value_bit);
4377117395Skan
4378132718Skan  /* Re-pack the value.  */
4379132718Skan
4380132718Skan  if (VECTOR_MODE_P (outermode))
4381132718Skan    {
4382132718Skan      num_elem = GET_MODE_NUNITS (outermode);
4383132718Skan      result_v = rtvec_alloc (num_elem);
4384132718Skan      elems = &RTVEC_ELT (result_v, 0);
4385132718Skan      outer_submode = GET_MODE_INNER (outermode);
4386132718Skan    }
4387132718Skan  else
4388132718Skan    {
4389132718Skan      num_elem = 1;
4390132718Skan      elems = &result_s;
4391132718Skan      outer_submode = outermode;
4392132718Skan    }
439390075Sobrien
4394132718Skan  outer_class = GET_MODE_CLASS (outer_submode);
4395132718Skan  elem_bitsize = GET_MODE_BITSIZE (outer_submode);
439690075Sobrien
4397169689Skan  gcc_assert (elem_bitsize % value_bit == 0);
4398169689Skan  gcc_assert (elem_bitsize + value_start * value_bit <= max_bitsize);
4399117395Skan
4400132718Skan  for (elem = 0; elem < num_elem; elem++)
4401132718Skan    {
4402132718Skan      unsigned char *vp;
4403132718Skan
4404132718Skan      /* Vectors are stored in target memory order.  (This is probably
4405132718Skan	 a mistake.)  */
4406132718Skan      {
4407132718Skan	unsigned byte = (elem * elem_bitsize) / BITS_PER_UNIT;
4408132718Skan	unsigned ibyte = (((num_elem - 1 - elem) * elem_bitsize)
4409132718Skan			  / BITS_PER_UNIT);
4410132718Skan	unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
4411132718Skan	unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
4412132718Skan	unsigned bytele = (subword_byte % UNITS_PER_WORD
4413132718Skan			 + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
4414132718Skan	vp = value + value_start + (bytele * BITS_PER_UNIT) / value_bit;
4415132718Skan      }
4416117395Skan
4417132718Skan      switch (outer_class)
441890075Sobrien	{
4419132718Skan	case MODE_INT:
4420132718Skan	case MODE_PARTIAL_INT:
4421132718Skan	  {
4422132718Skan	    unsigned HOST_WIDE_INT hi = 0, lo = 0;
442390075Sobrien
4424132718Skan	    for (i = 0;
4425132718Skan		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
4426132718Skan		 i += value_bit)
4427132718Skan	      lo |= (HOST_WIDE_INT)(*vp++ & value_mask) << i;
4428132718Skan	    for (; i < elem_bitsize; i += value_bit)
4429132718Skan	      hi |= ((HOST_WIDE_INT)(*vp++ & value_mask)
4430132718Skan		     << (i - HOST_BITS_PER_WIDE_INT));
4431132718Skan
4432132718Skan	    /* immed_double_const doesn't call trunc_int_for_mode.  I don't
4433132718Skan	       know why.  */
4434132718Skan	    if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
4435132718Skan	      elems[elem] = gen_int_mode (lo, outer_submode);
4436169689Skan	    else if (elem_bitsize <= 2 * HOST_BITS_PER_WIDE_INT)
4437169689Skan	      elems[elem] = immed_double_const (lo, hi, outer_submode);
4438132718Skan	    else
4439169689Skan	      return NULL_RTX;
4440132718Skan	  }
4441132718Skan	  break;
4442132718Skan
4443132718Skan	case MODE_FLOAT:
4444169689Skan	case MODE_DECIMAL_FLOAT:
4445132718Skan	  {
4446132718Skan	    REAL_VALUE_TYPE r;
4447132718Skan	    long tmp[max_bitsize / 32];
4448132718Skan
4449132718Skan	    /* real_from_target wants its input in words affected by
4450132718Skan	       FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
4451132718Skan	       and use WORDS_BIG_ENDIAN instead; see the documentation
4452132718Skan	       of SUBREG in rtl.texi.  */
4453132718Skan	    for (i = 0; i < max_bitsize / 32; i++)
4454132718Skan	      tmp[i] = 0;
4455132718Skan	    for (i = 0; i < elem_bitsize; i += value_bit)
4456132718Skan	      {
4457132718Skan		int ibase;
4458132718Skan		if (WORDS_BIG_ENDIAN)
4459132718Skan		  ibase = elem_bitsize - 1 - i;
4460132718Skan		else
4461132718Skan		  ibase = i;
4462132718Skan		tmp[ibase / 32] |= (*vp++ & value_mask) << i % 32;
4463132718Skan	      }
446490075Sobrien
4465132718Skan	    real_from_target (&r, tmp, outer_submode);
4466132718Skan	    elems[elem] = CONST_DOUBLE_FROM_REAL_VALUE (r, outer_submode);
4467132718Skan	  }
4468132718Skan	  break;
4469132718Skan
4470132718Skan	default:
4471169689Skan	  gcc_unreachable ();
4472132718Skan	}
4473132718Skan    }
4474132718Skan  if (VECTOR_MODE_P (outermode))
4475132718Skan    return gen_rtx_CONST_VECTOR (outermode, result_v);
4476132718Skan  else
4477132718Skan    return result_s;
4478132718Skan}
447990075Sobrien
4480132718Skan/* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
4481132718Skan   Return 0 if no simplifications are possible.  */
4482132718Skanrtx
4483132718Skansimplify_subreg (enum machine_mode outermode, rtx op,
4484132718Skan		 enum machine_mode innermode, unsigned int byte)
4485132718Skan{
4486132718Skan  /* Little bit of sanity checking.  */
4487169689Skan  gcc_assert (innermode != VOIDmode);
4488169689Skan  gcc_assert (outermode != VOIDmode);
4489169689Skan  gcc_assert (innermode != BLKmode);
4490169689Skan  gcc_assert (outermode != BLKmode);
449190075Sobrien
4492169689Skan  gcc_assert (GET_MODE (op) == innermode
4493169689Skan	      || GET_MODE (op) == VOIDmode);
449490075Sobrien
4495169689Skan  gcc_assert ((byte % GET_MODE_SIZE (outermode)) == 0);
4496169689Skan  gcc_assert (byte < GET_MODE_SIZE (innermode));
449790075Sobrien
4498132718Skan  if (outermode == innermode && !byte)
4499132718Skan    return op;
450090075Sobrien
4501132718Skan  if (GET_CODE (op) == CONST_INT
4502132718Skan      || GET_CODE (op) == CONST_DOUBLE
4503132718Skan      || GET_CODE (op) == CONST_VECTOR)
4504132718Skan    return simplify_immed_subreg (outermode, op, innermode, byte);
450590075Sobrien
450690075Sobrien  /* Changing mode twice with SUBREG => just change it once,
450790075Sobrien     or not at all if changing back op starting mode.  */
450890075Sobrien  if (GET_CODE (op) == SUBREG)
450990075Sobrien    {
451090075Sobrien      enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
451190075Sobrien      int final_offset = byte + SUBREG_BYTE (op);
4512169689Skan      rtx newx;
451390075Sobrien
451490075Sobrien      if (outermode == innermostmode
451590075Sobrien	  && byte == 0 && SUBREG_BYTE (op) == 0)
451690075Sobrien	return SUBREG_REG (op);
451790075Sobrien
451890075Sobrien      /* The SUBREG_BYTE represents offset, as if the value were stored
451990075Sobrien	 in memory.  Irritating exception is paradoxical subreg, where
452090075Sobrien	 we define SUBREG_BYTE to be 0.  On big endian machines, this
452190075Sobrien	 value should be negative.  For a moment, undo this exception.  */
452290075Sobrien      if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
452390075Sobrien	{
452490075Sobrien	  int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
452590075Sobrien	  if (WORDS_BIG_ENDIAN)
452690075Sobrien	    final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
452790075Sobrien	  if (BYTES_BIG_ENDIAN)
452890075Sobrien	    final_offset += difference % UNITS_PER_WORD;
452990075Sobrien	}
453090075Sobrien      if (SUBREG_BYTE (op) == 0
453190075Sobrien	  && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
453290075Sobrien	{
453390075Sobrien	  int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
453490075Sobrien	  if (WORDS_BIG_ENDIAN)
453590075Sobrien	    final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
453690075Sobrien	  if (BYTES_BIG_ENDIAN)
453790075Sobrien	    final_offset += difference % UNITS_PER_WORD;
453890075Sobrien	}
453990075Sobrien
454090075Sobrien      /* See whether resulting subreg will be paradoxical.  */
454190075Sobrien      if (GET_MODE_SIZE (innermostmode) > GET_MODE_SIZE (outermode))
454290075Sobrien	{
454390075Sobrien	  /* In nonparadoxical subregs we can't handle negative offsets.  */
454490075Sobrien	  if (final_offset < 0)
454590075Sobrien	    return NULL_RTX;
454690075Sobrien	  /* Bail out in case resulting subreg would be incorrect.  */
454790075Sobrien	  if (final_offset % GET_MODE_SIZE (outermode)
454890075Sobrien	      || (unsigned) final_offset >= GET_MODE_SIZE (innermostmode))
454990075Sobrien	    return NULL_RTX;
455090075Sobrien	}
455190075Sobrien      else
455290075Sobrien	{
455390075Sobrien	  int offset = 0;
455490075Sobrien	  int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode));
455590075Sobrien
455690075Sobrien	  /* In paradoxical subreg, see if we are still looking on lower part.
455790075Sobrien	     If so, our SUBREG_BYTE will be 0.  */
455890075Sobrien	  if (WORDS_BIG_ENDIAN)
455990075Sobrien	    offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
456090075Sobrien	  if (BYTES_BIG_ENDIAN)
456190075Sobrien	    offset += difference % UNITS_PER_WORD;
456290075Sobrien	  if (offset == final_offset)
456390075Sobrien	    final_offset = 0;
456490075Sobrien	  else
456590075Sobrien	    return NULL_RTX;
456690075Sobrien	}
456790075Sobrien
4568132718Skan      /* Recurse for further possible simplifications.  */
4569169689Skan      newx = simplify_subreg (outermode, SUBREG_REG (op), innermostmode,
4570169689Skan			      final_offset);
4571169689Skan      if (newx)
4572169689Skan	return newx;
4573169689Skan      if (validate_subreg (outermode, innermostmode,
4574169689Skan			   SUBREG_REG (op), final_offset))
4575169689Skan        return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
4576169689Skan      return NULL_RTX;
457790075Sobrien    }
457890075Sobrien
4579169689Skan  /* Merge implicit and explicit truncations.  */
4580169689Skan
4581169689Skan  if (GET_CODE (op) == TRUNCATE
4582169689Skan      && GET_MODE_SIZE (outermode) < GET_MODE_SIZE (innermode)
4583169689Skan      && subreg_lowpart_offset (outermode, innermode) == byte)
4584169689Skan    return simplify_gen_unary (TRUNCATE, outermode, XEXP (op, 0),
4585169689Skan			       GET_MODE (XEXP (op, 0)));
4586169689Skan
458790075Sobrien  /* SUBREG of a hard register => just change the register number
458890075Sobrien     and/or mode.  If the hard register is not valid in that mode,
458990075Sobrien     suppress this simplification.  If the hard register is the stack,
459090075Sobrien     frame, or argument pointer, leave this as a SUBREG.  */
459190075Sobrien
459290075Sobrien  if (REG_P (op)
4593117395Skan      && REGNO (op) < FIRST_PSEUDO_REGISTER
4594117395Skan#ifdef CANNOT_CHANGE_MODE_CLASS
4595117395Skan      && ! (REG_CANNOT_CHANGE_MODE_P (REGNO (op), innermode, outermode)
459690075Sobrien	    && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT
4597117395Skan	    && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT)
459890075Sobrien#endif
459990075Sobrien      && ((reload_completed && !frame_pointer_needed)
460090075Sobrien	  || (REGNO (op) != FRAME_POINTER_REGNUM
460190075Sobrien#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
460290075Sobrien	      && REGNO (op) != HARD_FRAME_POINTER_REGNUM
460390075Sobrien#endif
460490075Sobrien	     ))
460590075Sobrien#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
460690075Sobrien      && REGNO (op) != ARG_POINTER_REGNUM
460790075Sobrien#endif
4608132718Skan      && REGNO (op) != STACK_POINTER_REGNUM
4609132718Skan      && subreg_offset_representable_p (REGNO (op), innermode,
4610132718Skan					byte, outermode))
461190075Sobrien    {
4612169689Skan      unsigned int regno = REGNO (op);
4613169689Skan      unsigned int final_regno
4614169689Skan	= regno + subreg_regno_offset (regno, innermode, byte, outermode);
461590075Sobrien
461690075Sobrien      /* ??? We do allow it if the current REG is not valid for
461790075Sobrien	 its mode.  This is a kludge to work around how float/complex
4618117395Skan	 arguments are passed on 32-bit SPARC and should be fixed.  */
461990075Sobrien      if (HARD_REGNO_MODE_OK (final_regno, outermode)
4620169689Skan	  || ! HARD_REGNO_MODE_OK (regno, innermode))
462190075Sobrien	{
4622169689Skan	  rtx x;
4623169689Skan	  int final_offset = byte;
462490075Sobrien
4625169689Skan	  /* Adjust offset for paradoxical subregs.  */
4626169689Skan	  if (byte == 0
4627169689Skan	      && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
4628169689Skan	    {
4629169689Skan	      int difference = (GET_MODE_SIZE (innermode)
4630169689Skan				- GET_MODE_SIZE (outermode));
4631169689Skan	      if (WORDS_BIG_ENDIAN)
4632169689Skan		final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
4633169689Skan	      if (BYTES_BIG_ENDIAN)
4634169689Skan		final_offset += difference % UNITS_PER_WORD;
4635169689Skan	    }
4636169689Skan
4637169689Skan	  x = gen_rtx_REG_offset (op, outermode, final_regno, final_offset);
4638169689Skan
463990075Sobrien	  /* Propagate original regno.  We don't have any way to specify
4640132718Skan	     the offset inside original regno, so do so only for lowpart.
464190075Sobrien	     The information is used only by alias analysis that can not
464290075Sobrien	     grog partial register anyway.  */
464390075Sobrien
464490075Sobrien	  if (subreg_lowpart_offset (outermode, innermode) == byte)
464590075Sobrien	    ORIGINAL_REGNO (x) = ORIGINAL_REGNO (op);
464690075Sobrien	  return x;
464790075Sobrien	}
464890075Sobrien    }
464990075Sobrien
465090075Sobrien  /* If we have a SUBREG of a register that we are replacing and we are
465190075Sobrien     replacing it with a MEM, make a new MEM and try replacing the
465290075Sobrien     SUBREG with it.  Don't do this if the MEM has a mode-dependent address
465390075Sobrien     or if we would be widening it.  */
465490075Sobrien
4655169689Skan  if (MEM_P (op)
465690075Sobrien      && ! mode_dependent_address_p (XEXP (op, 0))
465790075Sobrien      /* Allow splitting of volatile memory references in case we don't
465890075Sobrien         have instruction to move the whole thing.  */
465990075Sobrien      && (! MEM_VOLATILE_P (op)
466090075Sobrien	  || ! have_insn_for (SET, innermode))
466190075Sobrien      && GET_MODE_SIZE (outermode) <= GET_MODE_SIZE (GET_MODE (op)))
466290075Sobrien    return adjust_address_nv (op, outermode, byte);
466390075Sobrien
466490075Sobrien  /* Handle complex values represented as CONCAT
466590075Sobrien     of real and imaginary part.  */
466690075Sobrien  if (GET_CODE (op) == CONCAT)
466790075Sobrien    {
4668169689Skan      unsigned int inner_size, final_offset;
4669169689Skan      rtx part, res;
467090075Sobrien
4671169689Skan      inner_size = GET_MODE_UNIT_SIZE (innermode);
4672169689Skan      part = byte < inner_size ? XEXP (op, 0) : XEXP (op, 1);
4673169689Skan      final_offset = byte % inner_size;
4674169689Skan      if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
4675169689Skan	return NULL_RTX;
4676169689Skan
467790075Sobrien      res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
467890075Sobrien      if (res)
467990075Sobrien	return res;
4680169689Skan      if (validate_subreg (outermode, GET_MODE (part), part, final_offset))
4681169689Skan	return gen_rtx_SUBREG (outermode, part, final_offset);
4682169689Skan      return NULL_RTX;
468390075Sobrien    }
468490075Sobrien
4685169689Skan  /* Optimize SUBREG truncations of zero and sign extended values.  */
4686169689Skan  if ((GET_CODE (op) == ZERO_EXTEND
4687169689Skan       || GET_CODE (op) == SIGN_EXTEND)
4688169689Skan      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode))
4689169689Skan    {
4690169689Skan      unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
4691169689Skan
4692169689Skan      /* If we're requesting the lowpart of a zero or sign extension,
4693169689Skan	 there are three possibilities.  If the outermode is the same
4694169689Skan	 as the origmode, we can omit both the extension and the subreg.
4695169689Skan	 If the outermode is not larger than the origmode, we can apply
4696169689Skan	 the truncation without the extension.  Finally, if the outermode
4697169689Skan	 is larger than the origmode, but both are integer modes, we
4698169689Skan	 can just extend to the appropriate mode.  */
4699169689Skan      if (bitpos == 0)
4700169689Skan	{
4701169689Skan	  enum machine_mode origmode = GET_MODE (XEXP (op, 0));
4702169689Skan	  if (outermode == origmode)
4703169689Skan	    return XEXP (op, 0);
4704169689Skan	  if (GET_MODE_BITSIZE (outermode) <= GET_MODE_BITSIZE (origmode))
4705169689Skan	    return simplify_gen_subreg (outermode, XEXP (op, 0), origmode,
4706169689Skan					subreg_lowpart_offset (outermode,
4707169689Skan							       origmode));
4708169689Skan	  if (SCALAR_INT_MODE_P (outermode))
4709169689Skan	    return simplify_gen_unary (GET_CODE (op), outermode,
4710169689Skan				       XEXP (op, 0), origmode);
4711169689Skan	}
4712169689Skan
4713169689Skan      /* A SUBREG resulting from a zero extension may fold to zero if
4714169689Skan	 it extracts higher bits that the ZERO_EXTEND's source bits.  */
4715169689Skan      if (GET_CODE (op) == ZERO_EXTEND
4716169689Skan	  && bitpos >= GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))))
4717169689Skan	return CONST0_RTX (outermode);
4718169689Skan    }
4719169689Skan
4720169689Skan  /* Simplify (subreg:QI (lshiftrt:SI (sign_extend:SI (x:QI)) C), 0) into
4721169689Skan     to (ashiftrt:QI (x:QI) C), where C is a suitable small constant and
4722169689Skan     the outer subreg is effectively a truncation to the original mode.  */
4723169689Skan  if ((GET_CODE (op) == LSHIFTRT
4724169689Skan       || GET_CODE (op) == ASHIFTRT)
4725169689Skan      && SCALAR_INT_MODE_P (outermode)
4726169689Skan      /* Ensure that OUTERMODE is at least twice as wide as the INNERMODE
4727169689Skan	 to avoid the possibility that an outer LSHIFTRT shifts by more
4728169689Skan	 than the sign extension's sign_bit_copies and introduces zeros
4729169689Skan	 into the high bits of the result.  */
4730169689Skan      && (2 * GET_MODE_BITSIZE (outermode)) <= GET_MODE_BITSIZE (innermode)
4731169689Skan      && GET_CODE (XEXP (op, 1)) == CONST_INT
4732169689Skan      && GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
4733169689Skan      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
4734169689Skan      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
4735169689Skan      && subreg_lsb_1 (outermode, innermode, byte) == 0)
4736169689Skan    return simplify_gen_binary (ASHIFTRT, outermode,
4737169689Skan				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
4738169689Skan
4739169689Skan  /* Likewise (subreg:QI (lshiftrt:SI (zero_extend:SI (x:QI)) C), 0) into
4740169689Skan     to (lshiftrt:QI (x:QI) C), where C is a suitable small constant and
4741169689Skan     the outer subreg is effectively a truncation to the original mode.  */
4742169689Skan  if ((GET_CODE (op) == LSHIFTRT
4743169689Skan       || GET_CODE (op) == ASHIFTRT)
4744169689Skan      && SCALAR_INT_MODE_P (outermode)
4745169689Skan      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
4746169689Skan      && GET_CODE (XEXP (op, 1)) == CONST_INT
4747169689Skan      && GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
4748169689Skan      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
4749169689Skan      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
4750169689Skan      && subreg_lsb_1 (outermode, innermode, byte) == 0)
4751169689Skan    return simplify_gen_binary (LSHIFTRT, outermode,
4752169689Skan				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
4753169689Skan
4754169689Skan  /* Likewise (subreg:QI (ashift:SI (zero_extend:SI (x:QI)) C), 0) into
4755169689Skan     to (ashift:QI (x:QI) C), where C is a suitable small constant and
4756169689Skan     the outer subreg is effectively a truncation to the original mode.  */
4757169689Skan  if (GET_CODE (op) == ASHIFT
4758169689Skan      && SCALAR_INT_MODE_P (outermode)
4759169689Skan      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
4760169689Skan      && GET_CODE (XEXP (op, 1)) == CONST_INT
4761169689Skan      && (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
4762169689Skan	  || GET_CODE (XEXP (op, 0)) == SIGN_EXTEND)
4763169689Skan      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
4764169689Skan      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
4765169689Skan      && subreg_lsb_1 (outermode, innermode, byte) == 0)
4766169689Skan    return simplify_gen_binary (ASHIFT, outermode,
4767169689Skan				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
4768169689Skan
476990075Sobrien  return NULL_RTX;
477090075Sobrien}
4771132718Skan
477290075Sobrien/* Make a SUBREG operation or equivalent if it folds.  */
477390075Sobrien
477490075Sobrienrtx
4775132718Skansimplify_gen_subreg (enum machine_mode outermode, rtx op,
4776132718Skan		     enum machine_mode innermode, unsigned int byte)
477790075Sobrien{
4778169689Skan  rtx newx;
477990075Sobrien
4780169689Skan  newx = simplify_subreg (outermode, op, innermode, byte);
4781169689Skan  if (newx)
4782169689Skan    return newx;
478390075Sobrien
4784169689Skan  if (GET_CODE (op) == SUBREG
4785169689Skan      || GET_CODE (op) == CONCAT
4786169689Skan      || GET_MODE (op) == VOIDmode)
478790075Sobrien    return NULL_RTX;
478890075Sobrien
4789169689Skan  if (validate_subreg (outermode, innermode, op, byte))
4790169689Skan    return gen_rtx_SUBREG (outermode, op, byte);
479190075Sobrien
4792169689Skan  return NULL_RTX;
4793169689Skan}
479490075Sobrien
479590075Sobrien/* Simplify X, an rtx expression.
479690075Sobrien
479790075Sobrien   Return the simplified expression or NULL if no simplifications
479890075Sobrien   were possible.
479990075Sobrien
480090075Sobrien   This is the preferred entry point into the simplification routines;
480190075Sobrien   however, we still allow passes to call the more specific routines.
480290075Sobrien
4803132718Skan   Right now GCC has three (yes, three) major bodies of RTL simplification
480490075Sobrien   code that need to be unified.
480590075Sobrien
480690075Sobrien	1. fold_rtx in cse.c.  This code uses various CSE specific
480790075Sobrien	   information to aid in RTL simplification.
480890075Sobrien
480990075Sobrien	2. simplify_rtx in combine.c.  Similar to fold_rtx, except that
481090075Sobrien	   it uses combine specific information to aid in RTL
481190075Sobrien	   simplification.
481290075Sobrien
481390075Sobrien	3. The routines in this file.
481490075Sobrien
481590075Sobrien
481690075Sobrien   Long term we want to only have one body of simplification code; to
481790075Sobrien   get to that state I recommend the following steps:
481890075Sobrien
481990075Sobrien	1. Pour over fold_rtx & simplify_rtx and move any simplifications
482090075Sobrien	   which are not pass dependent state into these routines.
482190075Sobrien
482290075Sobrien	2. As code is moved by #1, change fold_rtx & simplify_rtx to
482390075Sobrien	   use this routine whenever possible.
482490075Sobrien
482590075Sobrien	3. Allow for pass dependent state to be provided to these
482690075Sobrien	   routines and add simplifications based on the pass dependent
482790075Sobrien	   state.  Remove code from cse.c & combine.c that becomes
482890075Sobrien	   redundant/dead.
482990075Sobrien
483090075Sobrien    It will take time, but ultimately the compiler will be easier to
483190075Sobrien    maintain and improve.  It's totally silly that when we add a
483290075Sobrien    simplification that it needs to be added to 4 places (3 for RTL
483390075Sobrien    simplification and 1 for tree simplification.  */
4834117395Skan
483590075Sobrienrtx
4836132718Skansimplify_rtx (rtx x)
483790075Sobrien{
483890075Sobrien  enum rtx_code code = GET_CODE (x);
483990075Sobrien  enum machine_mode mode = GET_MODE (x);
484090075Sobrien
484190075Sobrien  switch (GET_RTX_CLASS (code))
484290075Sobrien    {
4843169689Skan    case RTX_UNARY:
484490075Sobrien      return simplify_unary_operation (code, mode,
484590075Sobrien				       XEXP (x, 0), GET_MODE (XEXP (x, 0)));
4846169689Skan    case RTX_COMM_ARITH:
484790075Sobrien      if (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
4848132718Skan	return simplify_gen_binary (code, mode, XEXP (x, 1), XEXP (x, 0));
484990075Sobrien
4850132718Skan      /* Fall through....  */
485190075Sobrien
4852169689Skan    case RTX_BIN_ARITH:
485390075Sobrien      return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
485490075Sobrien
4855169689Skan    case RTX_TERNARY:
4856169689Skan    case RTX_BITFIELD_OPS:
485790075Sobrien      return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)),
485890075Sobrien					 XEXP (x, 0), XEXP (x, 1),
485990075Sobrien					 XEXP (x, 2));
486090075Sobrien
4861169689Skan    case RTX_COMPARE:
4862169689Skan    case RTX_COMM_COMPARE:
4863169689Skan      return simplify_relational_operation (code, mode,
4864169689Skan                                            ((GET_MODE (XEXP (x, 0))
4865169689Skan                                             != VOIDmode)
4866169689Skan                                            ? GET_MODE (XEXP (x, 0))
4867169689Skan                                            : GET_MODE (XEXP (x, 1))),
4868169689Skan                                            XEXP (x, 0),
4869169689Skan                                            XEXP (x, 1));
4870132718Skan
4871169689Skan    case RTX_EXTRA:
487290075Sobrien      if (code == SUBREG)
4873117395Skan	return simplify_gen_subreg (mode, SUBREG_REG (x),
487490075Sobrien				    GET_MODE (SUBREG_REG (x)),
487590075Sobrien				    SUBREG_BYTE (x));
4876132718Skan      break;
4877132718Skan
4878169689Skan    case RTX_OBJ:
4879132718Skan      if (code == LO_SUM)
4880132718Skan	{
4881132718Skan	  /* Convert (lo_sum (high FOO) FOO) to FOO.  */
4882132718Skan	  if (GET_CODE (XEXP (x, 0)) == HIGH
4883132718Skan	      && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1)))
4884132718Skan	  return XEXP (x, 1);
4885132718Skan	}
4886132718Skan      break;
4887132718Skan
488890075Sobrien    default:
4889132718Skan      break;
489090075Sobrien    }
4891132718Skan  return NULL;
489290075Sobrien}
4893