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
104790075Sobrien	case TRUNCATE:
104890075Sobrien	  val = arg0;
104990075Sobrien	  break;
105090075Sobrien
105190075Sobrien	case ZERO_EXTEND:
105296263Sobrien	  /* When zero-extending a CONST_INT, we need to know its
105396263Sobrien             original mode.  */
1054169689Skan	  gcc_assert (op_mode != VOIDmode);
105590075Sobrien	  if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
105690075Sobrien	    {
105790075Sobrien	      /* If we were really extending the mode,
105890075Sobrien		 we would have to distinguish between zero-extension
105990075Sobrien		 and sign-extension.  */
1060169689Skan	      gcc_assert (width == GET_MODE_BITSIZE (op_mode));
106190075Sobrien	      val = arg0;
106290075Sobrien	    }
106390075Sobrien	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
106490075Sobrien	    val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
106590075Sobrien	  else
106690075Sobrien	    return 0;
106790075Sobrien	  break;
106890075Sobrien
106990075Sobrien	case SIGN_EXTEND:
107090075Sobrien	  if (op_mode == VOIDmode)
107190075Sobrien	    op_mode = mode;
107290075Sobrien	  if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
107390075Sobrien	    {
107490075Sobrien	      /* If we were really extending the mode,
107590075Sobrien		 we would have to distinguish between zero-extension
107690075Sobrien		 and sign-extension.  */
1077169689Skan	      gcc_assert (width == GET_MODE_BITSIZE (op_mode));
107890075Sobrien	      val = arg0;
107990075Sobrien	    }
108090075Sobrien	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
108190075Sobrien	    {
108290075Sobrien	      val
108390075Sobrien		= arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
108490075Sobrien	      if (val
108590075Sobrien		  & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1)))
108690075Sobrien		val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
108790075Sobrien	    }
108890075Sobrien	  else
108990075Sobrien	    return 0;
109090075Sobrien	  break;
109190075Sobrien
109290075Sobrien	case SQRT:
109390075Sobrien	case FLOAT_EXTEND:
109490075Sobrien	case FLOAT_TRUNCATE:
109590075Sobrien	case SS_TRUNCATE:
109690075Sobrien	case US_TRUNCATE:
1097169689Skan	case SS_NEG:
109890075Sobrien	  return 0;
109990075Sobrien
110090075Sobrien	default:
1101169689Skan	  gcc_unreachable ();
110290075Sobrien	}
110390075Sobrien
1104169689Skan      return gen_int_mode (val, mode);
110590075Sobrien    }
110690075Sobrien
110790075Sobrien  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
110890075Sobrien     for a DImode operation on a CONST_INT.  */
1109169689Skan  else if (GET_MODE (op) == VOIDmode
111096263Sobrien	   && width <= HOST_BITS_PER_WIDE_INT * 2
1111169689Skan	   && (GET_CODE (op) == CONST_DOUBLE
1112169689Skan	       || GET_CODE (op) == CONST_INT))
111390075Sobrien    {
111490075Sobrien      unsigned HOST_WIDE_INT l1, lv;
111590075Sobrien      HOST_WIDE_INT h1, hv;
111690075Sobrien
1117169689Skan      if (GET_CODE (op) == CONST_DOUBLE)
1118169689Skan	l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
111990075Sobrien      else
1120169689Skan	l1 = INTVAL (op), h1 = HWI_SIGN_EXTEND (l1);
112190075Sobrien
112290075Sobrien      switch (code)
112390075Sobrien	{
112490075Sobrien	case NOT:
112590075Sobrien	  lv = ~ l1;
112690075Sobrien	  hv = ~ h1;
112790075Sobrien	  break;
112890075Sobrien
112990075Sobrien	case NEG:
113090075Sobrien	  neg_double (l1, h1, &lv, &hv);
113190075Sobrien	  break;
113290075Sobrien
113390075Sobrien	case ABS:
113490075Sobrien	  if (h1 < 0)
113590075Sobrien	    neg_double (l1, h1, &lv, &hv);
113690075Sobrien	  else
113790075Sobrien	    lv = l1, hv = h1;
113890075Sobrien	  break;
113990075Sobrien
114090075Sobrien	case FFS:
114190075Sobrien	  hv = 0;
114290075Sobrien	  if (l1 == 0)
1143132718Skan	    {
1144132718Skan	      if (h1 == 0)
1145132718Skan		lv = 0;
1146132718Skan	      else
1147132718Skan		lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & -h1) + 1;
1148132718Skan	    }
114990075Sobrien	  else
1150132718Skan	    lv = exact_log2 (l1 & -l1) + 1;
115190075Sobrien	  break;
115290075Sobrien
1153132718Skan	case CLZ:
1154132718Skan	  hv = 0;
1155132718Skan	  if (h1 != 0)
1156132718Skan	    lv = GET_MODE_BITSIZE (mode) - floor_log2 (h1) - 1
1157132718Skan	      - HOST_BITS_PER_WIDE_INT;
1158132718Skan	  else if (l1 != 0)
1159132718Skan	    lv = GET_MODE_BITSIZE (mode) - floor_log2 (l1) - 1;
1160132718Skan	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, lv))
1161132718Skan	    lv = GET_MODE_BITSIZE (mode);
1162132718Skan	  break;
1163132718Skan
1164132718Skan	case CTZ:
1165132718Skan	  hv = 0;
1166132718Skan	  if (l1 != 0)
1167132718Skan	    lv = exact_log2 (l1 & -l1);
1168132718Skan	  else if (h1 != 0)
1169132718Skan	    lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & -h1);
1170132718Skan	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, lv))
1171132718Skan	    lv = GET_MODE_BITSIZE (mode);
1172132718Skan	  break;
1173132718Skan
1174132718Skan	case POPCOUNT:
1175132718Skan	  hv = 0;
1176132718Skan	  lv = 0;
1177132718Skan	  while (l1)
1178132718Skan	    lv++, l1 &= l1 - 1;
1179132718Skan	  while (h1)
1180132718Skan	    lv++, h1 &= h1 - 1;
1181132718Skan	  break;
1182132718Skan
1183132718Skan	case PARITY:
1184132718Skan	  hv = 0;
1185132718Skan	  lv = 0;
1186132718Skan	  while (l1)
1187132718Skan	    lv++, l1 &= l1 - 1;
1188132718Skan	  while (h1)
1189132718Skan	    lv++, h1 &= h1 - 1;
1190132718Skan	  lv &= 1;
1191132718Skan	  break;
1192132718Skan
119390075Sobrien	case TRUNCATE:
119490075Sobrien	  /* This is just a change-of-mode, so do nothing.  */
119590075Sobrien	  lv = l1, hv = h1;
119690075Sobrien	  break;
119790075Sobrien
119890075Sobrien	case ZERO_EXTEND:
1199169689Skan	  gcc_assert (op_mode != VOIDmode);
120096263Sobrien
120196263Sobrien	  if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
120290075Sobrien	    return 0;
120390075Sobrien
120490075Sobrien	  hv = 0;
120590075Sobrien	  lv = l1 & GET_MODE_MASK (op_mode);
120690075Sobrien	  break;
120790075Sobrien
120890075Sobrien	case SIGN_EXTEND:
120990075Sobrien	  if (op_mode == VOIDmode
121090075Sobrien	      || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
121190075Sobrien	    return 0;
121290075Sobrien	  else
121390075Sobrien	    {
121490075Sobrien	      lv = l1 & GET_MODE_MASK (op_mode);
121590075Sobrien	      if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
121690075Sobrien		  && (lv & ((HOST_WIDE_INT) 1
121790075Sobrien			    << (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
121890075Sobrien		lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
121990075Sobrien
122090075Sobrien	      hv = HWI_SIGN_EXTEND (lv);
122190075Sobrien	    }
122290075Sobrien	  break;
122390075Sobrien
122490075Sobrien	case SQRT:
122590075Sobrien	  return 0;
122690075Sobrien
122790075Sobrien	default:
122890075Sobrien	  return 0;
122990075Sobrien	}
123090075Sobrien
123190075Sobrien      return immed_double_const (lv, hv, mode);
123290075Sobrien    }
123390075Sobrien
1234169689Skan  else if (GET_CODE (op) == CONST_DOUBLE
1235169689Skan	   && SCALAR_FLOAT_MODE_P (mode))
123690075Sobrien    {
1237132718Skan      REAL_VALUE_TYPE d, t;
1238169689Skan      REAL_VALUE_FROM_CONST_DOUBLE (d, op);
123990075Sobrien
1240117395Skan      switch (code)
1241117395Skan	{
1242117395Skan	case SQRT:
1243132718Skan	  if (HONOR_SNANS (mode) && real_isnan (&d))
1244132718Skan	    return 0;
1245132718Skan	  real_sqrt (&t, mode, &d);
1246132718Skan	  d = t;
1247132718Skan	  break;
1248117395Skan	case ABS:
1249117395Skan	  d = REAL_VALUE_ABS (d);
1250117395Skan	  break;
1251117395Skan	case NEG:
1252117395Skan	  d = REAL_VALUE_NEGATE (d);
1253117395Skan	  break;
1254117395Skan	case FLOAT_TRUNCATE:
1255117395Skan	  d = real_value_truncate (mode, d);
1256117395Skan	  break;
1257117395Skan	case FLOAT_EXTEND:
1258117395Skan	  /* All this does is change the mode.  */
1259117395Skan	  break;
1260117395Skan	case FIX:
1261117395Skan	  real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
1262117395Skan	  break;
1263146895Skan	case NOT:
1264146895Skan	  {
1265146895Skan	    long tmp[4];
1266146895Skan	    int i;
1267117395Skan
1268169689Skan	    real_to_target (tmp, &d, GET_MODE (op));
1269146895Skan	    for (i = 0; i < 4; i++)
1270146895Skan	      tmp[i] = ~tmp[i];
1271146895Skan	    real_from_target (&d, tmp, mode);
1272146895Skan	    break;
1273146895Skan	  }
1274117395Skan	default:
1275169689Skan	  gcc_unreachable ();
1276117395Skan	}
1277117395Skan      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
127890075Sobrien    }
127990075Sobrien
1280169689Skan  else if (GET_CODE (op) == CONST_DOUBLE
1281169689Skan	   && SCALAR_FLOAT_MODE_P (GET_MODE (op))
128290075Sobrien	   && GET_MODE_CLASS (mode) == MODE_INT
1283132718Skan	   && width <= 2*HOST_BITS_PER_WIDE_INT && width > 0)
128490075Sobrien    {
1285132718Skan      /* Although the overflow semantics of RTL's FIX and UNSIGNED_FIX
1286132718Skan	 operators are intentionally left unspecified (to ease implementation
1287132718Skan	 by target backends), for consistency, this routine implements the
1288132718Skan	 same semantics for constant folding as used by the middle-end.  */
1289132718Skan
1290169689Skan      /* This was formerly used only for non-IEEE float.
1291169689Skan	 eggert@twinsun.com says it is safe for IEEE also.  */
1292132718Skan      HOST_WIDE_INT xh, xl, th, tl;
1293132718Skan      REAL_VALUE_TYPE x, t;
1294169689Skan      REAL_VALUE_FROM_CONST_DOUBLE (x, op);
1295117395Skan      switch (code)
1296117395Skan	{
1297132718Skan	case FIX:
1298132718Skan	  if (REAL_VALUE_ISNAN (x))
1299132718Skan	    return const0_rtx;
1300132718Skan
1301132718Skan	  /* Test against the signed upper bound.  */
1302132718Skan	  if (width > HOST_BITS_PER_WIDE_INT)
1303132718Skan	    {
1304132718Skan	      th = ((unsigned HOST_WIDE_INT) 1
1305132718Skan		    << (width - HOST_BITS_PER_WIDE_INT - 1)) - 1;
1306132718Skan	      tl = -1;
1307132718Skan	    }
1308132718Skan	  else
1309132718Skan	    {
1310132718Skan	      th = 0;
1311132718Skan	      tl = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1;
1312132718Skan	    }
1313132718Skan	  real_from_integer (&t, VOIDmode, tl, th, 0);
1314132718Skan	  if (REAL_VALUES_LESS (t, x))
1315132718Skan	    {
1316132718Skan	      xh = th;
1317132718Skan	      xl = tl;
1318132718Skan	      break;
1319132718Skan	    }
1320132718Skan
1321132718Skan	  /* Test against the signed lower bound.  */
1322132718Skan	  if (width > HOST_BITS_PER_WIDE_INT)
1323132718Skan	    {
1324132718Skan	      th = (HOST_WIDE_INT) -1 << (width - HOST_BITS_PER_WIDE_INT - 1);
1325132718Skan	      tl = 0;
1326132718Skan	    }
1327132718Skan	  else
1328132718Skan	    {
1329132718Skan	      th = -1;
1330132718Skan	      tl = (HOST_WIDE_INT) -1 << (width - 1);
1331132718Skan	    }
1332132718Skan	  real_from_integer (&t, VOIDmode, tl, th, 0);
1333132718Skan	  if (REAL_VALUES_LESS (x, t))
1334132718Skan	    {
1335132718Skan	      xh = th;
1336132718Skan	      xl = tl;
1337132718Skan	      break;
1338132718Skan	    }
1339132718Skan	  REAL_VALUE_TO_INT (&xl, &xh, x);
1340132718Skan	  break;
1341132718Skan
1342132718Skan	case UNSIGNED_FIX:
1343132718Skan	  if (REAL_VALUE_ISNAN (x) || REAL_VALUE_NEGATIVE (x))
1344132718Skan	    return const0_rtx;
1345132718Skan
1346132718Skan	  /* Test against the unsigned upper bound.  */
1347132718Skan	  if (width == 2*HOST_BITS_PER_WIDE_INT)
1348132718Skan	    {
1349132718Skan	      th = -1;
1350132718Skan	      tl = -1;
1351132718Skan	    }
1352132718Skan	  else if (width >= HOST_BITS_PER_WIDE_INT)
1353132718Skan	    {
1354132718Skan	      th = ((unsigned HOST_WIDE_INT) 1
1355132718Skan		    << (width - HOST_BITS_PER_WIDE_INT)) - 1;
1356132718Skan	      tl = -1;
1357132718Skan	    }
1358132718Skan	  else
1359132718Skan	    {
1360132718Skan	      th = 0;
1361132718Skan	      tl = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
1362132718Skan	    }
1363132718Skan	  real_from_integer (&t, VOIDmode, tl, th, 1);
1364132718Skan	  if (REAL_VALUES_LESS (t, x))
1365132718Skan	    {
1366132718Skan	      xh = th;
1367132718Skan	      xl = tl;
1368132718Skan	      break;
1369132718Skan	    }
1370132718Skan
1371132718Skan	  REAL_VALUE_TO_INT (&xl, &xh, x);
1372132718Skan	  break;
1373132718Skan
1374117395Skan	default:
1375169689Skan	  gcc_unreachable ();
1376117395Skan	}
1377132718Skan      return immed_double_const (xl, xh, mode);
1378117395Skan    }
137990075Sobrien
1380169689Skan  return NULL_RTX;
1381169689Skan}
1382169689Skan
1383169689Skan/* Subroutine of simplify_binary_operation to simplify a commutative,
1384169689Skan   associative binary operation CODE with result mode MODE, operating
1385169689Skan   on OP0 and OP1.  CODE is currently one of PLUS, MULT, AND, IOR, XOR,
1386169689Skan   SMIN, SMAX, UMIN or UMAX.  Return zero if no simplification or
1387169689Skan   canonicalization is possible.  */
1388169689Skan
1389169689Skanstatic rtx
1390169689Skansimplify_associative_operation (enum rtx_code code, enum machine_mode mode,
1391169689Skan				rtx op0, rtx op1)
1392169689Skan{
1393169689Skan  rtx tem;
1394169689Skan
1395169689Skan  /* Linearize the operator to the left.  */
1396169689Skan  if (GET_CODE (op1) == code)
139790075Sobrien    {
1398169689Skan      /* "(a op b) op (c op d)" becomes "((a op b) op c) op d)".  */
1399169689Skan      if (GET_CODE (op0) == code)
1400169689Skan	{
1401169689Skan	  tem = simplify_gen_binary (code, mode, op0, XEXP (op1, 0));
1402169689Skan	  return simplify_gen_binary (code, mode, tem, XEXP (op1, 1));
1403169689Skan	}
1404132718Skan
1405169689Skan      /* "a op (b op c)" becomes "(b op c) op a".  */
1406169689Skan      if (! swap_commutative_operands_p (op1, op0))
1407169689Skan	return simplify_gen_binary (code, mode, op1, op0);
1408169689Skan
1409169689Skan      tem = op0;
1410169689Skan      op0 = op1;
1411169689Skan      op1 = tem;
1412169689Skan    }
1413169689Skan
1414169689Skan  if (GET_CODE (op0) == code)
1415169689Skan    {
1416169689Skan      /* Canonicalize "(x op c) op y" as "(x op y) op c".  */
1417169689Skan      if (swap_commutative_operands_p (XEXP (op0, 1), op1))
141890075Sobrien	{
1419169689Skan	  tem = simplify_gen_binary (code, mode, XEXP (op0, 0), op1);
1420169689Skan	  return simplify_gen_binary (code, mode, tem, XEXP (op0, 1));
1421169689Skan	}
142290075Sobrien
1423169689Skan      /* Attempt to simplify "(a op b) op c" as "a op (b op c)".  */
1424169689Skan      tem = swap_commutative_operands_p (XEXP (op0, 1), op1)
1425169689Skan	    ? simplify_binary_operation (code, mode, op1, XEXP (op0, 1))
1426169689Skan	    : simplify_binary_operation (code, mode, XEXP (op0, 1), op1);
1427169689Skan      if (tem != 0)
1428169689Skan        return simplify_gen_binary (code, mode, XEXP (op0, 0), tem);
1429132718Skan
1430169689Skan      /* Attempt to simplify "(a op b) op c" as "(a op c) op b".  */
1431169689Skan      tem = swap_commutative_operands_p (XEXP (op0, 0), op1)
1432169689Skan	    ? simplify_binary_operation (code, mode, op1, XEXP (op0, 0))
1433169689Skan	    : simplify_binary_operation (code, mode, XEXP (op0, 0), op1);
1434169689Skan      if (tem != 0)
1435169689Skan        return simplify_gen_binary (code, mode, tem, XEXP (op0, 1));
1436169689Skan    }
1437132718Skan
1438169689Skan  return 0;
1439169689Skan}
1440132718Skan
1441132718Skan
1442169689Skan/* Simplify a binary operation CODE with result mode MODE, operating on OP0
1443169689Skan   and OP1.  Return 0 if no simplification is possible.
1444132718Skan
1445169689Skan   Don't use this for relational operations such as EQ or LT.
1446169689Skan   Use simplify_relational_operation instead.  */
1447169689Skanrtx
1448169689Skansimplify_binary_operation (enum rtx_code code, enum machine_mode mode,
1449169689Skan			   rtx op0, rtx op1)
1450169689Skan{
1451169689Skan  rtx trueop0, trueop1;
1452169689Skan  rtx tem;
1453169689Skan
1454169689Skan  /* Relational operations don't work here.  We must know the mode
1455169689Skan     of the operands in order to do the comparison correctly.
1456169689Skan     Assuming a full word can give incorrect results.
1457169689Skan     Consider comparing 128 with -128 in QImode.  */
1458169689Skan  gcc_assert (GET_RTX_CLASS (code) != RTX_COMPARE);
1459169689Skan  gcc_assert (GET_RTX_CLASS (code) != RTX_COMM_COMPARE);
1460169689Skan
1461169689Skan  /* Make sure the constant is second.  */
1462169689Skan  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
1463169689Skan      && swap_commutative_operands_p (op0, op1))
1464169689Skan    {
1465169689Skan      tem = op0, op0 = op1, op1 = tem;
1466169689Skan    }
1467169689Skan
1468169689Skan  trueop0 = avoid_constant_pool_reference (op0);
1469169689Skan  trueop1 = avoid_constant_pool_reference (op1);
1470169689Skan
1471169689Skan  tem = simplify_const_binary_operation (code, mode, trueop0, trueop1);
1472169689Skan  if (tem)
1473169689Skan    return tem;
1474169689Skan  return simplify_binary_operation_1 (code, mode, op0, op1, trueop0, trueop1);
1475169689Skan}
1476169689Skan
1477169689Skan/* Subroutine of simplify_binary_operation.  Simplify a binary operation
1478169689Skan   CODE with result mode MODE, operating on OP0 and OP1.  If OP0 and/or
1479169689Skan   OP1 are constant pool references, TRUEOP0 and TRUEOP1 represent the
1480169689Skan   actual constants.  */
1481169689Skan
1482169689Skanstatic rtx
1483169689Skansimplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
1484169689Skan			     rtx op0, rtx op1, rtx trueop0, rtx trueop1)
1485169689Skan{
1486169689Skan  rtx tem, reversed, opleft, opright;
1487169689Skan  HOST_WIDE_INT val;
1488169689Skan  unsigned int width = GET_MODE_BITSIZE (mode);
1489169689Skan
1490169689Skan  /* Even if we can't compute a constant result,
1491169689Skan     there are some cases worth simplifying.  */
1492169689Skan
1493169689Skan  switch (code)
1494169689Skan    {
1495169689Skan    case PLUS:
1496169689Skan      /* Maybe simplify x + 0 to x.  The two expressions are equivalent
1497169689Skan	 when x is NaN, infinite, or finite and nonzero.  They aren't
1498169689Skan	 when x is -0 and the rounding mode is not towards -infinity,
1499169689Skan	 since (-0) + 0 is then 0.  */
1500169689Skan      if (!HONOR_SIGNED_ZEROS (mode) && trueop1 == CONST0_RTX (mode))
1501169689Skan	return op0;
1502169689Skan
1503169689Skan      /* ((-a) + b) -> (b - a) and similarly for (a + (-b)).  These
1504169689Skan	 transformations are safe even for IEEE.  */
1505169689Skan      if (GET_CODE (op0) == NEG)
1506169689Skan	return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
1507169689Skan      else if (GET_CODE (op1) == NEG)
1508169689Skan	return simplify_gen_binary (MINUS, mode, op0, XEXP (op1, 0));
1509169689Skan
1510169689Skan      /* (~a) + 1 -> -a */
1511169689Skan      if (INTEGRAL_MODE_P (mode)
1512169689Skan	  && GET_CODE (op0) == NOT
1513169689Skan	  && trueop1 == const1_rtx)
1514169689Skan	return simplify_gen_unary (NEG, mode, XEXP (op0, 0), mode);
1515169689Skan
1516169689Skan      /* Handle both-operands-constant cases.  We can only add
1517169689Skan	 CONST_INTs to constants since the sum of relocatable symbols
1518169689Skan	 can't be handled by most assemblers.  Don't add CONST_INT
1519169689Skan	 to CONST_INT since overflow won't be computed properly if wider
1520169689Skan	 than HOST_BITS_PER_WIDE_INT.  */
1521169689Skan
1522169689Skan      if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode
1523169689Skan	  && GET_CODE (op1) == CONST_INT)
1524169689Skan	return plus_constant (op0, INTVAL (op1));
1525169689Skan      else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode
1526169689Skan	       && GET_CODE (op0) == CONST_INT)
1527169689Skan	return plus_constant (op1, INTVAL (op0));
1528169689Skan
1529169689Skan      /* See if this is something like X * C - X or vice versa or
1530169689Skan	 if the multiplication is written as a shift.  If so, we can
1531169689Skan	 distribute and make a new multiply, shift, or maybe just
1532169689Skan	 have X (if C is 2 in the example above).  But don't make
1533169689Skan	 something more expensive than we had before.  */
1534169689Skan
1535169689Skan      if (SCALAR_INT_MODE_P (mode))
1536169689Skan	{
1537169689Skan	  HOST_WIDE_INT coeff0h = 0, coeff1h = 0;
1538169689Skan	  unsigned HOST_WIDE_INT coeff0l = 1, coeff1l = 1;
1539169689Skan	  rtx lhs = op0, rhs = op1;
1540169689Skan
1541169689Skan	  if (GET_CODE (lhs) == NEG)
1542132718Skan	    {
1543169689Skan	      coeff0l = -1;
1544169689Skan	      coeff0h = -1;
1545169689Skan	      lhs = XEXP (lhs, 0);
1546132718Skan	    }
1547169689Skan	  else if (GET_CODE (lhs) == MULT
1548169689Skan		   && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
1549169689Skan	    {
1550169689Skan	      coeff0l = INTVAL (XEXP (lhs, 1));
1551169689Skan	      coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
1552169689Skan	      lhs = XEXP (lhs, 0);
1553169689Skan	    }
1554169689Skan	  else if (GET_CODE (lhs) == ASHIFT
1555169689Skan		   && GET_CODE (XEXP (lhs, 1)) == CONST_INT
1556169689Skan		   && INTVAL (XEXP (lhs, 1)) >= 0
1557169689Skan		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
1558169689Skan	    {
1559169689Skan	      coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
1560169689Skan	      coeff0h = 0;
1561169689Skan	      lhs = XEXP (lhs, 0);
1562169689Skan	    }
1563132718Skan
1564169689Skan	  if (GET_CODE (rhs) == NEG)
1565169689Skan	    {
1566169689Skan	      coeff1l = -1;
1567169689Skan	      coeff1h = -1;
1568169689Skan	      rhs = XEXP (rhs, 0);
1569169689Skan	    }
1570169689Skan	  else if (GET_CODE (rhs) == MULT
1571169689Skan		   && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
1572169689Skan	    {
1573169689Skan	      coeff1l = INTVAL (XEXP (rhs, 1));
1574169689Skan	      coeff1h = INTVAL (XEXP (rhs, 1)) < 0 ? -1 : 0;
1575169689Skan	      rhs = XEXP (rhs, 0);
1576169689Skan	    }
1577169689Skan	  else if (GET_CODE (rhs) == ASHIFT
1578169689Skan		   && GET_CODE (XEXP (rhs, 1)) == CONST_INT
1579169689Skan		   && INTVAL (XEXP (rhs, 1)) >= 0
1580169689Skan		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
1581169689Skan	    {
1582169689Skan	      coeff1l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
1583169689Skan	      coeff1h = 0;
1584169689Skan	      rhs = XEXP (rhs, 0);
1585169689Skan	    }
1586132718Skan
1587169689Skan	  if (rtx_equal_p (lhs, rhs))
1588169689Skan	    {
1589169689Skan	      rtx orig = gen_rtx_PLUS (mode, op0, op1);
1590169689Skan	      rtx coeff;
1591169689Skan	      unsigned HOST_WIDE_INT l;
1592169689Skan	      HOST_WIDE_INT h;
1593132718Skan
1594169689Skan	      add_double (coeff0l, coeff0h, coeff1l, coeff1h, &l, &h);
1595169689Skan	      coeff = immed_double_const (l, h, mode);
1596132718Skan
1597169689Skan	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
1598169689Skan	      return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
1599169689Skan		? tem : 0;
1600169689Skan	    }
1601169689Skan	}
160290075Sobrien
1603169689Skan      /* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit.  */
1604169689Skan      if ((GET_CODE (op1) == CONST_INT
1605169689Skan	   || GET_CODE (op1) == CONST_DOUBLE)
1606169689Skan	  && GET_CODE (op0) == XOR
1607169689Skan	  && (GET_CODE (XEXP (op0, 1)) == CONST_INT
1608169689Skan	      || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)
1609169689Skan	  && mode_signbit_p (mode, op1))
1610169689Skan	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
1611169689Skan				    simplify_gen_binary (XOR, mode, op1,
1612169689Skan							 XEXP (op0, 1)));
1613132718Skan
1614169689Skan      /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).  */
1615169689Skan      if (GET_CODE (op0) == MULT
1616169689Skan	  && GET_CODE (XEXP (op0, 0)) == NEG)
1617169689Skan	{
1618169689Skan	  rtx in1, in2;
1619132718Skan
1620169689Skan	  in1 = XEXP (XEXP (op0, 0), 0);
1621169689Skan	  in2 = XEXP (op0, 1);
1622169689Skan	  return simplify_gen_binary (MINUS, mode, op1,
1623169689Skan				      simplify_gen_binary (MULT, mode,
1624169689Skan							   in1, in2));
1625169689Skan	}
1626132718Skan
1627169689Skan      /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
1628169689Skan	 C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
1629169689Skan	 is 1.  */
1630169689Skan      if (COMPARISON_P (op0)
1631169689Skan	  && ((STORE_FLAG_VALUE == -1 && trueop1 == const1_rtx)
1632169689Skan	      || (STORE_FLAG_VALUE == 1 && trueop1 == constm1_rtx))
1633169689Skan	  && (reversed = reversed_comparison (op0, mode)))
1634169689Skan	return
1635169689Skan	  simplify_gen_unary (NEG, mode, reversed, mode);
1636132718Skan
1637169689Skan      /* If one of the operands is a PLUS or a MINUS, see if we can
1638169689Skan	 simplify this by the associative law.
1639169689Skan	 Don't use the associative law for floating point.
1640169689Skan	 The inaccuracy makes it nonassociative,
1641169689Skan	 and subtle programs can break if operations are associated.  */
1642169689Skan
1643169689Skan      if (INTEGRAL_MODE_P (mode)
1644169689Skan	  && (plus_minus_operand_p (op0)
1645169689Skan	      || plus_minus_operand_p (op1))
1646169689Skan	  && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
1647169689Skan	return tem;
1648169689Skan
1649169689Skan      /* Reassociate floating point addition only when the user
1650169689Skan	 specifies unsafe math optimizations.  */
1651169689Skan      if (FLOAT_MODE_P (mode)
1652169689Skan	  && flag_unsafe_math_optimizations)
1653169689Skan	{
1654169689Skan	  tem = simplify_associative_operation (code, mode, op0, op1);
1655169689Skan	  if (tem)
1656169689Skan	    return tem;
1657169689Skan	}
1658169689Skan      break;
1659169689Skan
1660169689Skan    case COMPARE:
1661169689Skan#ifdef HAVE_cc0
1662169689Skan      /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
1663169689Skan	 using cc0, in which case we want to leave it as a COMPARE
1664169689Skan	 so we can distinguish it from a register-register-copy.
1665169689Skan
1666169689Skan	 In IEEE floating point, x-0 is not the same as x.  */
1667169689Skan
1668169689Skan      if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
1669169689Skan	   || ! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
1670169689Skan	  && trueop1 == CONST0_RTX (mode))
1671169689Skan	return op0;
1672169689Skan#endif
1673169689Skan
1674169689Skan      /* Convert (compare (gt (flags) 0) (lt (flags) 0)) to (flags).  */
1675169689Skan      if (((GET_CODE (op0) == GT && GET_CODE (op1) == LT)
1676169689Skan	   || (GET_CODE (op0) == GTU && GET_CODE (op1) == LTU))
1677169689Skan	  && XEXP (op0, 1) == const0_rtx && XEXP (op1, 1) == const0_rtx)
1678169689Skan	{
1679169689Skan	  rtx xop00 = XEXP (op0, 0);
1680169689Skan	  rtx xop10 = XEXP (op1, 0);
1681169689Skan
1682169689Skan#ifdef HAVE_cc0
1683169689Skan	  if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
1684169689Skan#else
1685169689Skan	    if (REG_P (xop00) && REG_P (xop10)
1686169689Skan		&& GET_MODE (xop00) == GET_MODE (xop10)
1687169689Skan		&& REGNO (xop00) == REGNO (xop10)
1688169689Skan		&& GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
1689169689Skan		&& GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
1690169689Skan#endif
1691169689Skan	      return xop00;
1692169689Skan	}
1693169689Skan      break;
1694169689Skan
1695169689Skan    case MINUS:
1696169689Skan      /* We can't assume x-x is 0 even with non-IEEE floating point,
1697169689Skan	 but since it is zero except in very strange circumstances, we
1698169689Skan	 will treat it as zero with -funsafe-math-optimizations.  */
1699169689Skan      if (rtx_equal_p (trueop0, trueop1)
1700169689Skan	  && ! side_effects_p (op0)
1701169689Skan	  && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations))
1702169689Skan	return CONST0_RTX (mode);
1703169689Skan
1704169689Skan      /* Change subtraction from zero into negation.  (0 - x) is the
1705169689Skan	 same as -x when x is NaN, infinite, or finite and nonzero.
1706169689Skan	 But if the mode has signed zeros, and does not round towards
1707169689Skan	 -infinity, then 0 - 0 is 0, not -0.  */
1708169689Skan      if (!HONOR_SIGNED_ZEROS (mode) && trueop0 == CONST0_RTX (mode))
1709169689Skan	return simplify_gen_unary (NEG, mode, op1, mode);
1710169689Skan
1711169689Skan      /* (-1 - a) is ~a.  */
1712169689Skan      if (trueop0 == constm1_rtx)
1713169689Skan	return simplify_gen_unary (NOT, mode, op1, mode);
1714169689Skan
1715169689Skan      /* Subtracting 0 has no effect unless the mode has signed zeros
1716169689Skan	 and supports rounding towards -infinity.  In such a case,
1717169689Skan	 0 - 0 is -0.  */
1718169689Skan      if (!(HONOR_SIGNED_ZEROS (mode)
1719169689Skan	    && HONOR_SIGN_DEPENDENT_ROUNDING (mode))
1720169689Skan	  && trueop1 == CONST0_RTX (mode))
1721169689Skan	return op0;
1722169689Skan
1723169689Skan      /* See if this is something like X * C - X or vice versa or
1724169689Skan	 if the multiplication is written as a shift.  If so, we can
1725169689Skan	 distribute and make a new multiply, shift, or maybe just
1726169689Skan	 have X (if C is 2 in the example above).  But don't make
1727169689Skan	 something more expensive than we had before.  */
1728169689Skan
1729169689Skan      if (SCALAR_INT_MODE_P (mode))
1730169689Skan	{
1731169689Skan	  HOST_WIDE_INT coeff0h = 0, negcoeff1h = -1;
1732169689Skan	  unsigned HOST_WIDE_INT coeff0l = 1, negcoeff1l = -1;
1733169689Skan	  rtx lhs = op0, rhs = op1;
1734169689Skan
1735169689Skan	  if (GET_CODE (lhs) == NEG)
1736132718Skan	    {
1737169689Skan	      coeff0l = -1;
1738169689Skan	      coeff0h = -1;
1739169689Skan	      lhs = XEXP (lhs, 0);
1740169689Skan	    }
1741169689Skan	  else if (GET_CODE (lhs) == MULT
1742169689Skan		   && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
1743169689Skan	    {
1744169689Skan	      coeff0l = INTVAL (XEXP (lhs, 1));
1745169689Skan	      coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
1746169689Skan	      lhs = XEXP (lhs, 0);
1747169689Skan	    }
1748169689Skan	  else if (GET_CODE (lhs) == ASHIFT
1749169689Skan		   && GET_CODE (XEXP (lhs, 1)) == CONST_INT
1750169689Skan		   && INTVAL (XEXP (lhs, 1)) >= 0
1751169689Skan		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
1752169689Skan	    {
1753169689Skan	      coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
1754169689Skan	      coeff0h = 0;
1755169689Skan	      lhs = XEXP (lhs, 0);
1756169689Skan	    }
1757169689Skan
1758169689Skan	  if (GET_CODE (rhs) == NEG)
1759169689Skan	    {
1760169689Skan	      negcoeff1l = 1;
1761169689Skan	      negcoeff1h = 0;
1762169689Skan	      rhs = XEXP (rhs, 0);
1763169689Skan	    }
1764169689Skan	  else if (GET_CODE (rhs) == MULT
1765169689Skan		   && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
1766169689Skan	    {
1767169689Skan	      negcoeff1l = -INTVAL (XEXP (rhs, 1));
1768169689Skan	      negcoeff1h = INTVAL (XEXP (rhs, 1)) <= 0 ? 0 : -1;
1769169689Skan	      rhs = XEXP (rhs, 0);
1770169689Skan	    }
1771169689Skan	  else if (GET_CODE (rhs) == ASHIFT
1772169689Skan		   && GET_CODE (XEXP (rhs, 1)) == CONST_INT
1773169689Skan		   && INTVAL (XEXP (rhs, 1)) >= 0
1774169689Skan		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
1775169689Skan	    {
1776169689Skan	      negcoeff1l = -(((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)));
1777169689Skan	      negcoeff1h = -1;
1778169689Skan	      rhs = XEXP (rhs, 0);
1779169689Skan	    }
1780169689Skan
1781169689Skan	  if (rtx_equal_p (lhs, rhs))
1782169689Skan	    {
1783169689Skan	      rtx orig = gen_rtx_MINUS (mode, op0, op1);
1784169689Skan	      rtx coeff;
1785169689Skan	      unsigned HOST_WIDE_INT l;
1786169689Skan	      HOST_WIDE_INT h;
1787169689Skan
1788169689Skan	      add_double (coeff0l, coeff0h, negcoeff1l, negcoeff1h, &l, &h);
1789169689Skan	      coeff = immed_double_const (l, h, mode);
1790169689Skan
1791169689Skan	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
1792169689Skan	      return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
1793169689Skan		? tem : 0;
1794169689Skan	    }
1795169689Skan	}
1796169689Skan
1797169689Skan      /* (a - (-b)) -> (a + b).  True even for IEEE.  */
1798169689Skan      if (GET_CODE (op1) == NEG)
1799169689Skan	return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
1800169689Skan
1801169689Skan      /* (-x - c) may be simplified as (-c - x).  */
1802169689Skan      if (GET_CODE (op0) == NEG
1803169689Skan	  && (GET_CODE (op1) == CONST_INT
1804169689Skan	      || GET_CODE (op1) == CONST_DOUBLE))
1805169689Skan	{
1806169689Skan	  tem = simplify_unary_operation (NEG, mode, op1, mode);
1807169689Skan	  if (tem)
1808169689Skan	    return simplify_gen_binary (MINUS, mode, tem, XEXP (op0, 0));
1809169689Skan	}
1810169689Skan
1811169689Skan      /* Don't let a relocatable value get a negative coeff.  */
1812169689Skan      if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode)
1813169689Skan	return simplify_gen_binary (PLUS, mode,
1814169689Skan				    op0,
1815169689Skan				    neg_const_int (mode, op1));
1816169689Skan
1817169689Skan      /* (x - (x & y)) -> (x & ~y) */
1818169689Skan      if (GET_CODE (op1) == AND)
1819169689Skan	{
1820169689Skan	  if (rtx_equal_p (op0, XEXP (op1, 0)))
1821169689Skan	    {
1822169689Skan	      tem = simplify_gen_unary (NOT, mode, XEXP (op1, 1),
1823169689Skan					GET_MODE (XEXP (op1, 1)));
1824169689Skan	      return simplify_gen_binary (AND, mode, op0, tem);
1825169689Skan	    }
1826169689Skan	  if (rtx_equal_p (op0, XEXP (op1, 1)))
1827169689Skan	    {
1828169689Skan	      tem = simplify_gen_unary (NOT, mode, XEXP (op1, 0),
1829169689Skan					GET_MODE (XEXP (op1, 0)));
1830169689Skan	      return simplify_gen_binary (AND, mode, op0, tem);
1831169689Skan	    }
1832169689Skan	}
1833169689Skan
1834169689Skan      /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
1835169689Skan	 by reversing the comparison code if valid.  */
1836169689Skan      if (STORE_FLAG_VALUE == 1
1837169689Skan	  && trueop0 == const1_rtx
1838169689Skan	  && COMPARISON_P (op1)
1839169689Skan	  && (reversed = reversed_comparison (op1, mode)))
1840169689Skan	return reversed;
1841169689Skan
1842169689Skan      /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).  */
1843169689Skan      if (GET_CODE (op1) == MULT
1844169689Skan	  && GET_CODE (XEXP (op1, 0)) == NEG)
1845169689Skan	{
1846169689Skan	  rtx in1, in2;
1847169689Skan
1848169689Skan	  in1 = XEXP (XEXP (op1, 0), 0);
1849169689Skan	  in2 = XEXP (op1, 1);
1850169689Skan	  return simplify_gen_binary (PLUS, mode,
1851169689Skan				      simplify_gen_binary (MULT, mode,
1852169689Skan							   in1, in2),
1853169689Skan				      op0);
1854169689Skan	}
1855169689Skan
1856169689Skan      /* Canonicalize (minus (neg A) (mult B C)) to
1857169689Skan	 (minus (mult (neg B) C) A).  */
1858169689Skan      if (GET_CODE (op1) == MULT
1859169689Skan	  && GET_CODE (op0) == NEG)
1860169689Skan	{
1861169689Skan	  rtx in1, in2;
1862169689Skan
1863169689Skan	  in1 = simplify_gen_unary (NEG, mode, XEXP (op1, 0), mode);
1864169689Skan	  in2 = XEXP (op1, 1);
1865169689Skan	  return simplify_gen_binary (MINUS, mode,
1866169689Skan				      simplify_gen_binary (MULT, mode,
1867169689Skan							   in1, in2),
1868169689Skan				      XEXP (op0, 0));
1869169689Skan	}
1870169689Skan
1871169689Skan      /* If one of the operands is a PLUS or a MINUS, see if we can
1872169689Skan	 simplify this by the associative law.  This will, for example,
1873169689Skan         canonicalize (minus A (plus B C)) to (minus (minus A B) C).
1874169689Skan	 Don't use the associative law for floating point.
1875169689Skan	 The inaccuracy makes it nonassociative,
1876169689Skan	 and subtle programs can break if operations are associated.  */
1877169689Skan
1878169689Skan      if (INTEGRAL_MODE_P (mode)
1879169689Skan	  && (plus_minus_operand_p (op0)
1880169689Skan	      || plus_minus_operand_p (op1))
1881169689Skan	  && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
1882169689Skan	return tem;
1883169689Skan      break;
1884169689Skan
1885169689Skan    case MULT:
1886169689Skan      if (trueop1 == constm1_rtx)
1887169689Skan	return simplify_gen_unary (NEG, mode, op0, mode);
1888169689Skan
1889169689Skan      /* Maybe simplify x * 0 to 0.  The reduction is not valid if
1890169689Skan	 x is NaN, since x * 0 is then also NaN.  Nor is it valid
1891169689Skan	 when the mode has signed zeros, since multiplying a negative
1892169689Skan	 number by 0 will give -0, not 0.  */
1893169689Skan      if (!HONOR_NANS (mode)
1894169689Skan	  && !HONOR_SIGNED_ZEROS (mode)
1895169689Skan	  && trueop1 == CONST0_RTX (mode)
1896169689Skan	  && ! side_effects_p (op0))
1897169689Skan	return op1;
1898169689Skan
1899169689Skan      /* In IEEE floating point, x*1 is not equivalent to x for
1900169689Skan	 signalling NaNs.  */
1901169689Skan      if (!HONOR_SNANS (mode)
1902169689Skan	  && trueop1 == CONST1_RTX (mode))
1903169689Skan	return op0;
1904169689Skan
1905169689Skan      /* Convert multiply by constant power of two into shift unless
1906169689Skan	 we are still generating RTL.  This test is a kludge.  */
1907169689Skan      if (GET_CODE (trueop1) == CONST_INT
1908169689Skan	  && (val = exact_log2 (INTVAL (trueop1))) >= 0
1909169689Skan	  /* If the mode is larger than the host word size, and the
1910169689Skan	     uppermost bit is set, then this isn't a power of two due
1911169689Skan	     to implicit sign extension.  */
1912169689Skan	  && (width <= HOST_BITS_PER_WIDE_INT
1913169689Skan	      || val != HOST_BITS_PER_WIDE_INT - 1))
1914169689Skan	return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
1915169689Skan
1916169689Skan      /* Likewise for multipliers wider than a word.  */
1917169689Skan      if (GET_CODE (trueop1) == CONST_DOUBLE
1918169689Skan	  && (GET_MODE (trueop1) == VOIDmode
1919169689Skan	      || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
1920169689Skan	  && GET_MODE (op0) == mode
1921169689Skan	  && CONST_DOUBLE_LOW (trueop1) == 0
1922169689Skan	  && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
1923169689Skan	return simplify_gen_binary (ASHIFT, mode, op0,
1924169689Skan				    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
1925169689Skan
1926169689Skan      /* x*2 is x+x and x*(-1) is -x */
1927169689Skan      if (GET_CODE (trueop1) == CONST_DOUBLE
1928169689Skan	  && SCALAR_FLOAT_MODE_P (GET_MODE (trueop1))
1929169689Skan	  && GET_MODE (op0) == mode)
1930169689Skan	{
1931169689Skan	  REAL_VALUE_TYPE d;
1932169689Skan	  REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
1933169689Skan
1934169689Skan	  if (REAL_VALUES_EQUAL (d, dconst2))
1935169689Skan	    return simplify_gen_binary (PLUS, mode, op0, copy_rtx (op0));
1936169689Skan
1937169689Skan	  if (!HONOR_SNANS (mode)
1938169689Skan	      && REAL_VALUES_EQUAL (d, dconstm1))
1939169689Skan	    return simplify_gen_unary (NEG, mode, op0, mode);
1940169689Skan	}
1941169689Skan
1942169689Skan      /* Optimize -x * -x as x * x.  */
1943169689Skan      if (FLOAT_MODE_P (mode)
1944169689Skan	  && GET_CODE (op0) == NEG
1945169689Skan	  && GET_CODE (op1) == NEG
1946169689Skan	  && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
1947169689Skan	  && !side_effects_p (XEXP (op0, 0)))
1948169689Skan	return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0));
1949169689Skan
1950169689Skan      /* Likewise, optimize abs(x) * abs(x) as x * x.  */
1951169689Skan      if (SCALAR_FLOAT_MODE_P (mode)
1952169689Skan	  && GET_CODE (op0) == ABS
1953169689Skan	  && GET_CODE (op1) == ABS
1954169689Skan	  && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
1955169689Skan	  && !side_effects_p (XEXP (op0, 0)))
1956169689Skan	return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0));
1957169689Skan
1958169689Skan      /* Reassociate multiplication, but for floating point MULTs
1959169689Skan	 only when the user specifies unsafe math optimizations.  */
1960169689Skan      if (! FLOAT_MODE_P (mode)
1961169689Skan	  || flag_unsafe_math_optimizations)
1962169689Skan	{
1963169689Skan	  tem = simplify_associative_operation (code, mode, op0, op1);
1964169689Skan	  if (tem)
1965169689Skan	    return tem;
1966169689Skan	}
1967169689Skan      break;
1968169689Skan
1969169689Skan    case IOR:
1970169689Skan      if (trueop1 == const0_rtx)
1971169689Skan	return op0;
1972169689Skan      if (GET_CODE (trueop1) == CONST_INT
1973169689Skan	  && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
1974169689Skan	      == GET_MODE_MASK (mode)))
1975169689Skan	return op1;
1976169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
1977169689Skan	return op0;
1978169689Skan      /* A | (~A) -> -1 */
1979169689Skan      if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
1980169689Skan	   || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
1981169689Skan	  && ! side_effects_p (op0)
1982169689Skan	  && SCALAR_INT_MODE_P (mode))
1983169689Skan	return constm1_rtx;
1984169689Skan
1985169689Skan      /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
1986169689Skan      if (GET_CODE (op1) == CONST_INT
1987169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
1988169689Skan	  && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
1989169689Skan	return op1;
1990169689Skan
1991169689Skan      /* Convert (A & B) | A to A.  */
1992169689Skan      if (GET_CODE (op0) == AND
1993169689Skan	  && (rtx_equal_p (XEXP (op0, 0), op1)
1994169689Skan	      || rtx_equal_p (XEXP (op0, 1), op1))
1995169689Skan	  && ! side_effects_p (XEXP (op0, 0))
1996169689Skan	  && ! side_effects_p (XEXP (op0, 1)))
1997169689Skan	return op1;
1998169689Skan
1999169689Skan      /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
2000169689Skan         mode size to (rotate A CX).  */
2001169689Skan
2002169689Skan      if (GET_CODE (op1) == ASHIFT
2003169689Skan          || GET_CODE (op1) == SUBREG)
2004169689Skan        {
2005169689Skan	  opleft = op1;
2006169689Skan	  opright = op0;
2007169689Skan	}
2008169689Skan      else
2009169689Skan        {
2010169689Skan	  opright = op1;
2011169689Skan	  opleft = op0;
2012169689Skan	}
2013169689Skan
2014169689Skan      if (GET_CODE (opleft) == ASHIFT && GET_CODE (opright) == LSHIFTRT
2015169689Skan          && rtx_equal_p (XEXP (opleft, 0), XEXP (opright, 0))
2016169689Skan          && GET_CODE (XEXP (opleft, 1)) == CONST_INT
2017169689Skan          && GET_CODE (XEXP (opright, 1)) == CONST_INT
2018169689Skan          && (INTVAL (XEXP (opleft, 1)) + INTVAL (XEXP (opright, 1))
2019169689Skan              == GET_MODE_BITSIZE (mode)))
2020169689Skan        return gen_rtx_ROTATE (mode, XEXP (opright, 0), XEXP (opleft, 1));
2021169689Skan
2022169689Skan      /* Same, but for ashift that has been "simplified" to a wider mode
2023169689Skan        by simplify_shift_const.  */
2024169689Skan
2025169689Skan      if (GET_CODE (opleft) == SUBREG
2026169689Skan          && GET_CODE (SUBREG_REG (opleft)) == ASHIFT
2027169689Skan          && GET_CODE (opright) == LSHIFTRT
2028169689Skan          && GET_CODE (XEXP (opright, 0)) == SUBREG
2029169689Skan          && GET_MODE (opleft) == GET_MODE (XEXP (opright, 0))
2030169689Skan          && SUBREG_BYTE (opleft) == SUBREG_BYTE (XEXP (opright, 0))
2031169689Skan          && (GET_MODE_SIZE (GET_MODE (opleft))
2032169689Skan              < GET_MODE_SIZE (GET_MODE (SUBREG_REG (opleft))))
2033169689Skan          && rtx_equal_p (XEXP (SUBREG_REG (opleft), 0),
2034169689Skan                          SUBREG_REG (XEXP (opright, 0)))
2035169689Skan          && GET_CODE (XEXP (SUBREG_REG (opleft), 1)) == CONST_INT
2036169689Skan          && GET_CODE (XEXP (opright, 1)) == CONST_INT
2037169689Skan          && (INTVAL (XEXP (SUBREG_REG (opleft), 1)) + INTVAL (XEXP (opright, 1))
2038169689Skan              == GET_MODE_BITSIZE (mode)))
2039169689Skan        return gen_rtx_ROTATE (mode, XEXP (opright, 0),
2040169689Skan                               XEXP (SUBREG_REG (opleft), 1));
2041169689Skan
2042169689Skan      /* If we have (ior (and (X C1) C2)), simplify this by making
2043169689Skan	 C1 as small as possible if C1 actually changes.  */
2044169689Skan      if (GET_CODE (op1) == CONST_INT
2045169689Skan	  && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2046169689Skan	      || INTVAL (op1) > 0)
2047169689Skan	  && GET_CODE (op0) == AND
2048169689Skan	  && GET_CODE (XEXP (op0, 1)) == CONST_INT
2049169689Skan	  && GET_CODE (op1) == CONST_INT
2050169689Skan	  && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
2051169689Skan	return simplify_gen_binary (IOR, mode,
2052169689Skan				    simplify_gen_binary
2053169689Skan					  (AND, mode, XEXP (op0, 0),
2054169689Skan					   GEN_INT (INTVAL (XEXP (op0, 1))
2055169689Skan						    & ~INTVAL (op1))),
2056169689Skan				    op1);
2057169689Skan
2058169689Skan      /* If OP0 is (ashiftrt (plus ...) C), it might actually be
2059169689Skan         a (sign_extend (plus ...)).  Then check if OP1 is a CONST_INT and
2060169689Skan	 the PLUS does not affect any of the bits in OP1: then we can do
2061169689Skan	 the IOR as a PLUS and we can associate.  This is valid if OP1
2062169689Skan         can be safely shifted left C bits.  */
2063169689Skan      if (GET_CODE (trueop1) == CONST_INT && GET_CODE (op0) == ASHIFTRT
2064169689Skan          && GET_CODE (XEXP (op0, 0)) == PLUS
2065169689Skan          && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
2066169689Skan          && GET_CODE (XEXP (op0, 1)) == CONST_INT
2067169689Skan          && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT)
2068169689Skan        {
2069169689Skan          int count = INTVAL (XEXP (op0, 1));
2070169689Skan          HOST_WIDE_INT mask = INTVAL (trueop1) << count;
2071169689Skan
2072169689Skan          if (mask >> count == INTVAL (trueop1)
2073169689Skan              && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
2074169689Skan	    return simplify_gen_binary (ASHIFTRT, mode,
2075169689Skan					plus_constant (XEXP (op0, 0), mask),
2076169689Skan					XEXP (op0, 1));
2077169689Skan        }
2078169689Skan
2079169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2080169689Skan      if (tem)
2081169689Skan	return tem;
2082169689Skan      break;
2083169689Skan
2084169689Skan    case XOR:
2085169689Skan      if (trueop1 == const0_rtx)
2086169689Skan	return op0;
2087169689Skan      if (GET_CODE (trueop1) == CONST_INT
2088169689Skan	  && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
2089169689Skan	      == GET_MODE_MASK (mode)))
2090169689Skan	return simplify_gen_unary (NOT, mode, op0, mode);
2091169689Skan      if (rtx_equal_p (trueop0, trueop1)
2092169689Skan	  && ! side_effects_p (op0)
2093169689Skan	  && GET_MODE_CLASS (mode) != MODE_CC)
2094169689Skan	 return CONST0_RTX (mode);
2095169689Skan
2096169689Skan      /* Canonicalize XOR of the most significant bit to PLUS.  */
2097169689Skan      if ((GET_CODE (op1) == CONST_INT
2098169689Skan	   || GET_CODE (op1) == CONST_DOUBLE)
2099169689Skan	  && mode_signbit_p (mode, op1))
2100169689Skan	return simplify_gen_binary (PLUS, mode, op0, op1);
2101169689Skan      /* (xor (plus X C1) C2) is (xor X (C1^C2)) if C1 is signbit.  */
2102169689Skan      if ((GET_CODE (op1) == CONST_INT
2103169689Skan	   || GET_CODE (op1) == CONST_DOUBLE)
2104169689Skan	  && GET_CODE (op0) == PLUS
2105169689Skan	  && (GET_CODE (XEXP (op0, 1)) == CONST_INT
2106169689Skan	      || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)
2107169689Skan	  && mode_signbit_p (mode, XEXP (op0, 1)))
2108169689Skan	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
2109169689Skan				    simplify_gen_binary (XOR, mode, op1,
2110169689Skan							 XEXP (op0, 1)));
2111169689Skan
2112169689Skan      /* If we are XORing two things that have no bits in common,
2113169689Skan	 convert them into an IOR.  This helps to detect rotation encoded
2114169689Skan	 using those methods and possibly other simplifications.  */
2115169689Skan
2116169689Skan      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2117169689Skan	  && (nonzero_bits (op0, mode)
2118169689Skan	      & nonzero_bits (op1, mode)) == 0)
2119169689Skan	return (simplify_gen_binary (IOR, mode, op0, op1));
2120169689Skan
2121169689Skan      /* Convert (XOR (NOT x) (NOT y)) to (XOR x y).
2122169689Skan	 Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for
2123169689Skan	 (NOT y).  */
2124169689Skan      {
2125169689Skan	int num_negated = 0;
2126169689Skan
2127169689Skan	if (GET_CODE (op0) == NOT)
2128169689Skan	  num_negated++, op0 = XEXP (op0, 0);
2129169689Skan	if (GET_CODE (op1) == NOT)
2130169689Skan	  num_negated++, op1 = XEXP (op1, 0);
2131169689Skan
2132169689Skan	if (num_negated == 2)
2133169689Skan	  return simplify_gen_binary (XOR, mode, op0, op1);
2134169689Skan	else if (num_negated == 1)
2135169689Skan	  return simplify_gen_unary (NOT, mode,
2136169689Skan				     simplify_gen_binary (XOR, mode, op0, op1),
2137169689Skan				     mode);
2138169689Skan      }
2139169689Skan
2140169689Skan      /* Convert (xor (and A B) B) to (and (not A) B).  The latter may
2141169689Skan	 correspond to a machine insn or result in further simplifications
2142169689Skan	 if B is a constant.  */
2143169689Skan
2144169689Skan      if (GET_CODE (op0) == AND
2145169689Skan	  && rtx_equal_p (XEXP (op0, 1), op1)
2146169689Skan	  && ! side_effects_p (op1))
2147169689Skan	return simplify_gen_binary (AND, mode,
2148169689Skan				    simplify_gen_unary (NOT, mode,
2149169689Skan							XEXP (op0, 0), mode),
2150169689Skan				    op1);
2151169689Skan
2152169689Skan      else if (GET_CODE (op0) == AND
2153169689Skan	       && rtx_equal_p (XEXP (op0, 0), op1)
2154169689Skan	       && ! side_effects_p (op1))
2155169689Skan	return simplify_gen_binary (AND, mode,
2156169689Skan				    simplify_gen_unary (NOT, mode,
2157169689Skan							XEXP (op0, 1), mode),
2158169689Skan				    op1);
2159169689Skan
2160169689Skan      /* (xor (comparison foo bar) (const_int 1)) can become the reversed
2161169689Skan	 comparison if STORE_FLAG_VALUE is 1.  */
2162169689Skan      if (STORE_FLAG_VALUE == 1
2163169689Skan	  && trueop1 == const1_rtx
2164169689Skan	  && COMPARISON_P (op0)
2165169689Skan	  && (reversed = reversed_comparison (op0, mode)))
2166169689Skan	return reversed;
2167169689Skan
2168169689Skan      /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
2169169689Skan	 is (lt foo (const_int 0)), so we can perform the above
2170169689Skan	 simplification if STORE_FLAG_VALUE is 1.  */
2171169689Skan
2172169689Skan      if (STORE_FLAG_VALUE == 1
2173169689Skan	  && trueop1 == const1_rtx
2174169689Skan	  && GET_CODE (op0) == LSHIFTRT
2175169689Skan	  && GET_CODE (XEXP (op0, 1)) == CONST_INT
2176169689Skan	  && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
2177169689Skan	return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx);
2178169689Skan
2179169689Skan      /* (xor (comparison foo bar) (const_int sign-bit))
2180169689Skan	 when STORE_FLAG_VALUE is the sign bit.  */
2181169689Skan      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2182169689Skan	  && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
2183169689Skan	      == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
2184169689Skan	  && trueop1 == const_true_rtx
2185169689Skan	  && COMPARISON_P (op0)
2186169689Skan	  && (reversed = reversed_comparison (op0, mode)))
2187169689Skan	return reversed;
2188169689Skan
2189169689Skan      break;
2190169689Skan
2191169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2192169689Skan      if (tem)
2193169689Skan	return tem;
2194169689Skan      break;
2195169689Skan
2196169689Skan    case AND:
2197169689Skan      if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
2198169689Skan	return trueop1;
2199169689Skan      /* If we are turning off bits already known off in OP0, we need
2200169689Skan	 not do an AND.  */
2201169689Skan      if (GET_CODE (trueop1) == CONST_INT
2202169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2203169689Skan	  && (nonzero_bits (trueop0, mode) & ~INTVAL (trueop1)) == 0)
2204169689Skan	return op0;
2205169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)
2206169689Skan	  && GET_MODE_CLASS (mode) != MODE_CC)
2207169689Skan	return op0;
2208169689Skan      /* A & (~A) -> 0 */
2209169689Skan      if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
2210169689Skan	   || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
2211169689Skan	  && ! side_effects_p (op0)
2212169689Skan	  && GET_MODE_CLASS (mode) != MODE_CC)
2213169689Skan	return CONST0_RTX (mode);
2214169689Skan
2215169689Skan      /* Transform (and (extend X) C) into (zero_extend (and X C)) if
2216169689Skan	 there are no nonzero bits of C outside of X's mode.  */
2217169689Skan      if ((GET_CODE (op0) == SIGN_EXTEND
2218169689Skan	   || GET_CODE (op0) == ZERO_EXTEND)
2219169689Skan	  && GET_CODE (trueop1) == CONST_INT
2220169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2221169689Skan	  && (~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))
2222169689Skan	      & INTVAL (trueop1)) == 0)
2223169689Skan	{
2224169689Skan	  enum machine_mode imode = GET_MODE (XEXP (op0, 0));
2225169689Skan	  tem = simplify_gen_binary (AND, imode, XEXP (op0, 0),
2226169689Skan				     gen_int_mode (INTVAL (trueop1),
2227169689Skan						   imode));
2228169689Skan	  return simplify_gen_unary (ZERO_EXTEND, mode, tem, imode);
2229169689Skan	}
2230169689Skan
2231169689Skan      /* Convert (A ^ B) & A to A & (~B) since the latter is often a single
2232169689Skan	 insn (and may simplify more).  */
2233169689Skan      if (GET_CODE (op0) == XOR
2234169689Skan	  && rtx_equal_p (XEXP (op0, 0), op1)
2235169689Skan	  && ! side_effects_p (op1))
2236169689Skan	return simplify_gen_binary (AND, mode,
2237169689Skan				    simplify_gen_unary (NOT, mode,
2238169689Skan							XEXP (op0, 1), mode),
2239169689Skan				    op1);
2240169689Skan
2241169689Skan      if (GET_CODE (op0) == XOR
2242169689Skan	  && rtx_equal_p (XEXP (op0, 1), op1)
2243169689Skan	  && ! side_effects_p (op1))
2244169689Skan	return simplify_gen_binary (AND, mode,
2245169689Skan				    simplify_gen_unary (NOT, mode,
2246169689Skan							XEXP (op0, 0), mode),
2247169689Skan				    op1);
2248169689Skan
2249169689Skan      /* Similarly for (~(A ^ B)) & A.  */
2250169689Skan      if (GET_CODE (op0) == NOT
2251169689Skan	  && GET_CODE (XEXP (op0, 0)) == XOR
2252169689Skan	  && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1)
2253169689Skan	  && ! side_effects_p (op1))
2254169689Skan	return simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
2255169689Skan
2256169689Skan      if (GET_CODE (op0) == NOT
2257169689Skan	  && GET_CODE (XEXP (op0, 0)) == XOR
2258169689Skan	  && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1)
2259169689Skan	  && ! side_effects_p (op1))
2260169689Skan	return simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
2261169689Skan
2262169689Skan      /* Convert (A | B) & A to A.  */
2263169689Skan      if (GET_CODE (op0) == IOR
2264169689Skan	  && (rtx_equal_p (XEXP (op0, 0), op1)
2265169689Skan	      || rtx_equal_p (XEXP (op0, 1), op1))
2266169689Skan	  && ! side_effects_p (XEXP (op0, 0))
2267169689Skan	  && ! side_effects_p (XEXP (op0, 1)))
2268169689Skan	return op1;
2269169689Skan
2270169689Skan      /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
2271169689Skan	 ((A & N) + B) & M -> (A + B) & M
2272169689Skan	 Similarly if (N & M) == 0,
2273169689Skan	 ((A | N) + B) & M -> (A + B) & M
2274169689Skan	 and for - instead of + and/or ^ instead of |.  */
2275169689Skan      if (GET_CODE (trueop1) == CONST_INT
2276169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
2277169689Skan	  && ~INTVAL (trueop1)
2278169689Skan	  && (INTVAL (trueop1) & (INTVAL (trueop1) + 1)) == 0
2279169689Skan	  && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS))
2280169689Skan	{
2281169689Skan	  rtx pmop[2];
2282169689Skan	  int which;
2283169689Skan
2284169689Skan	  pmop[0] = XEXP (op0, 0);
2285169689Skan	  pmop[1] = XEXP (op0, 1);
2286169689Skan
2287169689Skan	  for (which = 0; which < 2; which++)
2288169689Skan	    {
2289169689Skan	      tem = pmop[which];
2290169689Skan	      switch (GET_CODE (tem))
2291132718Skan		{
2292169689Skan		case AND:
2293169689Skan		  if (GET_CODE (XEXP (tem, 1)) == CONST_INT
2294169689Skan		      && (INTVAL (XEXP (tem, 1)) & INTVAL (trueop1))
2295169689Skan		      == INTVAL (trueop1))
2296169689Skan		    pmop[which] = XEXP (tem, 0);
2297169689Skan		  break;
2298169689Skan		case IOR:
2299169689Skan		case XOR:
2300169689Skan		  if (GET_CODE (XEXP (tem, 1)) == CONST_INT
2301169689Skan		      && (INTVAL (XEXP (tem, 1)) & INTVAL (trueop1)) == 0)
2302169689Skan		    pmop[which] = XEXP (tem, 0);
2303169689Skan		  break;
2304169689Skan		default:
2305169689Skan		  break;
2306132718Skan		}
2307132718Skan	    }
2308132718Skan
2309169689Skan	  if (pmop[0] != XEXP (op0, 0) || pmop[1] != XEXP (op0, 1))
2310132718Skan	    {
2311169689Skan	      tem = simplify_gen_binary (GET_CODE (op0), mode,
2312169689Skan					 pmop[0], pmop[1]);
2313169689Skan	      return simplify_gen_binary (code, mode, tem, op1);
2314132718Skan	    }
2315169689Skan	}
2316169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2317169689Skan      if (tem)
2318169689Skan	return tem;
2319169689Skan      break;
2320132718Skan
2321169689Skan    case UDIV:
2322169689Skan      /* 0/x is 0 (or x&0 if x has side-effects).  */
2323169689Skan      if (trueop0 == CONST0_RTX (mode))
2324169689Skan	{
2325169689Skan	  if (side_effects_p (op1))
2326169689Skan	    return simplify_gen_binary (AND, mode, op1, trueop0);
2327169689Skan	  return trueop0;
2328169689Skan	}
2329169689Skan      /* x/1 is x.  */
2330169689Skan      if (trueop1 == CONST1_RTX (mode))
2331169689Skan	return rtl_hooks.gen_lowpart_no_emit (mode, op0);
2332169689Skan      /* Convert divide by power of two into shift.  */
2333169689Skan      if (GET_CODE (trueop1) == CONST_INT
2334169689Skan	  && (val = exact_log2 (INTVAL (trueop1))) > 0)
2335169689Skan	return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (val));
2336169689Skan      break;
2337169689Skan
2338169689Skan    case DIV:
2339169689Skan      /* Handle floating point and integers separately.  */
2340169689Skan      if (SCALAR_FLOAT_MODE_P (mode))
2341169689Skan	{
2342169689Skan	  /* Maybe change 0.0 / x to 0.0.  This transformation isn't
2343169689Skan	     safe for modes with NaNs, since 0.0 / 0.0 will then be
2344169689Skan	     NaN rather than 0.0.  Nor is it safe for modes with signed
2345169689Skan	     zeros, since dividing 0 by a negative number gives -0.0  */
2346169689Skan	  if (trueop0 == CONST0_RTX (mode)
2347169689Skan	      && !HONOR_NANS (mode)
2348169689Skan	      && !HONOR_SIGNED_ZEROS (mode)
2349169689Skan	      && ! side_effects_p (op1))
2350169689Skan	    return op0;
2351169689Skan	  /* x/1.0 is x.  */
2352169689Skan	  if (trueop1 == CONST1_RTX (mode)
2353169689Skan	      && !HONOR_SNANS (mode))
2354169689Skan	    return op0;
2355169689Skan
2356169689Skan	  if (GET_CODE (trueop1) == CONST_DOUBLE
2357169689Skan	      && trueop1 != CONST0_RTX (mode))
2358132718Skan	    {
2359169689Skan	      REAL_VALUE_TYPE d;
2360169689Skan	      REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
2361169689Skan
2362169689Skan	      /* x/-1.0 is -x.  */
2363169689Skan	      if (REAL_VALUES_EQUAL (d, dconstm1)
2364169689Skan		  && !HONOR_SNANS (mode))
2365169689Skan		return simplify_gen_unary (NEG, mode, op0, mode);
2366169689Skan
2367169689Skan	      /* Change FP division by a constant into multiplication.
2368169689Skan		 Only do this with -funsafe-math-optimizations.  */
2369169689Skan	      if (flag_unsafe_math_optimizations
2370169689Skan		  && !REAL_VALUES_EQUAL (d, dconst0))
2371169689Skan		{
2372169689Skan		  REAL_ARITHMETIC (d, RDIV_EXPR, dconst1, d);
2373169689Skan		  tem = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
2374169689Skan		  return simplify_gen_binary (MULT, mode, op0, tem);
2375169689Skan		}
2376132718Skan	    }
2377169689Skan	}
2378169689Skan      else
2379169689Skan	{
2380169689Skan	  /* 0/x is 0 (or x&0 if x has side-effects).  */
2381169689Skan	  if (trueop0 == CONST0_RTX (mode))
2382169689Skan	    {
2383169689Skan	      if (side_effects_p (op1))
2384169689Skan		return simplify_gen_binary (AND, mode, op1, trueop0);
2385169689Skan	      return trueop0;
2386169689Skan	    }
2387169689Skan	  /* x/1 is x.  */
2388169689Skan	  if (trueop1 == CONST1_RTX (mode))
2389169689Skan	    return rtl_hooks.gen_lowpart_no_emit (mode, op0);
2390169689Skan	  /* x/-1 is -x.  */
2391169689Skan	  if (trueop1 == constm1_rtx)
2392169689Skan	    {
2393169689Skan	      rtx x = rtl_hooks.gen_lowpart_no_emit (mode, op0);
2394169689Skan	      return simplify_gen_unary (NEG, mode, x, mode);
2395169689Skan	    }
2396169689Skan	}
2397169689Skan      break;
2398132718Skan
2399169689Skan    case UMOD:
2400169689Skan      /* 0%x is 0 (or x&0 if x has side-effects).  */
2401169689Skan      if (trueop0 == CONST0_RTX (mode))
2402169689Skan	{
2403169689Skan	  if (side_effects_p (op1))
2404169689Skan	    return simplify_gen_binary (AND, mode, op1, trueop0);
2405169689Skan	  return trueop0;
2406169689Skan	}
2407169689Skan      /* x%1 is 0 (of x&0 if x has side-effects).  */
2408169689Skan      if (trueop1 == CONST1_RTX (mode))
2409169689Skan	{
2410169689Skan	  if (side_effects_p (op0))
2411169689Skan	    return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode));
2412169689Skan	  return CONST0_RTX (mode);
2413169689Skan	}
2414169689Skan      /* Implement modulus by power of two as AND.  */
2415169689Skan      if (GET_CODE (trueop1) == CONST_INT
2416169689Skan	  && exact_log2 (INTVAL (trueop1)) > 0)
2417169689Skan	return simplify_gen_binary (AND, mode, op0,
2418169689Skan				    GEN_INT (INTVAL (op1) - 1));
2419169689Skan      break;
242090075Sobrien
2421169689Skan    case MOD:
2422169689Skan      /* 0%x is 0 (or x&0 if x has side-effects).  */
2423169689Skan      if (trueop0 == CONST0_RTX (mode))
2424169689Skan	{
2425169689Skan	  if (side_effects_p (op1))
2426169689Skan	    return simplify_gen_binary (AND, mode, op1, trueop0);
2427169689Skan	  return trueop0;
2428169689Skan	}
2429169689Skan      /* x%1 and x%-1 is 0 (or x&0 if x has side-effects).  */
2430169689Skan      if (trueop1 == CONST1_RTX (mode) || trueop1 == constm1_rtx)
2431169689Skan	{
2432169689Skan	  if (side_effects_p (op0))
2433169689Skan	    return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode));
2434169689Skan	  return CONST0_RTX (mode);
2435169689Skan	}
2436169689Skan      break;
243790075Sobrien
2438169689Skan    case ROTATERT:
2439169689Skan    case ROTATE:
2440169689Skan    case ASHIFTRT:
2441169689Skan      if (trueop1 == CONST0_RTX (mode))
2442169689Skan	return op0;
2443169689Skan      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
2444169689Skan	return op0;
2445169689Skan      /* Rotating ~0 always results in ~0.  */
2446169689Skan      if (GET_CODE (trueop0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
2447169689Skan	  && (unsigned HOST_WIDE_INT) INTVAL (trueop0) == GET_MODE_MASK (mode)
2448169689Skan	  && ! side_effects_p (op1))
2449169689Skan	return op0;
2450169689Skan      break;
2451132718Skan
2452169689Skan    case ASHIFT:
2453169689Skan    case SS_ASHIFT:
2454169689Skan      if (trueop1 == CONST0_RTX (mode))
2455169689Skan	return op0;
2456169689Skan      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
2457169689Skan	return op0;
2458169689Skan      break;
245990075Sobrien
2460169689Skan    case LSHIFTRT:
2461169689Skan      if (trueop1 == CONST0_RTX (mode))
2462169689Skan	return op0;
2463169689Skan      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
2464169689Skan	return op0;
2465169689Skan      /* Optimize (lshiftrt (clz X) C) as (eq X 0).  */
2466169689Skan      if (GET_CODE (op0) == CLZ
2467169689Skan	  && GET_CODE (trueop1) == CONST_INT
2468169689Skan	  && STORE_FLAG_VALUE == 1
2469169689Skan	  && INTVAL (trueop1) < (HOST_WIDE_INT)width)
2470169689Skan	{
2471169689Skan	  enum machine_mode imode = GET_MODE (XEXP (op0, 0));
2472169689Skan	  unsigned HOST_WIDE_INT zero_val = 0;
2473132718Skan
2474169689Skan	  if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
2475169689Skan	      && zero_val == GET_MODE_BITSIZE (imode)
2476169689Skan	      && INTVAL (trueop1) == exact_log2 (zero_val))
2477169689Skan	    return simplify_gen_relational (EQ, mode, imode,
2478169689Skan					    XEXP (op0, 0), const0_rtx);
2479169689Skan	}
2480169689Skan      break;
2481117395Skan
2482169689Skan    case SMIN:
2483169689Skan      if (width <= HOST_BITS_PER_WIDE_INT
2484169689Skan	  && GET_CODE (trueop1) == CONST_INT
2485169689Skan	  && INTVAL (trueop1) == (HOST_WIDE_INT) 1 << (width -1)
2486169689Skan	  && ! side_effects_p (op0))
2487169689Skan	return op1;
2488169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2489169689Skan	return op0;
2490169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2491169689Skan      if (tem)
2492169689Skan	return tem;
2493169689Skan      break;
2494169689Skan
2495169689Skan    case SMAX:
2496169689Skan      if (width <= HOST_BITS_PER_WIDE_INT
2497169689Skan	  && GET_CODE (trueop1) == CONST_INT
2498169689Skan	  && ((unsigned HOST_WIDE_INT) INTVAL (trueop1)
2499169689Skan	      == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
2500169689Skan	  && ! side_effects_p (op0))
2501169689Skan	return op1;
2502169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2503169689Skan	return op0;
2504169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2505169689Skan      if (tem)
2506169689Skan	return tem;
2507169689Skan      break;
2508169689Skan
2509169689Skan    case UMIN:
2510169689Skan      if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
2511169689Skan	return op1;
2512169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2513169689Skan	return op0;
2514169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2515169689Skan      if (tem)
2516169689Skan	return tem;
2517169689Skan      break;
2518169689Skan
2519169689Skan    case UMAX:
2520169689Skan      if (trueop1 == constm1_rtx && ! side_effects_p (op0))
2521169689Skan	return op1;
2522169689Skan      if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2523169689Skan	return op0;
2524169689Skan      tem = simplify_associative_operation (code, mode, op0, op1);
2525169689Skan      if (tem)
2526169689Skan	return tem;
2527169689Skan      break;
2528169689Skan
2529169689Skan    case SS_PLUS:
2530169689Skan    case US_PLUS:
2531169689Skan    case SS_MINUS:
2532169689Skan    case US_MINUS:
2533169689Skan      /* ??? There are simplifications that can be done.  */
2534169689Skan      return 0;
2535169689Skan
2536169689Skan    case VEC_SELECT:
2537169689Skan      if (!VECTOR_MODE_P (mode))
2538169689Skan	{
2539169689Skan	  gcc_assert (VECTOR_MODE_P (GET_MODE (trueop0)));
2540169689Skan	  gcc_assert (mode == GET_MODE_INNER (GET_MODE (trueop0)));
2541169689Skan	  gcc_assert (GET_CODE (trueop1) == PARALLEL);
2542169689Skan	  gcc_assert (XVECLEN (trueop1, 0) == 1);
2543169689Skan	  gcc_assert (GET_CODE (XVECEXP (trueop1, 0, 0)) == CONST_INT);
2544169689Skan
2545169689Skan	  if (GET_CODE (trueop0) == CONST_VECTOR)
2546169689Skan	    return CONST_VECTOR_ELT (trueop0, INTVAL (XVECEXP
2547169689Skan						      (trueop1, 0, 0)));
254890075Sobrien	}
2549169689Skan      else
2550169689Skan	{
2551169689Skan	  gcc_assert (VECTOR_MODE_P (GET_MODE (trueop0)));
2552169689Skan	  gcc_assert (GET_MODE_INNER (mode)
2553169689Skan		      == GET_MODE_INNER (GET_MODE (trueop0)));
2554169689Skan	  gcc_assert (GET_CODE (trueop1) == PARALLEL);
255590075Sobrien
2556169689Skan	  if (GET_CODE (trueop0) == CONST_VECTOR)
2557169689Skan	    {
2558169689Skan	      int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
2559169689Skan	      unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
2560169689Skan	      rtvec v = rtvec_alloc (n_elts);
2561169689Skan	      unsigned int i;
2562169689Skan
2563169689Skan	      gcc_assert (XVECLEN (trueop1, 0) == (int) n_elts);
2564169689Skan	      for (i = 0; i < n_elts; i++)
2565169689Skan		{
2566169689Skan		  rtx x = XVECEXP (trueop1, 0, i);
2567169689Skan
2568169689Skan		  gcc_assert (GET_CODE (x) == CONST_INT);
2569169689Skan		  RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop0,
2570169689Skan						       INTVAL (x));
2571169689Skan		}
2572169689Skan
2573169689Skan	      return gen_rtx_CONST_VECTOR (mode, v);
2574169689Skan	    }
2575169689Skan	}
2576169689Skan
2577169689Skan      if (XVECLEN (trueop1, 0) == 1
2578169689Skan	  && GET_CODE (XVECEXP (trueop1, 0, 0)) == CONST_INT
2579169689Skan	  && GET_CODE (trueop0) == VEC_CONCAT)
2580169689Skan	{
2581169689Skan	  rtx vec = trueop0;
2582169689Skan	  int offset = INTVAL (XVECEXP (trueop1, 0, 0)) * GET_MODE_SIZE (mode);
2583169689Skan
2584169689Skan	  /* Try to find the element in the VEC_CONCAT.  */
2585169689Skan	  while (GET_MODE (vec) != mode
2586169689Skan		 && GET_CODE (vec) == VEC_CONCAT)
2587169689Skan	    {
2588169689Skan	      HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
2589169689Skan	      if (offset < vec_size)
2590169689Skan		vec = XEXP (vec, 0);
2591169689Skan	      else
2592169689Skan		{
2593169689Skan		  offset -= vec_size;
2594169689Skan		  vec = XEXP (vec, 1);
2595169689Skan		}
2596169689Skan	      vec = avoid_constant_pool_reference (vec);
2597169689Skan	    }
2598169689Skan
2599169689Skan	  if (GET_MODE (vec) == mode)
2600169689Skan	    return vec;
2601169689Skan	}
2602169689Skan
260390075Sobrien      return 0;
2604169689Skan    case VEC_CONCAT:
2605169689Skan      {
2606169689Skan	enum machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
2607169689Skan				      ? GET_MODE (trueop0)
2608169689Skan				      : GET_MODE_INNER (mode));
2609169689Skan	enum machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
2610169689Skan				      ? GET_MODE (trueop1)
2611169689Skan				      : GET_MODE_INNER (mode));
2612132718Skan
2613169689Skan	gcc_assert (VECTOR_MODE_P (mode));
2614169689Skan	gcc_assert (GET_MODE_SIZE (op0_mode) + GET_MODE_SIZE (op1_mode)
2615169689Skan		    == GET_MODE_SIZE (mode));
2616132718Skan
2617169689Skan	if (VECTOR_MODE_P (op0_mode))
2618169689Skan	  gcc_assert (GET_MODE_INNER (mode)
2619169689Skan		      == GET_MODE_INNER (op0_mode));
2620169689Skan	else
2621169689Skan	  gcc_assert (GET_MODE_INNER (mode) == op0_mode);
2622132718Skan
2623169689Skan	if (VECTOR_MODE_P (op1_mode))
2624169689Skan	  gcc_assert (GET_MODE_INNER (mode)
2625169689Skan		      == GET_MODE_INNER (op1_mode));
2626169689Skan	else
2627169689Skan	  gcc_assert (GET_MODE_INNER (mode) == op1_mode);
2628132718Skan
2629169689Skan	if ((GET_CODE (trueop0) == CONST_VECTOR
2630169689Skan	     || GET_CODE (trueop0) == CONST_INT
2631169689Skan	     || GET_CODE (trueop0) == CONST_DOUBLE)
2632169689Skan	    && (GET_CODE (trueop1) == CONST_VECTOR
2633169689Skan		|| GET_CODE (trueop1) == CONST_INT
2634169689Skan		|| GET_CODE (trueop1) == CONST_DOUBLE))
2635169689Skan	  {
2636169689Skan	    int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
2637169689Skan	    unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
2638169689Skan	    rtvec v = rtvec_alloc (n_elts);
2639169689Skan	    unsigned int i;
2640169689Skan	    unsigned in_n_elts = 1;
2641132718Skan
2642169689Skan	    if (VECTOR_MODE_P (op0_mode))
2643169689Skan	      in_n_elts = (GET_MODE_SIZE (op0_mode) / elt_size);
2644169689Skan	    for (i = 0; i < n_elts; i++)
2645169689Skan	      {
2646169689Skan		if (i < in_n_elts)
2647169689Skan		  {
2648169689Skan		    if (!VECTOR_MODE_P (op0_mode))
2649169689Skan		      RTVEC_ELT (v, i) = trueop0;
2650169689Skan		    else
2651169689Skan		      RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop0, i);
2652169689Skan		  }
2653169689Skan		else
2654169689Skan		  {
2655169689Skan		    if (!VECTOR_MODE_P (op1_mode))
2656169689Skan		      RTVEC_ELT (v, i) = trueop1;
2657169689Skan		    else
2658169689Skan		      RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop1,
2659169689Skan							   i - in_n_elts);
2660169689Skan		  }
2661169689Skan	      }
2662169689Skan
2663169689Skan	    return gen_rtx_CONST_VECTOR (mode, v);
2664169689Skan	  }
2665169689Skan      }
2666169689Skan      return 0;
2667169689Skan
2668169689Skan    default:
2669169689Skan      gcc_unreachable ();
2670132718Skan    }
2671132718Skan
2672132718Skan  return 0;
2673132718Skan}
2674132718Skan
267590075Sobrienrtx
2676169689Skansimplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
2677169689Skan				 rtx op0, rtx op1)
267890075Sobrien{
267990075Sobrien  HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
268090075Sobrien  HOST_WIDE_INT val;
268190075Sobrien  unsigned int width = GET_MODE_BITSIZE (mode);
268290075Sobrien
2683132718Skan  if (VECTOR_MODE_P (mode)
2684146895Skan      && code != VEC_CONCAT
2685169689Skan      && GET_CODE (op0) == CONST_VECTOR
2686169689Skan      && GET_CODE (op1) == CONST_VECTOR)
2687132718Skan    {
2688169689Skan      unsigned n_elts = GET_MODE_NUNITS (mode);
2689169689Skan      enum machine_mode op0mode = GET_MODE (op0);
2690169689Skan      unsigned op0_n_elts = GET_MODE_NUNITS (op0mode);
2691169689Skan      enum machine_mode op1mode = GET_MODE (op1);
2692169689Skan      unsigned op1_n_elts = GET_MODE_NUNITS (op1mode);
2693132718Skan      rtvec v = rtvec_alloc (n_elts);
2694132718Skan      unsigned int i;
2695132718Skan
2696169689Skan      gcc_assert (op0_n_elts == n_elts);
2697169689Skan      gcc_assert (op1_n_elts == n_elts);
2698132718Skan      for (i = 0; i < n_elts; i++)
2699132718Skan	{
2700132718Skan	  rtx x = simplify_binary_operation (code, GET_MODE_INNER (mode),
2701169689Skan					     CONST_VECTOR_ELT (op0, i),
2702169689Skan					     CONST_VECTOR_ELT (op1, i));
2703132718Skan	  if (!x)
2704132718Skan	    return 0;
2705132718Skan	  RTVEC_ELT (v, i) = x;
2706132718Skan	}
2707132718Skan
2708132718Skan      return gen_rtx_CONST_VECTOR (mode, v);
2709132718Skan    }
2710132718Skan
2711169689Skan  if (VECTOR_MODE_P (mode)
2712169689Skan      && code == VEC_CONCAT
2713169689Skan      && CONSTANT_P (op0) && CONSTANT_P (op1))
2714169689Skan    {
2715169689Skan      unsigned n_elts = GET_MODE_NUNITS (mode);
2716169689Skan      rtvec v = rtvec_alloc (n_elts);
2717169689Skan
2718169689Skan      gcc_assert (n_elts >= 2);
2719169689Skan      if (n_elts == 2)
2720169689Skan	{
2721169689Skan	  gcc_assert (GET_CODE (op0) != CONST_VECTOR);
2722169689Skan	  gcc_assert (GET_CODE (op1) != CONST_VECTOR);
2723169689Skan
2724169689Skan	  RTVEC_ELT (v, 0) = op0;
2725169689Skan	  RTVEC_ELT (v, 1) = op1;
2726169689Skan	}
2727169689Skan      else
2728169689Skan	{
2729169689Skan	  unsigned op0_n_elts = GET_MODE_NUNITS (GET_MODE (op0));
2730169689Skan	  unsigned op1_n_elts = GET_MODE_NUNITS (GET_MODE (op1));
2731169689Skan	  unsigned i;
2732169689Skan
2733169689Skan	  gcc_assert (GET_CODE (op0) == CONST_VECTOR);
2734169689Skan	  gcc_assert (GET_CODE (op1) == CONST_VECTOR);
2735169689Skan	  gcc_assert (op0_n_elts + op1_n_elts == n_elts);
2736169689Skan
2737169689Skan	  for (i = 0; i < op0_n_elts; ++i)
2738169689Skan	    RTVEC_ELT (v, i) = XVECEXP (op0, 0, i);
2739169689Skan	  for (i = 0; i < op1_n_elts; ++i)
2740169689Skan	    RTVEC_ELT (v, op0_n_elts+i) = XVECEXP (op1, 0, i);
2741169689Skan	}
2742169689Skan
2743169689Skan      return gen_rtx_CONST_VECTOR (mode, v);
2744169689Skan    }
2745169689Skan
2746169689Skan  if (SCALAR_FLOAT_MODE_P (mode)
2747169689Skan      && GET_CODE (op0) == CONST_DOUBLE
2748169689Skan      && GET_CODE (op1) == CONST_DOUBLE
274990075Sobrien      && mode == GET_MODE (op0) && mode == GET_MODE (op1))
275090075Sobrien    {
2751146895Skan      if (code == AND
2752146895Skan	  || code == IOR
2753146895Skan	  || code == XOR)
2754146895Skan	{
2755146895Skan	  long tmp0[4];
2756146895Skan	  long tmp1[4];
2757146895Skan	  REAL_VALUE_TYPE r;
2758146895Skan	  int i;
275990075Sobrien
2760146895Skan	  real_to_target (tmp0, CONST_DOUBLE_REAL_VALUE (op0),
2761146895Skan			  GET_MODE (op0));
2762146895Skan	  real_to_target (tmp1, CONST_DOUBLE_REAL_VALUE (op1),
2763146895Skan			  GET_MODE (op1));
2764146895Skan	  for (i = 0; i < 4; i++)
2765146895Skan	    {
2766169689Skan	      switch (code)
2767169689Skan	      {
2768169689Skan	      case AND:
2769146895Skan		tmp0[i] &= tmp1[i];
2770169689Skan		break;
2771169689Skan	      case IOR:
2772146895Skan		tmp0[i] |= tmp1[i];
2773169689Skan		break;
2774169689Skan	      case XOR:
2775146895Skan		tmp0[i] ^= tmp1[i];
2776169689Skan		break;
2777169689Skan	      default:
2778169689Skan		gcc_unreachable ();
2779169689Skan	      }
2780146895Skan	    }
2781146895Skan	   real_from_target (&r, tmp0, mode);
2782146895Skan	   return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
2783146895Skan	}
2784146895Skan      else
2785146895Skan	{
2786169689Skan	  REAL_VALUE_TYPE f0, f1, value, result;
2787169689Skan	  bool inexact;
2788117395Skan
2789169689Skan	  REAL_VALUE_FROM_CONST_DOUBLE (f0, op0);
2790169689Skan	  REAL_VALUE_FROM_CONST_DOUBLE (f1, op1);
2791169689Skan	  real_convert (&f0, mode, &f0);
2792169689Skan	  real_convert (&f1, mode, &f1);
2793132718Skan
2794146895Skan	  if (HONOR_SNANS (mode)
2795146895Skan	      && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
2796146895Skan	    return 0;
2797117395Skan
2798146895Skan	  if (code == DIV
2799146895Skan	      && REAL_VALUES_EQUAL (f1, dconst0)
2800146895Skan	      && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
2801146895Skan	    return 0;
2802132718Skan
2803146895Skan	  if (MODE_HAS_INFINITIES (mode) && HONOR_NANS (mode)
2804146895Skan	      && flag_trapping_math
2805146895Skan	      && REAL_VALUE_ISINF (f0) && REAL_VALUE_ISINF (f1))
2806132718Skan	    {
2807146895Skan	      int s0 = REAL_VALUE_NEGATIVE (f0);
2808146895Skan	      int s1 = REAL_VALUE_NEGATIVE (f1);
2809146895Skan
2810146895Skan	      switch (code)
2811146895Skan		{
2812146895Skan		case PLUS:
2813146895Skan		  /* Inf + -Inf = NaN plus exception.  */
2814146895Skan		  if (s0 != s1)
2815146895Skan		    return 0;
2816146895Skan		  break;
2817146895Skan		case MINUS:
2818146895Skan		  /* Inf - Inf = NaN plus exception.  */
2819146895Skan		  if (s0 == s1)
2820146895Skan		    return 0;
2821146895Skan		  break;
2822146895Skan		case DIV:
2823146895Skan		  /* Inf / Inf = NaN plus exception.  */
2824146895Skan		  return 0;
2825146895Skan		default:
2826146895Skan		  break;
2827146895Skan		}
2828132718Skan	    }
2829132718Skan
2830146895Skan	  if (code == MULT && MODE_HAS_INFINITIES (mode) && HONOR_NANS (mode)
2831146895Skan	      && flag_trapping_math
2832146895Skan	      && ((REAL_VALUE_ISINF (f0) && REAL_VALUES_EQUAL (f1, dconst0))
2833146895Skan		  || (REAL_VALUE_ISINF (f1)
2834146895Skan		      && REAL_VALUES_EQUAL (f0, dconst0))))
2835146895Skan	    /* Inf * 0 = NaN plus exception.  */
2836146895Skan	    return 0;
2837132718Skan
2838169689Skan	  inexact = real_arithmetic (&value, rtx_to_tree_code (code),
2839169689Skan				     &f0, &f1);
2840169689Skan	  real_convert (&result, mode, &value);
2841117395Skan
2842169689Skan	  /* Don't constant fold this floating point operation if
2843169689Skan	     the result has overflowed and flag_trapping_math.  */
2844169689Skan
2845169689Skan	  if (flag_trapping_math
2846169689Skan	      && MODE_HAS_INFINITIES (mode)
2847169689Skan	      && REAL_VALUE_ISINF (result)
2848169689Skan	      && !REAL_VALUE_ISINF (f0)
2849169689Skan	      && !REAL_VALUE_ISINF (f1))
2850169689Skan	    /* Overflow plus exception.  */
2851169689Skan	    return 0;
2852169689Skan
2853169689Skan	  /* Don't constant fold this floating point operation if the
2854169689Skan	     result may dependent upon the run-time rounding mode and
2855169689Skan	     flag_rounding_math is set, or if GCC's software emulation
2856169689Skan	     is unable to accurately represent the result.  */
2857169689Skan
2858169689Skan	  if ((flag_rounding_math
2859169689Skan	       || (REAL_MODE_FORMAT_COMPOSITE_P (mode)
2860169689Skan		   && !flag_unsafe_math_optimizations))
2861169689Skan	      && (inexact || !real_identical (&result, &value)))
2862169689Skan	    return NULL_RTX;
2863169689Skan
2864169689Skan	  return CONST_DOUBLE_FROM_REAL_VALUE (result, mode);
2865146895Skan	}
286690075Sobrien    }
286790075Sobrien
286890075Sobrien  /* We can fold some multi-word operations.  */
286990075Sobrien  if (GET_MODE_CLASS (mode) == MODE_INT
287090075Sobrien      && width == HOST_BITS_PER_WIDE_INT * 2
2871169689Skan      && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
2872169689Skan      && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
287390075Sobrien    {
2874169689Skan      unsigned HOST_WIDE_INT l1, l2, lv, lt;
2875169689Skan      HOST_WIDE_INT h1, h2, hv, ht;
287690075Sobrien
2877169689Skan      if (GET_CODE (op0) == CONST_DOUBLE)
2878169689Skan	l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
287990075Sobrien      else
2880169689Skan	l1 = INTVAL (op0), h1 = HWI_SIGN_EXTEND (l1);
288190075Sobrien
2882169689Skan      if (GET_CODE (op1) == CONST_DOUBLE)
2883169689Skan	l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1);
288490075Sobrien      else
2885169689Skan	l2 = INTVAL (op1), h2 = HWI_SIGN_EXTEND (l2);
288690075Sobrien
288790075Sobrien      switch (code)
288890075Sobrien	{
288990075Sobrien	case MINUS:
289090075Sobrien	  /* A - B == A + (-B).  */
289190075Sobrien	  neg_double (l2, h2, &lv, &hv);
289290075Sobrien	  l2 = lv, h2 = hv;
289390075Sobrien
2894132718Skan	  /* Fall through....  */
289590075Sobrien
289690075Sobrien	case PLUS:
289790075Sobrien	  add_double (l1, h1, l2, h2, &lv, &hv);
289890075Sobrien	  break;
289990075Sobrien
290090075Sobrien	case MULT:
290190075Sobrien	  mul_double (l1, h1, l2, h2, &lv, &hv);
290290075Sobrien	  break;
290390075Sobrien
2904169689Skan	case DIV:
2905169689Skan	  if (div_and_round_double (TRUNC_DIV_EXPR, 0, l1, h1, l2, h2,
2906169689Skan				    &lv, &hv, &lt, &ht))
2907169689Skan	    return 0;
2908169689Skan	  break;
290990075Sobrien
2910169689Skan	case MOD:
2911169689Skan	  if (div_and_round_double (TRUNC_DIV_EXPR, 0, l1, h1, l2, h2,
2912169689Skan				    &lt, &ht, &lv, &hv))
2913169689Skan	    return 0;
2914169689Skan	  break;
2915169689Skan
2916169689Skan	case UDIV:
2917169689Skan	  if (div_and_round_double (TRUNC_DIV_EXPR, 1, l1, h1, l2, h2,
2918169689Skan				    &lv, &hv, &lt, &ht))
2919169689Skan	    return 0;
2920169689Skan	  break;
2921169689Skan
2922169689Skan	case UMOD:
2923169689Skan	  if (div_and_round_double (TRUNC_DIV_EXPR, 1, l1, h1, l2, h2,
2924169689Skan				    &lt, &ht, &lv, &hv))
2925169689Skan	    return 0;
2926169689Skan	  break;
2927169689Skan
292890075Sobrien	case AND:
292990075Sobrien	  lv = l1 & l2, hv = h1 & h2;
293090075Sobrien	  break;
293190075Sobrien
293290075Sobrien	case IOR:
293390075Sobrien	  lv = l1 | l2, hv = h1 | h2;
293490075Sobrien	  break;
293590075Sobrien
293690075Sobrien	case XOR:
293790075Sobrien	  lv = l1 ^ l2, hv = h1 ^ h2;
293890075Sobrien	  break;
293990075Sobrien
294090075Sobrien	case SMIN:
294190075Sobrien	  if (h1 < h2
294290075Sobrien	      || (h1 == h2
294390075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
294490075Sobrien		      < (unsigned HOST_WIDE_INT) l2)))
294590075Sobrien	    lv = l1, hv = h1;
294690075Sobrien	  else
294790075Sobrien	    lv = l2, hv = h2;
294890075Sobrien	  break;
294990075Sobrien
295090075Sobrien	case SMAX:
295190075Sobrien	  if (h1 > h2
295290075Sobrien	      || (h1 == h2
295390075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
295490075Sobrien		      > (unsigned HOST_WIDE_INT) l2)))
295590075Sobrien	    lv = l1, hv = h1;
295690075Sobrien	  else
295790075Sobrien	    lv = l2, hv = h2;
295890075Sobrien	  break;
295990075Sobrien
296090075Sobrien	case UMIN:
296190075Sobrien	  if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2
296290075Sobrien	      || (h1 == h2
296390075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
296490075Sobrien		      < (unsigned HOST_WIDE_INT) l2)))
296590075Sobrien	    lv = l1, hv = h1;
296690075Sobrien	  else
296790075Sobrien	    lv = l2, hv = h2;
296890075Sobrien	  break;
296990075Sobrien
297090075Sobrien	case UMAX:
297190075Sobrien	  if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2
297290075Sobrien	      || (h1 == h2
297390075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
297490075Sobrien		      > (unsigned HOST_WIDE_INT) l2)))
297590075Sobrien	    lv = l1, hv = h1;
297690075Sobrien	  else
297790075Sobrien	    lv = l2, hv = h2;
297890075Sobrien	  break;
297990075Sobrien
298090075Sobrien	case LSHIFTRT:   case ASHIFTRT:
298190075Sobrien	case ASHIFT:
298290075Sobrien	case ROTATE:     case ROTATERT:
298390075Sobrien	  if (SHIFT_COUNT_TRUNCATED)
298490075Sobrien	    l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
298590075Sobrien
298690075Sobrien	  if (h2 != 0 || l2 >= GET_MODE_BITSIZE (mode))
298790075Sobrien	    return 0;
298890075Sobrien
298990075Sobrien	  if (code == LSHIFTRT || code == ASHIFTRT)
299090075Sobrien	    rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
299190075Sobrien			   code == ASHIFTRT);
299290075Sobrien	  else if (code == ASHIFT)
299390075Sobrien	    lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
299490075Sobrien	  else if (code == ROTATE)
299590075Sobrien	    lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
299690075Sobrien	  else /* code == ROTATERT */
299790075Sobrien	    rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
299890075Sobrien	  break;
299990075Sobrien
300090075Sobrien	default:
300190075Sobrien	  return 0;
300290075Sobrien	}
300390075Sobrien
300490075Sobrien      return immed_double_const (lv, hv, mode);
300590075Sobrien    }
300690075Sobrien
3007169689Skan  if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
3008169689Skan      && width <= HOST_BITS_PER_WIDE_INT && width != 0)
300990075Sobrien    {
3010169689Skan      /* Get the integer argument values in two forms:
3011169689Skan         zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
301290075Sobrien
3013169689Skan      arg0 = INTVAL (op0);
3014169689Skan      arg1 = INTVAL (op1);
3015169689Skan
3016169689Skan      if (width < HOST_BITS_PER_WIDE_INT)
3017169689Skan        {
3018169689Skan          arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
3019169689Skan          arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
3020169689Skan
3021169689Skan          arg0s = arg0;
3022169689Skan          if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
3023169689Skan	    arg0s |= ((HOST_WIDE_INT) (-1) << width);
3024169689Skan
3025169689Skan	  arg1s = arg1;
3026169689Skan	  if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
3027169689Skan	    arg1s |= ((HOST_WIDE_INT) (-1) << width);
3028169689Skan	}
3029169689Skan      else
3030169689Skan	{
3031169689Skan	  arg0s = arg0;
3032169689Skan	  arg1s = arg1;
3033169689Skan	}
3034169689Skan
3035169689Skan      /* Compute the value of the arithmetic.  */
3036169689Skan
303790075Sobrien      switch (code)
303890075Sobrien	{
303990075Sobrien	case PLUS:
3040169689Skan	  val = arg0s + arg1s;
304190075Sobrien	  break;
3042169689Skan
304390075Sobrien	case MINUS:
3044169689Skan	  val = arg0s - arg1s;
304590075Sobrien	  break;
3046169689Skan
304790075Sobrien	case MULT:
3048169689Skan	  val = arg0s * arg1s;
304990075Sobrien	  break;
3050169689Skan
3051169689Skan	case DIV:
3052169689Skan	  if (arg1s == 0
3053169689Skan	      || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3054169689Skan		  && arg1s == -1))
3055169689Skan	    return 0;
3056169689Skan	  val = arg0s / arg1s;
305790075Sobrien	  break;
3058169689Skan
3059169689Skan	case MOD:
3060169689Skan	  if (arg1s == 0
3061169689Skan	      || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3062169689Skan		  && arg1s == -1))
3063169689Skan	    return 0;
3064169689Skan	  val = arg0s % arg1s;
306590075Sobrien	  break;
3066169689Skan
306790075Sobrien	case UDIV:
3068169689Skan	  if (arg1 == 0
3069169689Skan	      || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3070169689Skan		  && arg1s == -1))
3071169689Skan	    return 0;
3072169689Skan	  val = (unsigned HOST_WIDE_INT) arg0 / arg1;
307390075Sobrien	  break;
3074169689Skan
307590075Sobrien	case UMOD:
3076169689Skan	  if (arg1 == 0
3077169689Skan	      || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3078169689Skan		  && arg1s == -1))
3079169689Skan	    return 0;
3080169689Skan	  val = (unsigned HOST_WIDE_INT) arg0 % arg1;
308190075Sobrien	  break;
3082169689Skan
3083169689Skan	case AND:
3084169689Skan	  val = arg0 & arg1;
3085169689Skan	  break;
3086169689Skan
3087169689Skan	case IOR:
3088169689Skan	  val = arg0 | arg1;
3089169689Skan	  break;
3090169689Skan
3091169689Skan	case XOR:
3092169689Skan	  val = arg0 ^ arg1;
3093169689Skan	  break;
3094169689Skan
3095169689Skan	case LSHIFTRT:
3096169689Skan	case ASHIFT:
3097169689Skan	case ASHIFTRT:
3098169689Skan	  /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
3099169689Skan	     the value is in range.  We can't return any old value for
3100169689Skan	     out-of-range arguments because either the middle-end (via
3101169689Skan	     shift_truncation_mask) or the back-end might be relying on
3102169689Skan	     target-specific knowledge.  Nor can we rely on
3103169689Skan	     shift_truncation_mask, since the shift might not be part of an
3104169689Skan	     ashlM3, lshrM3 or ashrM3 instruction.  */
3105169689Skan	  if (SHIFT_COUNT_TRUNCATED)
3106169689Skan	    arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
3107169689Skan	  else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
3108169689Skan	    return 0;
3109169689Skan
3110169689Skan	  val = (code == ASHIFT
3111169689Skan		 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
3112169689Skan		 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
3113169689Skan
3114169689Skan	  /* Sign-extend the result for arithmetic right shifts.  */
3115169689Skan	  if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
3116169689Skan	    val |= ((HOST_WIDE_INT) -1) << (width - arg1);
3117169689Skan	  break;
3118169689Skan
311990075Sobrien	case ROTATERT:
3120169689Skan	  if (arg1 < 0)
3121169689Skan	    return 0;
3122169689Skan
3123169689Skan	  arg1 %= width;
3124169689Skan	  val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
3125169689Skan		 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
3126169689Skan	  break;
3127169689Skan
312890075Sobrien	case ROTATE:
3129169689Skan	  if (arg1 < 0)
3130169689Skan	    return 0;
3131169689Skan
3132169689Skan	  arg1 %= width;
3133169689Skan	  val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
3134169689Skan		 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
313590075Sobrien	  break;
3136169689Skan
3137169689Skan	case COMPARE:
3138169689Skan	  /* Do nothing here.  */
3139169689Skan	  return 0;
3140169689Skan
314190075Sobrien	case SMIN:
3142169689Skan	  val = arg0s <= arg1s ? arg0s : arg1s;
314390075Sobrien	  break;
3144169689Skan
3145169689Skan	case UMIN:
3146169689Skan	  val = ((unsigned HOST_WIDE_INT) arg0
3147169689Skan		 <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
3148169689Skan	  break;
3149169689Skan
315090075Sobrien	case SMAX:
3151169689Skan	  val = arg0s > arg1s ? arg0s : arg1s;
315290075Sobrien	  break;
3153169689Skan
315490075Sobrien	case UMAX:
3155169689Skan	  val = ((unsigned HOST_WIDE_INT) arg0
3156169689Skan		 > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
315790075Sobrien	  break;
3158169689Skan
315990075Sobrien	case SS_PLUS:
316090075Sobrien	case US_PLUS:
316190075Sobrien	case SS_MINUS:
316290075Sobrien	case US_MINUS:
3163169689Skan	case SS_ASHIFT:
316490075Sobrien	  /* ??? There are simplifications that can be done.  */
316590075Sobrien	  return 0;
3166169689Skan
316790075Sobrien	default:
3168169689Skan	  gcc_unreachable ();
316990075Sobrien	}
3170117395Skan
3171169689Skan      return gen_int_mode (val, mode);
317290075Sobrien    }
317390075Sobrien
3174169689Skan  return NULL_RTX;
3175169689Skan}
317690075Sobrien
317790075Sobrien
317890075Sobrien
317990075Sobrien/* Simplify a PLUS or MINUS, at least one of whose operands may be another
318090075Sobrien   PLUS or MINUS.
318190075Sobrien
318290075Sobrien   Rather than test for specific case, we do this by a brute-force method
318390075Sobrien   and do all possible simplifications until no more changes occur.  Then
3184169689Skan   we rebuild the operation.  */
318590075Sobrien
318690075Sobrienstruct simplify_plus_minus_op_data
318790075Sobrien{
318890075Sobrien  rtx op;
3189169689Skan  short neg;
319090075Sobrien};
319190075Sobrien
319290075Sobrienstatic int
3193132718Skansimplify_plus_minus_op_data_cmp (const void *p1, const void *p2)
319490075Sobrien{
319590075Sobrien  const struct simplify_plus_minus_op_data *d1 = p1;
319690075Sobrien  const struct simplify_plus_minus_op_data *d2 = p2;
3197169689Skan  int result;
319890075Sobrien
3199169689Skan  result = (commutative_operand_precedence (d2->op)
3200169689Skan	    - commutative_operand_precedence (d1->op));
3201169689Skan  if (result)
3202169689Skan    return result;
3203169689Skan
3204169689Skan  /* Group together equal REGs to do more simplification.  */
3205169689Skan  if (REG_P (d1->op) && REG_P (d2->op))
3206169689Skan    return REGNO (d1->op) - REGNO (d2->op);
3207169689Skan  else
3208169689Skan    return 0;
320990075Sobrien}
321090075Sobrien
321190075Sobrienstatic rtx
3212132718Skansimplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
3213169689Skan		     rtx op1)
321490075Sobrien{
321590075Sobrien  struct simplify_plus_minus_op_data ops[8];
321690075Sobrien  rtx result, tem;
3217169689Skan  int n_ops = 2, input_ops = 2;
3218169689Skan  int changed, n_constants = 0, canonicalized = 0;
321990075Sobrien  int i, j;
322090075Sobrien
3221132718Skan  memset (ops, 0, sizeof ops);
3222117395Skan
322390075Sobrien  /* Set up the two operands and then expand them until nothing has been
322490075Sobrien     changed.  If we run out of room in our array, give up; this should
322590075Sobrien     almost never happen.  */
322690075Sobrien
322790075Sobrien  ops[0].op = op0;
322890075Sobrien  ops[0].neg = 0;
322990075Sobrien  ops[1].op = op1;
323090075Sobrien  ops[1].neg = (code == MINUS);
323190075Sobrien
323290075Sobrien  do
323390075Sobrien    {
323490075Sobrien      changed = 0;
323590075Sobrien
323690075Sobrien      for (i = 0; i < n_ops; i++)
323790075Sobrien	{
323890075Sobrien	  rtx this_op = ops[i].op;
323990075Sobrien	  int this_neg = ops[i].neg;
324090075Sobrien	  enum rtx_code this_code = GET_CODE (this_op);
324190075Sobrien
324290075Sobrien	  switch (this_code)
324390075Sobrien	    {
324490075Sobrien	    case PLUS:
324590075Sobrien	    case MINUS:
324690075Sobrien	      if (n_ops == 7)
324796263Sobrien		return NULL_RTX;
324890075Sobrien
324990075Sobrien	      ops[n_ops].op = XEXP (this_op, 1);
325090075Sobrien	      ops[n_ops].neg = (this_code == MINUS) ^ this_neg;
325190075Sobrien	      n_ops++;
325290075Sobrien
325390075Sobrien	      ops[i].op = XEXP (this_op, 0);
325490075Sobrien	      input_ops++;
325590075Sobrien	      changed = 1;
3256169689Skan	      canonicalized |= this_neg;
325790075Sobrien	      break;
325890075Sobrien
325990075Sobrien	    case NEG:
326090075Sobrien	      ops[i].op = XEXP (this_op, 0);
326190075Sobrien	      ops[i].neg = ! this_neg;
326290075Sobrien	      changed = 1;
3263169689Skan	      canonicalized = 1;
326490075Sobrien	      break;
326590075Sobrien
326690075Sobrien	    case CONST:
326796263Sobrien	      if (n_ops < 7
326896263Sobrien		  && GET_CODE (XEXP (this_op, 0)) == PLUS
326996263Sobrien		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 0))
327096263Sobrien		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 1)))
327196263Sobrien		{
327296263Sobrien		  ops[i].op = XEXP (XEXP (this_op, 0), 0);
327396263Sobrien		  ops[n_ops].op = XEXP (XEXP (this_op, 0), 1);
327496263Sobrien		  ops[n_ops].neg = this_neg;
327596263Sobrien		  n_ops++;
327696263Sobrien		  changed = 1;
3277169689Skan	          canonicalized = 1;
327896263Sobrien		}
327990075Sobrien	      break;
328090075Sobrien
328190075Sobrien	    case NOT:
328290075Sobrien	      /* ~a -> (-a - 1) */
328390075Sobrien	      if (n_ops != 7)
328490075Sobrien		{
328590075Sobrien		  ops[n_ops].op = constm1_rtx;
328690075Sobrien		  ops[n_ops++].neg = this_neg;
328790075Sobrien		  ops[i].op = XEXP (this_op, 0);
328890075Sobrien		  ops[i].neg = !this_neg;
328990075Sobrien		  changed = 1;
3290169689Skan	          canonicalized = 1;
329190075Sobrien		}
329290075Sobrien	      break;
329390075Sobrien
329490075Sobrien	    case CONST_INT:
3295169689Skan	      n_constants++;
329690075Sobrien	      if (this_neg)
329790075Sobrien		{
329890075Sobrien		  ops[i].op = neg_const_int (mode, this_op);
329990075Sobrien		  ops[i].neg = 0;
330090075Sobrien		  changed = 1;
3301169689Skan	          canonicalized = 1;
330290075Sobrien		}
330390075Sobrien	      break;
330490075Sobrien
330590075Sobrien	    default:
330690075Sobrien	      break;
330790075Sobrien	    }
330890075Sobrien	}
330990075Sobrien    }
331090075Sobrien  while (changed);
331190075Sobrien
3312169689Skan  if (n_constants > 1)
3313169689Skan    canonicalized = 1;
331490075Sobrien
3315169689Skan  gcc_assert (n_ops >= 2);
331696263Sobrien
3317169689Skan  /* If we only have two operands, we can avoid the loops.  */
3318169689Skan  if (n_ops == 2)
3319169689Skan    {
3320169689Skan      enum rtx_code code = ops[0].neg || ops[1].neg ? MINUS : PLUS;
3321169689Skan      rtx lhs, rhs;
332290075Sobrien
3323169689Skan      /* Get the two operands.  Be careful with the order, especially for
3324169689Skan	 the cases where code == MINUS.  */
3325169689Skan      if (ops[0].neg && ops[1].neg)
3326169689Skan	{
3327169689Skan	  lhs = gen_rtx_NEG (mode, ops[0].op);
3328169689Skan	  rhs = ops[1].op;
3329169689Skan	}
3330169689Skan      else if (ops[0].neg)
3331169689Skan	{
3332169689Skan	  lhs = ops[1].op;
3333169689Skan	  rhs = ops[0].op;
3334169689Skan	}
3335169689Skan      else
3336169689Skan	{
3337169689Skan	  lhs = ops[0].op;
3338169689Skan	  rhs = ops[1].op;
3339169689Skan	}
3340169689Skan
3341169689Skan      return simplify_const_binary_operation (code, mode, lhs, rhs);
3342169689Skan    }
3343169689Skan
3344169689Skan  /* Now simplify each pair of operands until nothing changes.  */
334590075Sobrien  do
334690075Sobrien    {
3347169689Skan      /* Insertion sort is good enough for an eight-element array.  */
3348169689Skan      for (i = 1; i < n_ops; i++)
3349169689Skan        {
3350169689Skan          struct simplify_plus_minus_op_data save;
3351169689Skan          j = i - 1;
3352169689Skan          if (simplify_plus_minus_op_data_cmp (&ops[j], &ops[i]) < 0)
3353169689Skan	    continue;
335490075Sobrien
3355169689Skan          canonicalized = 1;
3356169689Skan          save = ops[i];
3357169689Skan          do
3358169689Skan	    ops[j + 1] = ops[j];
3359169689Skan          while (j-- && simplify_plus_minus_op_data_cmp (&ops[j], &save) > 0);
3360169689Skan          ops[j + 1] = save;
3361169689Skan        }
3362169689Skan
3363169689Skan      /* This is only useful the first time through.  */
3364169689Skan      if (!canonicalized)
3365169689Skan        return NULL_RTX;
3366169689Skan
3367169689Skan      changed = 0;
3368169689Skan      for (i = n_ops - 1; i > 0; i--)
3369169689Skan	for (j = i - 1; j >= 0; j--)
337090075Sobrien	  {
3371169689Skan	    rtx lhs = ops[j].op, rhs = ops[i].op;
3372169689Skan	    int lneg = ops[j].neg, rneg = ops[i].neg;
337390075Sobrien
3374169689Skan	    if (lhs != 0 && rhs != 0)
337590075Sobrien	      {
337690075Sobrien		enum rtx_code ncode = PLUS;
337790075Sobrien
337890075Sobrien		if (lneg != rneg)
337990075Sobrien		  {
338090075Sobrien		    ncode = MINUS;
338190075Sobrien		    if (lneg)
338290075Sobrien		      tem = lhs, lhs = rhs, rhs = tem;
338390075Sobrien		  }
338490075Sobrien		else if (swap_commutative_operands_p (lhs, rhs))
338590075Sobrien		  tem = lhs, lhs = rhs, rhs = tem;
338690075Sobrien
3387169689Skan		if ((GET_CODE (lhs) == CONST || GET_CODE (lhs) == CONST_INT)
3388169689Skan		    && (GET_CODE (rhs) == CONST || GET_CODE (rhs) == CONST_INT))
3389169689Skan		  {
3390169689Skan		    rtx tem_lhs, tem_rhs;
339190075Sobrien
3392169689Skan		    tem_lhs = GET_CODE (lhs) == CONST ? XEXP (lhs, 0) : lhs;
3393169689Skan		    tem_rhs = GET_CODE (rhs) == CONST ? XEXP (rhs, 0) : rhs;
3394169689Skan		    tem = simplify_binary_operation (ncode, mode, tem_lhs, tem_rhs);
3395169689Skan
3396169689Skan		    if (tem && !CONSTANT_P (tem))
3397169689Skan		      tem = gen_rtx_CONST (GET_MODE (tem), tem);
3398169689Skan		  }
3399169689Skan		else
3400169689Skan		  tem = simplify_binary_operation (ncode, mode, lhs, rhs);
3401169689Skan
3402117395Skan		/* Reject "simplifications" that just wrap the two
340390075Sobrien		   arguments in a CONST.  Failure to do so can result
340490075Sobrien		   in infinite recursion with simplify_binary_operation
340590075Sobrien		   when it calls us to simplify CONST operations.  */
340690075Sobrien		if (tem
340790075Sobrien		    && ! (GET_CODE (tem) == CONST
340890075Sobrien			  && GET_CODE (XEXP (tem, 0)) == ncode
340990075Sobrien			  && XEXP (XEXP (tem, 0), 0) == lhs
3410169689Skan			  && XEXP (XEXP (tem, 0), 1) == rhs))
341190075Sobrien		  {
341290075Sobrien		    lneg &= rneg;
341390075Sobrien		    if (GET_CODE (tem) == NEG)
341490075Sobrien		      tem = XEXP (tem, 0), lneg = !lneg;
341590075Sobrien		    if (GET_CODE (tem) == CONST_INT && lneg)
341690075Sobrien		      tem = neg_const_int (mode, tem), lneg = 0;
341790075Sobrien
341890075Sobrien		    ops[i].op = tem;
341990075Sobrien		    ops[i].neg = lneg;
342090075Sobrien		    ops[j].op = NULL_RTX;
342190075Sobrien		    changed = 1;
342290075Sobrien		  }
342390075Sobrien	      }
342490075Sobrien	  }
342590075Sobrien
3426169689Skan      /* Pack all the operands to the lower-numbered entries.  */
3427169689Skan      for (i = 0, j = 0; j < n_ops; j++)
3428169689Skan        if (ops[j].op)
3429169689Skan          {
3430169689Skan	    ops[i] = ops[j];
3431169689Skan	    i++;
3432169689Skan          }
3433169689Skan      n_ops = i;
343490075Sobrien    }
343590075Sobrien  while (changed);
343690075Sobrien
3437132718Skan  /* Create (minus -C X) instead of (neg (const (plus X C))).  */
3438132718Skan  if (n_ops == 2
3439132718Skan      && GET_CODE (ops[1].op) == CONST_INT
3440132718Skan      && CONSTANT_P (ops[0].op)
3441132718Skan      && ops[0].neg)
3442132718Skan    return gen_rtx_fmt_ee (MINUS, mode, ops[1].op, ops[0].op);
3443132718Skan
344490075Sobrien  /* We suppressed creation of trivial CONST expressions in the
344590075Sobrien     combination loop to avoid recursion.  Create one manually now.
344690075Sobrien     The combination loop should have ensured that there is exactly
344790075Sobrien     one CONST_INT, and the sort will have ensured that it is last
344890075Sobrien     in the array and that any other constant will be next-to-last.  */
344990075Sobrien
345090075Sobrien  if (n_ops > 1
345190075Sobrien      && GET_CODE (ops[n_ops - 1].op) == CONST_INT
345290075Sobrien      && CONSTANT_P (ops[n_ops - 2].op))
345390075Sobrien    {
345490075Sobrien      rtx value = ops[n_ops - 1].op;
345590075Sobrien      if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg)
345690075Sobrien	value = neg_const_int (mode, value);
345790075Sobrien      ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value));
345890075Sobrien      n_ops--;
345990075Sobrien    }
346090075Sobrien
3461132718Skan  /* Put a non-negated operand first, if possible.  */
346290075Sobrien
346390075Sobrien  for (i = 0; i < n_ops && ops[i].neg; i++)
346490075Sobrien    continue;
346590075Sobrien  if (i == n_ops)
3466132718Skan    ops[0].op = gen_rtx_NEG (mode, ops[0].op);
346790075Sobrien  else if (i != 0)
346890075Sobrien    {
346990075Sobrien      tem = ops[0].op;
347090075Sobrien      ops[0] = ops[i];
347190075Sobrien      ops[i].op = tem;
347290075Sobrien      ops[i].neg = 1;
347390075Sobrien    }
347490075Sobrien
347590075Sobrien  /* Now make the result by performing the requested operations.  */
347690075Sobrien  result = ops[0].op;
347790075Sobrien  for (i = 1; i < n_ops; i++)
347890075Sobrien    result = gen_rtx_fmt_ee (ops[i].neg ? MINUS : PLUS,
347990075Sobrien			     mode, result, ops[i].op);
348090075Sobrien
3481132718Skan  return result;
348290075Sobrien}
348390075Sobrien
3484169689Skan/* Check whether an operand is suitable for calling simplify_plus_minus.  */
3485169689Skanstatic bool
3486169689Skanplus_minus_operand_p (rtx x)
3487169689Skan{
3488169689Skan  return GET_CODE (x) == PLUS
3489169689Skan         || GET_CODE (x) == MINUS
3490169689Skan	 || (GET_CODE (x) == CONST
3491169689Skan	     && GET_CODE (XEXP (x, 0)) == PLUS
3492169689Skan	     && CONSTANT_P (XEXP (XEXP (x, 0), 0))
3493169689Skan	     && CONSTANT_P (XEXP (XEXP (x, 0), 1)));
3494169689Skan}
3495169689Skan
349690075Sobrien/* Like simplify_binary_operation except used for relational operators.
3497169689Skan   MODE is the mode of the result. If MODE is VOIDmode, both operands must
3498169689Skan   not also be VOIDmode.
349990075Sobrien
3500169689Skan   CMP_MODE specifies in which mode the comparison is done in, so it is
3501169689Skan   the mode of the operands.  If CMP_MODE is VOIDmode, it is taken from
3502169689Skan   the operands or, if both are VOIDmode, the operands are compared in
3503169689Skan   "infinite precision".  */
350490075Sobrienrtx
3505132718Skansimplify_relational_operation (enum rtx_code code, enum machine_mode mode,
3506169689Skan			       enum machine_mode cmp_mode, rtx op0, rtx op1)
350790075Sobrien{
3508169689Skan  rtx tem, trueop0, trueop1;
3509169689Skan
3510169689Skan  if (cmp_mode == VOIDmode)
3511169689Skan    cmp_mode = GET_MODE (op0);
3512169689Skan  if (cmp_mode == VOIDmode)
3513169689Skan    cmp_mode = GET_MODE (op1);
3514169689Skan
3515169689Skan  tem = simplify_const_relational_operation (code, cmp_mode, op0, op1);
3516169689Skan  if (tem)
3517169689Skan    {
3518169689Skan      if (SCALAR_FLOAT_MODE_P (mode))
3519169689Skan	{
3520169689Skan          if (tem == const0_rtx)
3521169689Skan            return CONST0_RTX (mode);
3522169689Skan#ifdef FLOAT_STORE_FLAG_VALUE
3523169689Skan	  {
3524169689Skan	    REAL_VALUE_TYPE val;
3525169689Skan	    val = FLOAT_STORE_FLAG_VALUE (mode);
3526169689Skan	    return CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
3527169689Skan	  }
3528169689Skan#else
3529169689Skan	  return NULL_RTX;
3530169689Skan#endif
3531169689Skan	}
3532169689Skan      if (VECTOR_MODE_P (mode))
3533169689Skan	{
3534169689Skan	  if (tem == const0_rtx)
3535169689Skan	    return CONST0_RTX (mode);
3536169689Skan#ifdef VECTOR_STORE_FLAG_VALUE
3537169689Skan	  {
3538169689Skan	    int i, units;
3539169689Skan	    rtvec v;
3540169689Skan
3541169689Skan	    rtx val = VECTOR_STORE_FLAG_VALUE (mode);
3542169689Skan	    if (val == NULL_RTX)
3543169689Skan	      return NULL_RTX;
3544169689Skan	    if (val == const1_rtx)
3545169689Skan	      return CONST1_RTX (mode);
3546169689Skan
3547169689Skan	    units = GET_MODE_NUNITS (mode);
3548169689Skan	    v = rtvec_alloc (units);
3549169689Skan	    for (i = 0; i < units; i++)
3550169689Skan	      RTVEC_ELT (v, i) = val;
3551169689Skan	    return gen_rtx_raw_CONST_VECTOR (mode, v);
3552169689Skan	  }
3553169689Skan#else
3554169689Skan	  return NULL_RTX;
3555169689Skan#endif
3556169689Skan	}
3557169689Skan
3558169689Skan      return tem;
3559169689Skan    }
3560169689Skan
3561169689Skan  /* For the following tests, ensure const0_rtx is op1.  */
3562169689Skan  if (swap_commutative_operands_p (op0, op1)
3563169689Skan      || (op0 == const0_rtx && op1 != const0_rtx))
3564169689Skan    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
3565169689Skan
3566169689Skan  /* If op0 is a compare, extract the comparison arguments from it.  */
3567169689Skan  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
3568169689Skan    return simplify_relational_operation (code, mode, VOIDmode,
3569169689Skan				          XEXP (op0, 0), XEXP (op0, 1));
3570169689Skan
3571169689Skan  if (GET_MODE_CLASS (cmp_mode) == MODE_CC
3572169689Skan      || CC0_P (op0))
3573169689Skan    return NULL_RTX;
3574169689Skan
3575169689Skan  trueop0 = avoid_constant_pool_reference (op0);
3576169689Skan  trueop1 = avoid_constant_pool_reference (op1);
3577169689Skan  return simplify_relational_operation_1 (code, mode, cmp_mode,
3578169689Skan		  			  trueop0, trueop1);
3579169689Skan}
3580169689Skan
3581169689Skan/* This part of simplify_relational_operation is only used when CMP_MODE
3582169689Skan   is not in class MODE_CC (i.e. it is a real comparison).
3583169689Skan
3584169689Skan   MODE is the mode of the result, while CMP_MODE specifies in which
3585169689Skan   mode the comparison is done in, so it is the mode of the operands.  */
3586169689Skan
3587169689Skanstatic rtx
3588169689Skansimplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
3589169689Skan				 enum machine_mode cmp_mode, rtx op0, rtx op1)
3590169689Skan{
3591169689Skan  enum rtx_code op0code = GET_CODE (op0);
3592169689Skan
3593169689Skan  if (GET_CODE (op1) == CONST_INT)
3594169689Skan    {
3595169689Skan      if (INTVAL (op1) == 0 && COMPARISON_P (op0))
3596169689Skan	{
3597169689Skan	  /* If op0 is a comparison, extract the comparison arguments
3598169689Skan	     from it.  */
3599169689Skan	  if (code == NE)
3600169689Skan	    {
3601169689Skan	      if (GET_MODE (op0) == mode)
3602169689Skan		return simplify_rtx (op0);
3603169689Skan	      else
3604169689Skan		return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
3605169689Skan					        XEXP (op0, 0), XEXP (op0, 1));
3606169689Skan	    }
3607169689Skan	  else if (code == EQ)
3608169689Skan	    {
3609169689Skan	      enum rtx_code new_code = reversed_comparison_code (op0, NULL_RTX);
3610169689Skan	      if (new_code != UNKNOWN)
3611169689Skan	        return simplify_gen_relational (new_code, mode, VOIDmode,
3612169689Skan					        XEXP (op0, 0), XEXP (op0, 1));
3613169689Skan	    }
3614169689Skan	}
3615169689Skan    }
3616169689Skan
3617169689Skan  /* (eq/ne (plus x cst1) cst2) simplifies to (eq/ne x (cst2 - cst1))  */
3618169689Skan  if ((code == EQ || code == NE)
3619169689Skan      && (op0code == PLUS || op0code == MINUS)
3620169689Skan      && CONSTANT_P (op1)
3621169689Skan      && CONSTANT_P (XEXP (op0, 1))
3622169689Skan      && (INTEGRAL_MODE_P (cmp_mode) || flag_unsafe_math_optimizations))
3623169689Skan    {
3624169689Skan      rtx x = XEXP (op0, 0);
3625169689Skan      rtx c = XEXP (op0, 1);
3626169689Skan
3627169689Skan      c = simplify_gen_binary (op0code == PLUS ? MINUS : PLUS,
3628169689Skan			       cmp_mode, op1, c);
3629169689Skan      return simplify_gen_relational (code, mode, cmp_mode, x, c);
3630169689Skan    }
3631169689Skan
3632169689Skan  /* (ne:SI (zero_extract:SI FOO (const_int 1) BAR) (const_int 0))) is
3633169689Skan     the same as (zero_extract:SI FOO (const_int 1) BAR).  */
3634169689Skan  if (code == NE
3635169689Skan      && op1 == const0_rtx
3636169689Skan      && GET_MODE_CLASS (mode) == MODE_INT
3637169689Skan      && cmp_mode != VOIDmode
3638169689Skan      /* ??? Work-around BImode bugs in the ia64 backend.  */
3639169689Skan      && mode != BImode
3640169689Skan      && cmp_mode != BImode
3641169689Skan      && nonzero_bits (op0, cmp_mode) == 1
3642169689Skan      && STORE_FLAG_VALUE == 1)
3643169689Skan    return GET_MODE_SIZE (mode) > GET_MODE_SIZE (cmp_mode)
3644169689Skan	   ? simplify_gen_unary (ZERO_EXTEND, mode, op0, cmp_mode)
3645169689Skan	   : lowpart_subreg (mode, op0, cmp_mode);
3646169689Skan
3647169689Skan  /* (eq/ne (xor x y) 0) simplifies to (eq/ne x y).  */
3648169689Skan  if ((code == EQ || code == NE)
3649169689Skan      && op1 == const0_rtx
3650169689Skan      && op0code == XOR)
3651169689Skan    return simplify_gen_relational (code, mode, cmp_mode,
3652169689Skan				    XEXP (op0, 0), XEXP (op0, 1));
3653169689Skan
3654169689Skan  /* (eq/ne (xor x y) x) simplifies to (eq/ne y 0).  */
3655169689Skan  if ((code == EQ || code == NE)
3656169689Skan      && op0code == XOR
3657169689Skan      && rtx_equal_p (XEXP (op0, 0), op1)
3658169689Skan      && !side_effects_p (XEXP (op0, 0)))
3659169689Skan    return simplify_gen_relational (code, mode, cmp_mode,
3660169689Skan				    XEXP (op0, 1), const0_rtx);
3661169689Skan
3662169689Skan  /* Likewise (eq/ne (xor x y) y) simplifies to (eq/ne x 0).  */
3663169689Skan  if ((code == EQ || code == NE)
3664169689Skan      && op0code == XOR
3665169689Skan      && rtx_equal_p (XEXP (op0, 1), op1)
3666169689Skan      && !side_effects_p (XEXP (op0, 1)))
3667169689Skan    return simplify_gen_relational (code, mode, cmp_mode,
3668169689Skan				    XEXP (op0, 0), const0_rtx);
3669169689Skan
3670169689Skan  /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
3671169689Skan  if ((code == EQ || code == NE)
3672169689Skan      && op0code == XOR
3673169689Skan      && (GET_CODE (op1) == CONST_INT
3674169689Skan	  || GET_CODE (op1) == CONST_DOUBLE)
3675169689Skan      && (GET_CODE (XEXP (op0, 1)) == CONST_INT
3676169689Skan	  || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE))
3677169689Skan    return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
3678169689Skan				    simplify_gen_binary (XOR, cmp_mode,
3679169689Skan							 XEXP (op0, 1), op1));
3680169689Skan
3681169689Skan  return NULL_RTX;
3682169689Skan}
3683169689Skan
3684169689Skan/* Check if the given comparison (done in the given MODE) is actually a
3685169689Skan   tautology or a contradiction.
3686169689Skan   If no simplification is possible, this function returns zero.
3687169689Skan   Otherwise, it returns either const_true_rtx or const0_rtx.  */
3688169689Skan
3689169689Skanrtx
3690169689Skansimplify_const_relational_operation (enum rtx_code code,
3691169689Skan				     enum machine_mode mode,
3692169689Skan				     rtx op0, rtx op1)
3693169689Skan{
369490075Sobrien  int equal, op0lt, op0ltu, op1lt, op1ltu;
369590075Sobrien  rtx tem;
369690075Sobrien  rtx trueop0;
369790075Sobrien  rtx trueop1;
369890075Sobrien
3699169689Skan  gcc_assert (mode != VOIDmode
3700169689Skan	      || (GET_MODE (op0) == VOIDmode
3701169689Skan		  && GET_MODE (op1) == VOIDmode));
370290075Sobrien
370390075Sobrien  /* If op0 is a compare, extract the comparison arguments from it.  */
370490075Sobrien  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
3705169689Skan    {
3706169689Skan      op1 = XEXP (op0, 1);
3707169689Skan      op0 = XEXP (op0, 0);
370890075Sobrien
3709169689Skan      if (GET_MODE (op0) != VOIDmode)
3710169689Skan	mode = GET_MODE (op0);
3711169689Skan      else if (GET_MODE (op1) != VOIDmode)
3712169689Skan	mode = GET_MODE (op1);
3713169689Skan      else
3714169689Skan	return 0;
3715169689Skan    }
371690075Sobrien
371790075Sobrien  /* We can't simplify MODE_CC values since we don't know what the
371890075Sobrien     actual comparison is.  */
3719132718Skan  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC || CC0_P (op0))
372090075Sobrien    return 0;
372190075Sobrien
372290075Sobrien  /* Make sure the constant is second.  */
3723169689Skan  if (swap_commutative_operands_p (op0, op1))
372490075Sobrien    {
372590075Sobrien      tem = op0, op0 = op1, op1 = tem;
372690075Sobrien      code = swap_condition (code);
372790075Sobrien    }
372890075Sobrien
3729169689Skan  trueop0 = avoid_constant_pool_reference (op0);
3730169689Skan  trueop1 = avoid_constant_pool_reference (op1);
3731169689Skan
373290075Sobrien  /* For integer comparisons of A and B maybe we can simplify A - B and can
373390075Sobrien     then simplify a comparison of that with zero.  If A and B are both either
373490075Sobrien     a register or a CONST_INT, this can't help; testing for these cases will
373590075Sobrien     prevent infinite recursion here and speed things up.
373690075Sobrien
3737169689Skan     We can only do this for EQ and NE comparisons as otherwise we may
3738169689Skan     lose or introduce overflow which we cannot disregard as undefined as
3739169689Skan     we do not know the signedness of the operation on either the left or
3740169689Skan     the right hand side of the comparison.  */
374190075Sobrien
374290075Sobrien  if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
3743169689Skan      && (code == EQ || code == NE)
3744169689Skan      && ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
3745169689Skan	    && (REG_P (op1) || GET_CODE (trueop1) == CONST_INT))
374690075Sobrien      && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
3747169689Skan      /* We cannot do this if tem is a nonzero address.  */
3748169689Skan      && ! nonzero_address_p (tem))
3749169689Skan    return simplify_const_relational_operation (signed_condition (code),
3750169689Skan						mode, tem, const0_rtx);
375190075Sobrien
3752169689Skan  if (! HONOR_NANS (mode) && code == ORDERED)
375390075Sobrien    return const_true_rtx;
375490075Sobrien
3755169689Skan  if (! HONOR_NANS (mode) && code == UNORDERED)
375690075Sobrien    return const0_rtx;
375790075Sobrien
3758117395Skan  /* For modes without NaNs, if the two operands are equal, we know the
3759132718Skan     result except if they have side-effects.  */
3760132718Skan  if (! HONOR_NANS (GET_MODE (trueop0))
3761117395Skan      && rtx_equal_p (trueop0, trueop1)
3762117395Skan      && ! side_effects_p (trueop0))
376390075Sobrien    equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
376490075Sobrien
376590075Sobrien  /* If the operands are floating-point constants, see if we can fold
376690075Sobrien     the result.  */
376790075Sobrien  else if (GET_CODE (trueop0) == CONST_DOUBLE
376890075Sobrien	   && GET_CODE (trueop1) == CONST_DOUBLE
3769169689Skan	   && SCALAR_FLOAT_MODE_P (GET_MODE (trueop0)))
377090075Sobrien    {
3771117395Skan      REAL_VALUE_TYPE d0, d1;
377290075Sobrien
3773117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (d0, trueop0);
3774117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (d1, trueop1);
377590075Sobrien
3776117395Skan      /* Comparisons are unordered iff at least one of the values is NaN.  */
3777117395Skan      if (REAL_VALUE_ISNAN (d0) || REAL_VALUE_ISNAN (d1))
377890075Sobrien	switch (code)
377990075Sobrien	  {
378090075Sobrien	  case UNEQ:
378190075Sobrien	  case UNLT:
378290075Sobrien	  case UNGT:
378390075Sobrien	  case UNLE:
378490075Sobrien	  case UNGE:
378590075Sobrien	  case NE:
378690075Sobrien	  case UNORDERED:
378790075Sobrien	    return const_true_rtx;
378890075Sobrien	  case EQ:
378990075Sobrien	  case LT:
379090075Sobrien	  case GT:
379190075Sobrien	  case LE:
379290075Sobrien	  case GE:
379390075Sobrien	  case LTGT:
379490075Sobrien	  case ORDERED:
379590075Sobrien	    return const0_rtx;
379690075Sobrien	  default:
379790075Sobrien	    return 0;
379890075Sobrien	  }
379990075Sobrien
3800117395Skan      equal = REAL_VALUES_EQUAL (d0, d1);
3801117395Skan      op0lt = op0ltu = REAL_VALUES_LESS (d0, d1);
3802117395Skan      op1lt = op1ltu = REAL_VALUES_LESS (d1, d0);
380390075Sobrien    }
380490075Sobrien
380590075Sobrien  /* Otherwise, see if the operands are both integers.  */
380690075Sobrien  else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
380790075Sobrien	   && (GET_CODE (trueop0) == CONST_DOUBLE
380890075Sobrien	       || GET_CODE (trueop0) == CONST_INT)
380990075Sobrien	   && (GET_CODE (trueop1) == CONST_DOUBLE
381090075Sobrien	       || GET_CODE (trueop1) == CONST_INT))
381190075Sobrien    {
381290075Sobrien      int width = GET_MODE_BITSIZE (mode);
381390075Sobrien      HOST_WIDE_INT l0s, h0s, l1s, h1s;
381490075Sobrien      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
381590075Sobrien
381690075Sobrien      /* Get the two words comprising each integer constant.  */
381790075Sobrien      if (GET_CODE (trueop0) == CONST_DOUBLE)
381890075Sobrien	{
381990075Sobrien	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
382090075Sobrien	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
382190075Sobrien	}
382290075Sobrien      else
382390075Sobrien	{
382490075Sobrien	  l0u = l0s = INTVAL (trueop0);
382590075Sobrien	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
382690075Sobrien	}
3827117395Skan
382890075Sobrien      if (GET_CODE (trueop1) == CONST_DOUBLE)
382990075Sobrien	{
383090075Sobrien	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
383190075Sobrien	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
383290075Sobrien	}
383390075Sobrien      else
383490075Sobrien	{
383590075Sobrien	  l1u = l1s = INTVAL (trueop1);
383690075Sobrien	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
383790075Sobrien	}
383890075Sobrien
383990075Sobrien      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
384090075Sobrien	 we have to sign or zero-extend the values.  */
384190075Sobrien      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
384290075Sobrien	{
384390075Sobrien	  l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
384490075Sobrien	  l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
384590075Sobrien
384690075Sobrien	  if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
384790075Sobrien	    l0s |= ((HOST_WIDE_INT) (-1) << width);
384890075Sobrien
384990075Sobrien	  if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
385090075Sobrien	    l1s |= ((HOST_WIDE_INT) (-1) << width);
385190075Sobrien	}
385290075Sobrien      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
385390075Sobrien	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
385490075Sobrien
385590075Sobrien      equal = (h0u == h1u && l0u == l1u);
385690075Sobrien      op0lt = (h0s < h1s || (h0s == h1s && l0u < l1u));
385790075Sobrien      op1lt = (h1s < h0s || (h1s == h0s && l1u < l0u));
385890075Sobrien      op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
385990075Sobrien      op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
386090075Sobrien    }
386190075Sobrien
386290075Sobrien  /* Otherwise, there are some code-specific tests we can make.  */
386390075Sobrien  else
386490075Sobrien    {
3865169689Skan      /* Optimize comparisons with upper and lower bounds.  */
3866169689Skan      if (SCALAR_INT_MODE_P (mode)
3867169689Skan	  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
3868169689Skan	{
3869169689Skan	  rtx mmin, mmax;
3870169689Skan	  int sign;
3871169689Skan
3872169689Skan	  if (code == GEU
3873169689Skan	      || code == LEU
3874169689Skan	      || code == GTU
3875169689Skan	      || code == LTU)
3876169689Skan	    sign = 0;
3877169689Skan	  else
3878169689Skan	    sign = 1;
3879169689Skan
3880169689Skan	  get_mode_bounds (mode, sign, mode, &mmin, &mmax);
3881169689Skan
3882169689Skan	  tem = NULL_RTX;
3883169689Skan	  switch (code)
3884169689Skan	    {
3885169689Skan	    case GEU:
3886169689Skan	    case GE:
3887169689Skan	      /* x >= min is always true.  */
3888169689Skan	      if (rtx_equal_p (trueop1, mmin))
3889169689Skan		tem = const_true_rtx;
3890169689Skan	      else
3891169689Skan	      break;
3892169689Skan
3893169689Skan	    case LEU:
3894169689Skan	    case LE:
3895169689Skan	      /* x <= max is always true.  */
3896169689Skan	      if (rtx_equal_p (trueop1, mmax))
3897169689Skan		tem = const_true_rtx;
3898169689Skan	      break;
3899169689Skan
3900169689Skan	    case GTU:
3901169689Skan	    case GT:
3902169689Skan	      /* x > max is always false.  */
3903169689Skan	      if (rtx_equal_p (trueop1, mmax))
3904169689Skan		tem = const0_rtx;
3905169689Skan	      break;
3906169689Skan
3907169689Skan	    case LTU:
3908169689Skan	    case LT:
3909169689Skan	      /* x < min is always false.  */
3910169689Skan	      if (rtx_equal_p (trueop1, mmin))
3911169689Skan		tem = const0_rtx;
3912169689Skan	      break;
3913169689Skan
3914169689Skan	    default:
3915169689Skan	      break;
3916169689Skan	    }
3917169689Skan	  if (tem == const0_rtx
3918169689Skan	      || tem == const_true_rtx)
3919169689Skan	    return tem;
3920169689Skan	}
3921169689Skan
392290075Sobrien      switch (code)
392390075Sobrien	{
392490075Sobrien	case EQ:
3925132718Skan	  if (trueop1 == const0_rtx && nonzero_address_p (op0))
392690075Sobrien	    return const0_rtx;
392790075Sobrien	  break;
392890075Sobrien
392990075Sobrien	case NE:
3930132718Skan	  if (trueop1 == const0_rtx && nonzero_address_p (op0))
393190075Sobrien	    return const_true_rtx;
393290075Sobrien	  break;
393390075Sobrien
3934117395Skan	case LT:
3935117395Skan	  /* Optimize abs(x) < 0.0.  */
3936169689Skan	  if (trueop1 == CONST0_RTX (mode)
3937169689Skan	      && !HONOR_SNANS (mode)
3938169689Skan	      && (!INTEGRAL_MODE_P (mode)
3939169689Skan		  || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
3940117395Skan	    {
3941117395Skan	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
3942117395Skan						       : trueop0;
3943117395Skan	      if (GET_CODE (tem) == ABS)
3944169689Skan		{
3945169689Skan		  if (INTEGRAL_MODE_P (mode)
3946169689Skan		      && (issue_strict_overflow_warning
3947169689Skan			  (WARN_STRICT_OVERFLOW_CONDITIONAL)))
3948169689Skan		    warning (OPT_Wstrict_overflow,
3949169689Skan			     ("assuming signed overflow does not occur when "
3950169689Skan			      "assuming abs (x) < 0 is false"));
3951169689Skan		  return const0_rtx;
3952169689Skan		}
3953117395Skan	    }
3954117395Skan	  break;
3955117395Skan
3956117395Skan	case GE:
3957117395Skan	  /* Optimize abs(x) >= 0.0.  */
3958169689Skan	  if (trueop1 == CONST0_RTX (mode)
3959169689Skan	      && !HONOR_NANS (mode)
3960169689Skan	      && (!INTEGRAL_MODE_P (mode)
3961169689Skan		  || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
3962117395Skan	    {
3963117395Skan	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
3964117395Skan						       : trueop0;
3965117395Skan	      if (GET_CODE (tem) == ABS)
3966169689Skan		{
3967169689Skan		  if (INTEGRAL_MODE_P (mode)
3968169689Skan		      && (issue_strict_overflow_warning
3969169689Skan			  (WARN_STRICT_OVERFLOW_CONDITIONAL)))
3970169689Skan		    warning (OPT_Wstrict_overflow,
3971169689Skan			     ("assuming signed overflow does not occur when "
3972169689Skan			      "assuming abs (x) >= 0 is true"));
3973169689Skan		  return const_true_rtx;
3974169689Skan		}
3975117395Skan	    }
3976117395Skan	  break;
3977117395Skan
3978132718Skan	case UNGE:
3979132718Skan	  /* Optimize ! (abs(x) < 0.0).  */
3980132718Skan	  if (trueop1 == CONST0_RTX (mode))
3981132718Skan	    {
3982132718Skan	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
3983132718Skan						       : trueop0;
3984132718Skan	      if (GET_CODE (tem) == ABS)
3985132718Skan		return const_true_rtx;
3986132718Skan	    }
3987132718Skan	  break;
3988132718Skan
398990075Sobrien	default:
399090075Sobrien	  break;
399190075Sobrien	}
399290075Sobrien
399390075Sobrien      return 0;
399490075Sobrien    }
399590075Sobrien
399690075Sobrien  /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
399790075Sobrien     as appropriate.  */
399890075Sobrien  switch (code)
399990075Sobrien    {
400090075Sobrien    case EQ:
400190075Sobrien    case UNEQ:
400290075Sobrien      return equal ? const_true_rtx : const0_rtx;
400390075Sobrien    case NE:
400490075Sobrien    case LTGT:
400590075Sobrien      return ! equal ? const_true_rtx : const0_rtx;
400690075Sobrien    case LT:
400790075Sobrien    case UNLT:
400890075Sobrien      return op0lt ? const_true_rtx : const0_rtx;
400990075Sobrien    case GT:
401090075Sobrien    case UNGT:
401190075Sobrien      return op1lt ? const_true_rtx : const0_rtx;
401290075Sobrien    case LTU:
401390075Sobrien      return op0ltu ? const_true_rtx : const0_rtx;
401490075Sobrien    case GTU:
401590075Sobrien      return op1ltu ? const_true_rtx : const0_rtx;
401690075Sobrien    case LE:
401790075Sobrien    case UNLE:
401890075Sobrien      return equal || op0lt ? const_true_rtx : const0_rtx;
401990075Sobrien    case GE:
402090075Sobrien    case UNGE:
402190075Sobrien      return equal || op1lt ? const_true_rtx : const0_rtx;
402290075Sobrien    case LEU:
402390075Sobrien      return equal || op0ltu ? const_true_rtx : const0_rtx;
402490075Sobrien    case GEU:
402590075Sobrien      return equal || op1ltu ? const_true_rtx : const0_rtx;
402690075Sobrien    case ORDERED:
402790075Sobrien      return const_true_rtx;
402890075Sobrien    case UNORDERED:
402990075Sobrien      return const0_rtx;
403090075Sobrien    default:
4031169689Skan      gcc_unreachable ();
403290075Sobrien    }
403390075Sobrien}
403490075Sobrien
403590075Sobrien/* Simplify CODE, an operation with result mode MODE and three operands,
403690075Sobrien   OP0, OP1, and OP2.  OP0_MODE was the mode of OP0 before it became
403790075Sobrien   a constant.  Return 0 if no simplifications is possible.  */
403890075Sobrien
403990075Sobrienrtx
4040132718Skansimplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
4041132718Skan			    enum machine_mode op0_mode, rtx op0, rtx op1,
4042132718Skan			    rtx op2)
404390075Sobrien{
404490075Sobrien  unsigned int width = GET_MODE_BITSIZE (mode);
404590075Sobrien
404690075Sobrien  /* VOIDmode means "infinite" precision.  */
404790075Sobrien  if (width == 0)
404890075Sobrien    width = HOST_BITS_PER_WIDE_INT;
404990075Sobrien
405090075Sobrien  switch (code)
405190075Sobrien    {
405290075Sobrien    case SIGN_EXTRACT:
405390075Sobrien    case ZERO_EXTRACT:
405490075Sobrien      if (GET_CODE (op0) == CONST_INT
405590075Sobrien	  && GET_CODE (op1) == CONST_INT
405690075Sobrien	  && GET_CODE (op2) == CONST_INT
405790075Sobrien	  && ((unsigned) INTVAL (op1) + (unsigned) INTVAL (op2) <= width)
405890075Sobrien	  && width <= (unsigned) HOST_BITS_PER_WIDE_INT)
405990075Sobrien	{
406090075Sobrien	  /* Extracting a bit-field from a constant */
406190075Sobrien	  HOST_WIDE_INT val = INTVAL (op0);
406290075Sobrien
406390075Sobrien	  if (BITS_BIG_ENDIAN)
406490075Sobrien	    val >>= (GET_MODE_BITSIZE (op0_mode)
406590075Sobrien		     - INTVAL (op2) - INTVAL (op1));
406690075Sobrien	  else
406790075Sobrien	    val >>= INTVAL (op2);
406890075Sobrien
406990075Sobrien	  if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
407090075Sobrien	    {
407190075Sobrien	      /* First zero-extend.  */
407290075Sobrien	      val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
407390075Sobrien	      /* If desired, propagate sign bit.  */
407490075Sobrien	      if (code == SIGN_EXTRACT
407590075Sobrien		  && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1))))
407690075Sobrien		val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
407790075Sobrien	    }
407890075Sobrien
407990075Sobrien	  /* Clear the bits that don't belong in our mode,
408090075Sobrien	     unless they and our sign bit are all one.
408190075Sobrien	     So we get either a reasonable negative value or a reasonable
408290075Sobrien	     unsigned value for this mode.  */
408390075Sobrien	  if (width < HOST_BITS_PER_WIDE_INT
408490075Sobrien	      && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
408590075Sobrien		  != ((HOST_WIDE_INT) (-1) << (width - 1))))
408690075Sobrien	    val &= ((HOST_WIDE_INT) 1 << width) - 1;
408790075Sobrien
4088169689Skan	  return gen_int_mode (val, mode);
408990075Sobrien	}
409090075Sobrien      break;
409190075Sobrien
409290075Sobrien    case IF_THEN_ELSE:
409390075Sobrien      if (GET_CODE (op0) == CONST_INT)
409490075Sobrien	return op0 != const0_rtx ? op1 : op2;
409590075Sobrien
4096132718Skan      /* Convert c ? a : a into "a".  */
4097132718Skan      if (rtx_equal_p (op1, op2) && ! side_effects_p (op0))
409890075Sobrien	return op1;
4099132718Skan
4100132718Skan      /* Convert a != b ? a : b into "a".  */
4101132718Skan      if (GET_CODE (op0) == NE
4102132718Skan	  && ! side_effects_p (op0)
4103132718Skan	  && ! HONOR_NANS (mode)
4104132718Skan	  && ! HONOR_SIGNED_ZEROS (mode)
4105132718Skan	  && ((rtx_equal_p (XEXP (op0, 0), op1)
4106132718Skan	       && rtx_equal_p (XEXP (op0, 1), op2))
4107132718Skan	      || (rtx_equal_p (XEXP (op0, 0), op2)
4108132718Skan		  && rtx_equal_p (XEXP (op0, 1), op1))))
4109132718Skan	return op1;
4110132718Skan
4111132718Skan      /* Convert a == b ? a : b into "b".  */
4112132718Skan      if (GET_CODE (op0) == EQ
4113132718Skan	  && ! side_effects_p (op0)
4114132718Skan	  && ! HONOR_NANS (mode)
4115132718Skan	  && ! HONOR_SIGNED_ZEROS (mode)
4116132718Skan	  && ((rtx_equal_p (XEXP (op0, 0), op1)
4117132718Skan	       && rtx_equal_p (XEXP (op0, 1), op2))
4118132718Skan	      || (rtx_equal_p (XEXP (op0, 0), op2)
4119132718Skan		  && rtx_equal_p (XEXP (op0, 1), op1))))
412090075Sobrien	return op2;
4121132718Skan
4122169689Skan      if (COMPARISON_P (op0) && ! side_effects_p (op0))
412390075Sobrien	{
412490075Sobrien	  enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
412590075Sobrien					? GET_MODE (XEXP (op0, 1))
412690075Sobrien					: GET_MODE (XEXP (op0, 0)));
412790075Sobrien	  rtx temp;
412890075Sobrien
412990075Sobrien	  /* Look for happy constants in op1 and op2.  */
413090075Sobrien	  if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
413190075Sobrien	    {
413290075Sobrien	      HOST_WIDE_INT t = INTVAL (op1);
413390075Sobrien	      HOST_WIDE_INT f = INTVAL (op2);
4134117395Skan
413590075Sobrien	      if (t == STORE_FLAG_VALUE && f == 0)
413690075Sobrien	        code = GET_CODE (op0);
413790075Sobrien	      else if (t == 0 && f == STORE_FLAG_VALUE)
413890075Sobrien		{
413990075Sobrien		  enum rtx_code tmp;
414090075Sobrien		  tmp = reversed_comparison_code (op0, NULL_RTX);
414190075Sobrien		  if (tmp == UNKNOWN)
414290075Sobrien		    break;
414390075Sobrien		  code = tmp;
414490075Sobrien		}
414590075Sobrien	      else
414690075Sobrien		break;
414790075Sobrien
4148169689Skan	      return simplify_gen_relational (code, mode, cmp_mode,
4149169689Skan					      XEXP (op0, 0), XEXP (op0, 1));
415090075Sobrien	    }
4151169689Skan
4152169689Skan	  if (cmp_mode == VOIDmode)
4153169689Skan	    cmp_mode = op0_mode;
4154169689Skan	  temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
4155169689Skan			  			cmp_mode, XEXP (op0, 0),
4156169689Skan						XEXP (op0, 1));
4157169689Skan
4158169689Skan	  /* See if any simplifications were possible.  */
4159169689Skan	  if (temp)
4160169689Skan	    {
4161169689Skan	      if (GET_CODE (temp) == CONST_INT)
4162169689Skan		return temp == const0_rtx ? op2 : op1;
4163169689Skan	      else if (temp)
4164169689Skan	        return gen_rtx_IF_THEN_ELSE (mode, temp, op1, op2);
4165169689Skan	    }
416690075Sobrien	}
416790075Sobrien      break;
4168132718Skan
4169117395Skan    case VEC_MERGE:
4170169689Skan      gcc_assert (GET_MODE (op0) == mode);
4171169689Skan      gcc_assert (GET_MODE (op1) == mode);
4172169689Skan      gcc_assert (VECTOR_MODE_P (mode));
4173117395Skan      op2 = avoid_constant_pool_reference (op2);
4174132718Skan      if (GET_CODE (op2) == CONST_INT)
4175117395Skan	{
4176117395Skan          int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
4177117395Skan	  unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
4178132718Skan	  int mask = (1 << n_elts) - 1;
417990075Sobrien
4180132718Skan	  if (!(INTVAL (op2) & mask))
4181132718Skan	    return op1;
4182132718Skan	  if ((INTVAL (op2) & mask) == mask)
4183132718Skan	    return op0;
4184132718Skan
4185132718Skan	  op0 = avoid_constant_pool_reference (op0);
4186132718Skan	  op1 = avoid_constant_pool_reference (op1);
4187132718Skan	  if (GET_CODE (op0) == CONST_VECTOR
4188132718Skan	      && GET_CODE (op1) == CONST_VECTOR)
4189132718Skan	    {
4190132718Skan	      rtvec v = rtvec_alloc (n_elts);
4191132718Skan	      unsigned int i;
4192132718Skan
4193132718Skan	      for (i = 0; i < n_elts; i++)
4194132718Skan		RTVEC_ELT (v, i) = (INTVAL (op2) & (1 << i)
4195132718Skan				    ? CONST_VECTOR_ELT (op0, i)
4196132718Skan				    : CONST_VECTOR_ELT (op1, i));
4197132718Skan	      return gen_rtx_CONST_VECTOR (mode, v);
4198132718Skan	    }
4199117395Skan	}
4200117395Skan      break;
4201117395Skan
420290075Sobrien    default:
4203169689Skan      gcc_unreachable ();
420490075Sobrien    }
420590075Sobrien
420690075Sobrien  return 0;
420790075Sobrien}
420890075Sobrien
4209132718Skan/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_VECTOR,
4210132718Skan   returning another CONST_INT or CONST_DOUBLE or CONST_VECTOR.
4211132718Skan
4212132718Skan   Works by unpacking OP into a collection of 8-bit values
4213132718Skan   represented as a little-endian array of 'unsigned char', selecting by BYTE,
4214132718Skan   and then repacking them again for OUTERMODE.  */
4215132718Skan
4216132718Skanstatic rtx
4217132718Skansimplify_immed_subreg (enum machine_mode outermode, rtx op,
4218132718Skan		       enum machine_mode innermode, unsigned int byte)
421990075Sobrien{
4220132718Skan  /* We support up to 512-bit values (for V8DFmode).  */
4221132718Skan  enum {
4222132718Skan    max_bitsize = 512,
4223132718Skan    value_bit = 8,
4224132718Skan    value_mask = (1 << value_bit) - 1
4225132718Skan  };
4226132718Skan  unsigned char value[max_bitsize / value_bit];
4227132718Skan  int value_start;
4228132718Skan  int i;
4229132718Skan  int elem;
423090075Sobrien
4231132718Skan  int num_elem;
4232132718Skan  rtx * elems;
4233132718Skan  int elem_bitsize;
4234132718Skan  rtx result_s;
4235132718Skan  rtvec result_v = NULL;
4236132718Skan  enum mode_class outer_class;
4237132718Skan  enum machine_mode outer_submode;
423890075Sobrien
4239132718Skan  /* Some ports misuse CCmode.  */
4240132718Skan  if (GET_MODE_CLASS (outermode) == MODE_CC && GET_CODE (op) == CONST_INT)
424190075Sobrien    return op;
424290075Sobrien
4243169689Skan  /* We have no way to represent a complex constant at the rtl level.  */
4244169689Skan  if (COMPLEX_MODE_P (outermode))
4245169689Skan    return NULL_RTX;
4246169689Skan
4247132718Skan  /* Unpack the value.  */
4248132718Skan
4249117395Skan  if (GET_CODE (op) == CONST_VECTOR)
4250117395Skan    {
4251132718Skan      num_elem = CONST_VECTOR_NUNITS (op);
4252132718Skan      elems = &CONST_VECTOR_ELT (op, 0);
4253132718Skan      elem_bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (innermode));
4254132718Skan    }
4255132718Skan  else
4256132718Skan    {
4257132718Skan      num_elem = 1;
4258132718Skan      elems = &op;
4259132718Skan      elem_bitsize = max_bitsize;
4260132718Skan    }
4261169689Skan  /* If this asserts, it is too complicated; reducing value_bit may help.  */
4262169689Skan  gcc_assert (BITS_PER_UNIT % value_bit == 0);
4263169689Skan  /* I don't know how to handle endianness of sub-units.  */
4264169689Skan  gcc_assert (elem_bitsize % BITS_PER_UNIT == 0);
4265132718Skan
4266132718Skan  for (elem = 0; elem < num_elem; elem++)
4267132718Skan    {
4268132718Skan      unsigned char * vp;
4269132718Skan      rtx el = elems[elem];
4270132718Skan
4271132718Skan      /* Vectors are kept in target memory order.  (This is probably
4272132718Skan	 a mistake.)  */
4273132718Skan      {
4274132718Skan	unsigned byte = (elem * elem_bitsize) / BITS_PER_UNIT;
4275132718Skan	unsigned ibyte = (((num_elem - 1 - elem) * elem_bitsize)
4276132718Skan			  / BITS_PER_UNIT);
4277132718Skan	unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
4278132718Skan	unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
4279132718Skan	unsigned bytele = (subword_byte % UNITS_PER_WORD
4280132718Skan			 + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
4281132718Skan	vp = value + (bytele * BITS_PER_UNIT) / value_bit;
4282132718Skan      }
4283132718Skan
4284132718Skan      switch (GET_CODE (el))
4285117395Skan	{
4286132718Skan	case CONST_INT:
4287132718Skan	  for (i = 0;
4288132718Skan	       i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
4289132718Skan	       i += value_bit)
4290132718Skan	    *vp++ = INTVAL (el) >> i;
4291132718Skan	  /* CONST_INTs are always logically sign-extended.  */
4292132718Skan	  for (; i < elem_bitsize; i += value_bit)
4293132718Skan	    *vp++ = INTVAL (el) < 0 ? -1 : 0;
4294132718Skan	  break;
4295132718Skan
4296132718Skan	case CONST_DOUBLE:
4297132718Skan	  if (GET_MODE (el) == VOIDmode)
4298132718Skan	    {
4299132718Skan	      /* If this triggers, someone should have generated a
4300132718Skan		 CONST_INT instead.  */
4301169689Skan	      gcc_assert (elem_bitsize > HOST_BITS_PER_WIDE_INT);
4302117395Skan
4303132718Skan	      for (i = 0; i < HOST_BITS_PER_WIDE_INT; i += value_bit)
4304132718Skan		*vp++ = CONST_DOUBLE_LOW (el) >> i;
4305132718Skan	      while (i < HOST_BITS_PER_WIDE_INT * 2 && i < elem_bitsize)
4306132718Skan		{
4307132718Skan		  *vp++
4308132718Skan		    = CONST_DOUBLE_HIGH (el) >> (i - HOST_BITS_PER_WIDE_INT);
4309132718Skan		  i += value_bit;
4310132718Skan		}
4311132718Skan	      /* It shouldn't matter what's done here, so fill it with
4312132718Skan		 zero.  */
4313161651Skan	      for (; i < elem_bitsize; i += value_bit)
4314132718Skan		*vp++ = 0;
4315132718Skan	    }
4316169689Skan	  else
4317132718Skan	    {
4318132718Skan	      long tmp[max_bitsize / 32];
4319132718Skan	      int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
4320117395Skan
4321169689Skan	      gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
4322169689Skan	      gcc_assert (bitsize <= elem_bitsize);
4323169689Skan	      gcc_assert (bitsize % value_bit == 0);
4324169689Skan
4325132718Skan	      real_to_target (tmp, CONST_DOUBLE_REAL_VALUE (el),
4326132718Skan			      GET_MODE (el));
4327117395Skan
4328132718Skan	      /* real_to_target produces its result in words affected by
4329132718Skan		 FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
4330132718Skan		 and use WORDS_BIG_ENDIAN instead; see the documentation
4331132718Skan	         of SUBREG in rtl.texi.  */
4332132718Skan	      for (i = 0; i < bitsize; i += value_bit)
4333117395Skan		{
4334132718Skan		  int ibase;
4335132718Skan		  if (WORDS_BIG_ENDIAN)
4336132718Skan		    ibase = bitsize - 1 - i;
4337132718Skan		  else
4338132718Skan		    ibase = i;
4339132718Skan		  *vp++ = tmp[ibase / 32] >> i % 32;
4340117395Skan		}
4341132718Skan
4342132718Skan	      /* It shouldn't matter what's done here, so fill it with
4343132718Skan		 zero.  */
4344132718Skan	      for (; i < elem_bitsize; i += value_bit)
4345132718Skan		*vp++ = 0;
4346117395Skan	    }
4347132718Skan	  break;
4348132718Skan
4349132718Skan	default:
4350169689Skan	  gcc_unreachable ();
4351117395Skan	}
4352117395Skan    }
4353117395Skan
4354132718Skan  /* Now, pick the right byte to start with.  */
4355132718Skan  /* Renumber BYTE so that the least-significant byte is byte 0.  A special
4356132718Skan     case is paradoxical SUBREGs, which shouldn't be adjusted since they
4357132718Skan     will already have offset 0.  */
4358132718Skan  if (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode))
435990075Sobrien    {
4360132718Skan      unsigned ibyte = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)
4361132718Skan			- byte);
4362132718Skan      unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
4363132718Skan      unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
4364132718Skan      byte = (subword_byte % UNITS_PER_WORD
4365132718Skan	      + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
4366132718Skan    }
436790075Sobrien
4368132718Skan  /* BYTE should still be inside OP.  (Note that BYTE is unsigned,
4369132718Skan     so if it's become negative it will instead be very large.)  */
4370169689Skan  gcc_assert (byte < GET_MODE_SIZE (innermode));
4371117395Skan
4372132718Skan  /* Convert from bytes to chunks of size value_bit.  */
4373132718Skan  value_start = byte * (BITS_PER_UNIT / value_bit);
4374117395Skan
4375132718Skan  /* Re-pack the value.  */
4376132718Skan
4377132718Skan  if (VECTOR_MODE_P (outermode))
4378132718Skan    {
4379132718Skan      num_elem = GET_MODE_NUNITS (outermode);
4380132718Skan      result_v = rtvec_alloc (num_elem);
4381132718Skan      elems = &RTVEC_ELT (result_v, 0);
4382132718Skan      outer_submode = GET_MODE_INNER (outermode);
4383132718Skan    }
4384132718Skan  else
4385132718Skan    {
4386132718Skan      num_elem = 1;
4387132718Skan      elems = &result_s;
4388132718Skan      outer_submode = outermode;
4389132718Skan    }
439090075Sobrien
4391132718Skan  outer_class = GET_MODE_CLASS (outer_submode);
4392132718Skan  elem_bitsize = GET_MODE_BITSIZE (outer_submode);
439390075Sobrien
4394169689Skan  gcc_assert (elem_bitsize % value_bit == 0);
4395169689Skan  gcc_assert (elem_bitsize + value_start * value_bit <= max_bitsize);
4396117395Skan
4397132718Skan  for (elem = 0; elem < num_elem; elem++)
4398132718Skan    {
4399132718Skan      unsigned char *vp;
4400132718Skan
4401132718Skan      /* Vectors are stored in target memory order.  (This is probably
4402132718Skan	 a mistake.)  */
4403132718Skan      {
4404132718Skan	unsigned byte = (elem * elem_bitsize) / BITS_PER_UNIT;
4405132718Skan	unsigned ibyte = (((num_elem - 1 - elem) * elem_bitsize)
4406132718Skan			  / BITS_PER_UNIT);
4407132718Skan	unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
4408132718Skan	unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
4409132718Skan	unsigned bytele = (subword_byte % UNITS_PER_WORD
4410132718Skan			 + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
4411132718Skan	vp = value + value_start + (bytele * BITS_PER_UNIT) / value_bit;
4412132718Skan      }
4413117395Skan
4414132718Skan      switch (outer_class)
441590075Sobrien	{
4416132718Skan	case MODE_INT:
4417132718Skan	case MODE_PARTIAL_INT:
4418132718Skan	  {
4419132718Skan	    unsigned HOST_WIDE_INT hi = 0, lo = 0;
442090075Sobrien
4421132718Skan	    for (i = 0;
4422132718Skan		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
4423132718Skan		 i += value_bit)
4424132718Skan	      lo |= (HOST_WIDE_INT)(*vp++ & value_mask) << i;
4425132718Skan	    for (; i < elem_bitsize; i += value_bit)
4426132718Skan	      hi |= ((HOST_WIDE_INT)(*vp++ & value_mask)
4427132718Skan		     << (i - HOST_BITS_PER_WIDE_INT));
4428132718Skan
4429132718Skan	    /* immed_double_const doesn't call trunc_int_for_mode.  I don't
4430132718Skan	       know why.  */
4431132718Skan	    if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
4432132718Skan	      elems[elem] = gen_int_mode (lo, outer_submode);
4433169689Skan	    else if (elem_bitsize <= 2 * HOST_BITS_PER_WIDE_INT)
4434169689Skan	      elems[elem] = immed_double_const (lo, hi, outer_submode);
4435132718Skan	    else
4436169689Skan	      return NULL_RTX;
4437132718Skan	  }
4438132718Skan	  break;
4439132718Skan
4440132718Skan	case MODE_FLOAT:
4441169689Skan	case MODE_DECIMAL_FLOAT:
4442132718Skan	  {
4443132718Skan	    REAL_VALUE_TYPE r;
4444132718Skan	    long tmp[max_bitsize / 32];
4445132718Skan
4446132718Skan	    /* real_from_target wants its input in words affected by
4447132718Skan	       FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
4448132718Skan	       and use WORDS_BIG_ENDIAN instead; see the documentation
4449132718Skan	       of SUBREG in rtl.texi.  */
4450132718Skan	    for (i = 0; i < max_bitsize / 32; i++)
4451132718Skan	      tmp[i] = 0;
4452132718Skan	    for (i = 0; i < elem_bitsize; i += value_bit)
4453132718Skan	      {
4454132718Skan		int ibase;
4455132718Skan		if (WORDS_BIG_ENDIAN)
4456132718Skan		  ibase = elem_bitsize - 1 - i;
4457132718Skan		else
4458132718Skan		  ibase = i;
4459132718Skan		tmp[ibase / 32] |= (*vp++ & value_mask) << i % 32;
4460132718Skan	      }
446190075Sobrien
4462132718Skan	    real_from_target (&r, tmp, outer_submode);
4463132718Skan	    elems[elem] = CONST_DOUBLE_FROM_REAL_VALUE (r, outer_submode);
4464132718Skan	  }
4465132718Skan	  break;
4466132718Skan
4467132718Skan	default:
4468169689Skan	  gcc_unreachable ();
4469132718Skan	}
4470132718Skan    }
4471132718Skan  if (VECTOR_MODE_P (outermode))
4472132718Skan    return gen_rtx_CONST_VECTOR (outermode, result_v);
4473132718Skan  else
4474132718Skan    return result_s;
4475132718Skan}
447690075Sobrien
4477132718Skan/* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
4478132718Skan   Return 0 if no simplifications are possible.  */
4479132718Skanrtx
4480132718Skansimplify_subreg (enum machine_mode outermode, rtx op,
4481132718Skan		 enum machine_mode innermode, unsigned int byte)
4482132718Skan{
4483132718Skan  /* Little bit of sanity checking.  */
4484169689Skan  gcc_assert (innermode != VOIDmode);
4485169689Skan  gcc_assert (outermode != VOIDmode);
4486169689Skan  gcc_assert (innermode != BLKmode);
4487169689Skan  gcc_assert (outermode != BLKmode);
448890075Sobrien
4489169689Skan  gcc_assert (GET_MODE (op) == innermode
4490169689Skan	      || GET_MODE (op) == VOIDmode);
449190075Sobrien
4492169689Skan  gcc_assert ((byte % GET_MODE_SIZE (outermode)) == 0);
4493169689Skan  gcc_assert (byte < GET_MODE_SIZE (innermode));
449490075Sobrien
4495132718Skan  if (outermode == innermode && !byte)
4496132718Skan    return op;
449790075Sobrien
4498132718Skan  if (GET_CODE (op) == CONST_INT
4499132718Skan      || GET_CODE (op) == CONST_DOUBLE
4500132718Skan      || GET_CODE (op) == CONST_VECTOR)
4501132718Skan    return simplify_immed_subreg (outermode, op, innermode, byte);
450290075Sobrien
450390075Sobrien  /* Changing mode twice with SUBREG => just change it once,
450490075Sobrien     or not at all if changing back op starting mode.  */
450590075Sobrien  if (GET_CODE (op) == SUBREG)
450690075Sobrien    {
450790075Sobrien      enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
450890075Sobrien      int final_offset = byte + SUBREG_BYTE (op);
4509169689Skan      rtx newx;
451090075Sobrien
451190075Sobrien      if (outermode == innermostmode
451290075Sobrien	  && byte == 0 && SUBREG_BYTE (op) == 0)
451390075Sobrien	return SUBREG_REG (op);
451490075Sobrien
451590075Sobrien      /* The SUBREG_BYTE represents offset, as if the value were stored
451690075Sobrien	 in memory.  Irritating exception is paradoxical subreg, where
451790075Sobrien	 we define SUBREG_BYTE to be 0.  On big endian machines, this
451890075Sobrien	 value should be negative.  For a moment, undo this exception.  */
451990075Sobrien      if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
452090075Sobrien	{
452190075Sobrien	  int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
452290075Sobrien	  if (WORDS_BIG_ENDIAN)
452390075Sobrien	    final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
452490075Sobrien	  if (BYTES_BIG_ENDIAN)
452590075Sobrien	    final_offset += difference % UNITS_PER_WORD;
452690075Sobrien	}
452790075Sobrien      if (SUBREG_BYTE (op) == 0
452890075Sobrien	  && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
452990075Sobrien	{
453090075Sobrien	  int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
453190075Sobrien	  if (WORDS_BIG_ENDIAN)
453290075Sobrien	    final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
453390075Sobrien	  if (BYTES_BIG_ENDIAN)
453490075Sobrien	    final_offset += difference % UNITS_PER_WORD;
453590075Sobrien	}
453690075Sobrien
453790075Sobrien      /* See whether resulting subreg will be paradoxical.  */
453890075Sobrien      if (GET_MODE_SIZE (innermostmode) > GET_MODE_SIZE (outermode))
453990075Sobrien	{
454090075Sobrien	  /* In nonparadoxical subregs we can't handle negative offsets.  */
454190075Sobrien	  if (final_offset < 0)
454290075Sobrien	    return NULL_RTX;
454390075Sobrien	  /* Bail out in case resulting subreg would be incorrect.  */
454490075Sobrien	  if (final_offset % GET_MODE_SIZE (outermode)
454590075Sobrien	      || (unsigned) final_offset >= GET_MODE_SIZE (innermostmode))
454690075Sobrien	    return NULL_RTX;
454790075Sobrien	}
454890075Sobrien      else
454990075Sobrien	{
455090075Sobrien	  int offset = 0;
455190075Sobrien	  int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode));
455290075Sobrien
455390075Sobrien	  /* In paradoxical subreg, see if we are still looking on lower part.
455490075Sobrien	     If so, our SUBREG_BYTE will be 0.  */
455590075Sobrien	  if (WORDS_BIG_ENDIAN)
455690075Sobrien	    offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
455790075Sobrien	  if (BYTES_BIG_ENDIAN)
455890075Sobrien	    offset += difference % UNITS_PER_WORD;
455990075Sobrien	  if (offset == final_offset)
456090075Sobrien	    final_offset = 0;
456190075Sobrien	  else
456290075Sobrien	    return NULL_RTX;
456390075Sobrien	}
456490075Sobrien
4565132718Skan      /* Recurse for further possible simplifications.  */
4566169689Skan      newx = simplify_subreg (outermode, SUBREG_REG (op), innermostmode,
4567169689Skan			      final_offset);
4568169689Skan      if (newx)
4569169689Skan	return newx;
4570169689Skan      if (validate_subreg (outermode, innermostmode,
4571169689Skan			   SUBREG_REG (op), final_offset))
4572169689Skan        return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
4573169689Skan      return NULL_RTX;
457490075Sobrien    }
457590075Sobrien
4576169689Skan  /* Merge implicit and explicit truncations.  */
4577169689Skan
4578169689Skan  if (GET_CODE (op) == TRUNCATE
4579169689Skan      && GET_MODE_SIZE (outermode) < GET_MODE_SIZE (innermode)
4580169689Skan      && subreg_lowpart_offset (outermode, innermode) == byte)
4581169689Skan    return simplify_gen_unary (TRUNCATE, outermode, XEXP (op, 0),
4582169689Skan			       GET_MODE (XEXP (op, 0)));
4583169689Skan
458490075Sobrien  /* SUBREG of a hard register => just change the register number
458590075Sobrien     and/or mode.  If the hard register is not valid in that mode,
458690075Sobrien     suppress this simplification.  If the hard register is the stack,
458790075Sobrien     frame, or argument pointer, leave this as a SUBREG.  */
458890075Sobrien
458990075Sobrien  if (REG_P (op)
4590117395Skan      && REGNO (op) < FIRST_PSEUDO_REGISTER
4591117395Skan#ifdef CANNOT_CHANGE_MODE_CLASS
4592117395Skan      && ! (REG_CANNOT_CHANGE_MODE_P (REGNO (op), innermode, outermode)
459390075Sobrien	    && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT
4594117395Skan	    && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT)
459590075Sobrien#endif
459690075Sobrien      && ((reload_completed && !frame_pointer_needed)
459790075Sobrien	  || (REGNO (op) != FRAME_POINTER_REGNUM
459890075Sobrien#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
459990075Sobrien	      && REGNO (op) != HARD_FRAME_POINTER_REGNUM
460090075Sobrien#endif
460190075Sobrien	     ))
460290075Sobrien#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
460390075Sobrien      && REGNO (op) != ARG_POINTER_REGNUM
460490075Sobrien#endif
4605132718Skan      && REGNO (op) != STACK_POINTER_REGNUM
4606132718Skan      && subreg_offset_representable_p (REGNO (op), innermode,
4607132718Skan					byte, outermode))
460890075Sobrien    {
4609169689Skan      unsigned int regno = REGNO (op);
4610169689Skan      unsigned int final_regno
4611169689Skan	= regno + subreg_regno_offset (regno, innermode, byte, outermode);
461290075Sobrien
461390075Sobrien      /* ??? We do allow it if the current REG is not valid for
461490075Sobrien	 its mode.  This is a kludge to work around how float/complex
4615117395Skan	 arguments are passed on 32-bit SPARC and should be fixed.  */
461690075Sobrien      if (HARD_REGNO_MODE_OK (final_regno, outermode)
4617169689Skan	  || ! HARD_REGNO_MODE_OK (regno, innermode))
461890075Sobrien	{
4619169689Skan	  rtx x;
4620169689Skan	  int final_offset = byte;
462190075Sobrien
4622169689Skan	  /* Adjust offset for paradoxical subregs.  */
4623169689Skan	  if (byte == 0
4624169689Skan	      && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
4625169689Skan	    {
4626169689Skan	      int difference = (GET_MODE_SIZE (innermode)
4627169689Skan				- GET_MODE_SIZE (outermode));
4628169689Skan	      if (WORDS_BIG_ENDIAN)
4629169689Skan		final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
4630169689Skan	      if (BYTES_BIG_ENDIAN)
4631169689Skan		final_offset += difference % UNITS_PER_WORD;
4632169689Skan	    }
4633169689Skan
4634169689Skan	  x = gen_rtx_REG_offset (op, outermode, final_regno, final_offset);
4635169689Skan
463690075Sobrien	  /* Propagate original regno.  We don't have any way to specify
4637132718Skan	     the offset inside original regno, so do so only for lowpart.
463890075Sobrien	     The information is used only by alias analysis that can not
463990075Sobrien	     grog partial register anyway.  */
464090075Sobrien
464190075Sobrien	  if (subreg_lowpart_offset (outermode, innermode) == byte)
464290075Sobrien	    ORIGINAL_REGNO (x) = ORIGINAL_REGNO (op);
464390075Sobrien	  return x;
464490075Sobrien	}
464590075Sobrien    }
464690075Sobrien
464790075Sobrien  /* If we have a SUBREG of a register that we are replacing and we are
464890075Sobrien     replacing it with a MEM, make a new MEM and try replacing the
464990075Sobrien     SUBREG with it.  Don't do this if the MEM has a mode-dependent address
465090075Sobrien     or if we would be widening it.  */
465190075Sobrien
4652169689Skan  if (MEM_P (op)
465390075Sobrien      && ! mode_dependent_address_p (XEXP (op, 0))
465490075Sobrien      /* Allow splitting of volatile memory references in case we don't
465590075Sobrien         have instruction to move the whole thing.  */
465690075Sobrien      && (! MEM_VOLATILE_P (op)
465790075Sobrien	  || ! have_insn_for (SET, innermode))
465890075Sobrien      && GET_MODE_SIZE (outermode) <= GET_MODE_SIZE (GET_MODE (op)))
465990075Sobrien    return adjust_address_nv (op, outermode, byte);
466090075Sobrien
466190075Sobrien  /* Handle complex values represented as CONCAT
466290075Sobrien     of real and imaginary part.  */
466390075Sobrien  if (GET_CODE (op) == CONCAT)
466490075Sobrien    {
4665169689Skan      unsigned int inner_size, final_offset;
4666169689Skan      rtx part, res;
466790075Sobrien
4668169689Skan      inner_size = GET_MODE_UNIT_SIZE (innermode);
4669169689Skan      part = byte < inner_size ? XEXP (op, 0) : XEXP (op, 1);
4670169689Skan      final_offset = byte % inner_size;
4671169689Skan      if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
4672169689Skan	return NULL_RTX;
4673169689Skan
467490075Sobrien      res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
467590075Sobrien      if (res)
467690075Sobrien	return res;
4677169689Skan      if (validate_subreg (outermode, GET_MODE (part), part, final_offset))
4678169689Skan	return gen_rtx_SUBREG (outermode, part, final_offset);
4679169689Skan      return NULL_RTX;
468090075Sobrien    }
468190075Sobrien
4682169689Skan  /* Optimize SUBREG truncations of zero and sign extended values.  */
4683169689Skan  if ((GET_CODE (op) == ZERO_EXTEND
4684169689Skan       || GET_CODE (op) == SIGN_EXTEND)
4685169689Skan      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode))
4686169689Skan    {
4687169689Skan      unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
4688169689Skan
4689169689Skan      /* If we're requesting the lowpart of a zero or sign extension,
4690169689Skan	 there are three possibilities.  If the outermode is the same
4691169689Skan	 as the origmode, we can omit both the extension and the subreg.
4692169689Skan	 If the outermode is not larger than the origmode, we can apply
4693169689Skan	 the truncation without the extension.  Finally, if the outermode
4694169689Skan	 is larger than the origmode, but both are integer modes, we
4695169689Skan	 can just extend to the appropriate mode.  */
4696169689Skan      if (bitpos == 0)
4697169689Skan	{
4698169689Skan	  enum machine_mode origmode = GET_MODE (XEXP (op, 0));
4699169689Skan	  if (outermode == origmode)
4700169689Skan	    return XEXP (op, 0);
4701169689Skan	  if (GET_MODE_BITSIZE (outermode) <= GET_MODE_BITSIZE (origmode))
4702169689Skan	    return simplify_gen_subreg (outermode, XEXP (op, 0), origmode,
4703169689Skan					subreg_lowpart_offset (outermode,
4704169689Skan							       origmode));
4705169689Skan	  if (SCALAR_INT_MODE_P (outermode))
4706169689Skan	    return simplify_gen_unary (GET_CODE (op), outermode,
4707169689Skan				       XEXP (op, 0), origmode);
4708169689Skan	}
4709169689Skan
4710169689Skan      /* A SUBREG resulting from a zero extension may fold to zero if
4711169689Skan	 it extracts higher bits that the ZERO_EXTEND's source bits.  */
4712169689Skan      if (GET_CODE (op) == ZERO_EXTEND
4713169689Skan	  && bitpos >= GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))))
4714169689Skan	return CONST0_RTX (outermode);
4715169689Skan    }
4716169689Skan
4717169689Skan  /* Simplify (subreg:QI (lshiftrt:SI (sign_extend:SI (x:QI)) C), 0) into
4718169689Skan     to (ashiftrt:QI (x:QI) C), where C is a suitable small constant and
4719169689Skan     the outer subreg is effectively a truncation to the original mode.  */
4720169689Skan  if ((GET_CODE (op) == LSHIFTRT
4721169689Skan       || GET_CODE (op) == ASHIFTRT)
4722169689Skan      && SCALAR_INT_MODE_P (outermode)
4723169689Skan      /* Ensure that OUTERMODE is at least twice as wide as the INNERMODE
4724169689Skan	 to avoid the possibility that an outer LSHIFTRT shifts by more
4725169689Skan	 than the sign extension's sign_bit_copies and introduces zeros
4726169689Skan	 into the high bits of the result.  */
4727169689Skan      && (2 * GET_MODE_BITSIZE (outermode)) <= GET_MODE_BITSIZE (innermode)
4728169689Skan      && GET_CODE (XEXP (op, 1)) == CONST_INT
4729169689Skan      && GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
4730169689Skan      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
4731169689Skan      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
4732169689Skan      && subreg_lsb_1 (outermode, innermode, byte) == 0)
4733169689Skan    return simplify_gen_binary (ASHIFTRT, outermode,
4734169689Skan				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
4735169689Skan
4736169689Skan  /* Likewise (subreg:QI (lshiftrt:SI (zero_extend:SI (x:QI)) C), 0) into
4737169689Skan     to (lshiftrt:QI (x:QI) C), where C is a suitable small constant and
4738169689Skan     the outer subreg is effectively a truncation to the original mode.  */
4739169689Skan  if ((GET_CODE (op) == LSHIFTRT
4740169689Skan       || GET_CODE (op) == ASHIFTRT)
4741169689Skan      && SCALAR_INT_MODE_P (outermode)
4742169689Skan      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
4743169689Skan      && GET_CODE (XEXP (op, 1)) == CONST_INT
4744169689Skan      && GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
4745169689Skan      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
4746169689Skan      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
4747169689Skan      && subreg_lsb_1 (outermode, innermode, byte) == 0)
4748169689Skan    return simplify_gen_binary (LSHIFTRT, outermode,
4749169689Skan				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
4750169689Skan
4751169689Skan  /* Likewise (subreg:QI (ashift:SI (zero_extend:SI (x:QI)) C), 0) into
4752169689Skan     to (ashift:QI (x:QI) C), where C is a suitable small constant and
4753169689Skan     the outer subreg is effectively a truncation to the original mode.  */
4754169689Skan  if (GET_CODE (op) == ASHIFT
4755169689Skan      && SCALAR_INT_MODE_P (outermode)
4756169689Skan      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
4757169689Skan      && GET_CODE (XEXP (op, 1)) == CONST_INT
4758169689Skan      && (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
4759169689Skan	  || GET_CODE (XEXP (op, 0)) == SIGN_EXTEND)
4760169689Skan      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
4761169689Skan      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
4762169689Skan      && subreg_lsb_1 (outermode, innermode, byte) == 0)
4763169689Skan    return simplify_gen_binary (ASHIFT, outermode,
4764169689Skan				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
4765169689Skan
476690075Sobrien  return NULL_RTX;
476790075Sobrien}
4768132718Skan
476990075Sobrien/* Make a SUBREG operation or equivalent if it folds.  */
477090075Sobrien
477190075Sobrienrtx
4772132718Skansimplify_gen_subreg (enum machine_mode outermode, rtx op,
4773132718Skan		     enum machine_mode innermode, unsigned int byte)
477490075Sobrien{
4775169689Skan  rtx newx;
477690075Sobrien
4777169689Skan  newx = simplify_subreg (outermode, op, innermode, byte);
4778169689Skan  if (newx)
4779169689Skan    return newx;
478090075Sobrien
4781169689Skan  if (GET_CODE (op) == SUBREG
4782169689Skan      || GET_CODE (op) == CONCAT
4783169689Skan      || GET_MODE (op) == VOIDmode)
478490075Sobrien    return NULL_RTX;
478590075Sobrien
4786169689Skan  if (validate_subreg (outermode, innermode, op, byte))
4787169689Skan    return gen_rtx_SUBREG (outermode, op, byte);
478890075Sobrien
4789169689Skan  return NULL_RTX;
4790169689Skan}
479190075Sobrien
479290075Sobrien/* Simplify X, an rtx expression.
479390075Sobrien
479490075Sobrien   Return the simplified expression or NULL if no simplifications
479590075Sobrien   were possible.
479690075Sobrien
479790075Sobrien   This is the preferred entry point into the simplification routines;
479890075Sobrien   however, we still allow passes to call the more specific routines.
479990075Sobrien
4800132718Skan   Right now GCC has three (yes, three) major bodies of RTL simplification
480190075Sobrien   code that need to be unified.
480290075Sobrien
480390075Sobrien	1. fold_rtx in cse.c.  This code uses various CSE specific
480490075Sobrien	   information to aid in RTL simplification.
480590075Sobrien
480690075Sobrien	2. simplify_rtx in combine.c.  Similar to fold_rtx, except that
480790075Sobrien	   it uses combine specific information to aid in RTL
480890075Sobrien	   simplification.
480990075Sobrien
481090075Sobrien	3. The routines in this file.
481190075Sobrien
481290075Sobrien
481390075Sobrien   Long term we want to only have one body of simplification code; to
481490075Sobrien   get to that state I recommend the following steps:
481590075Sobrien
481690075Sobrien	1. Pour over fold_rtx & simplify_rtx and move any simplifications
481790075Sobrien	   which are not pass dependent state into these routines.
481890075Sobrien
481990075Sobrien	2. As code is moved by #1, change fold_rtx & simplify_rtx to
482090075Sobrien	   use this routine whenever possible.
482190075Sobrien
482290075Sobrien	3. Allow for pass dependent state to be provided to these
482390075Sobrien	   routines and add simplifications based on the pass dependent
482490075Sobrien	   state.  Remove code from cse.c & combine.c that becomes
482590075Sobrien	   redundant/dead.
482690075Sobrien
482790075Sobrien    It will take time, but ultimately the compiler will be easier to
482890075Sobrien    maintain and improve.  It's totally silly that when we add a
482990075Sobrien    simplification that it needs to be added to 4 places (3 for RTL
483090075Sobrien    simplification and 1 for tree simplification.  */
4831117395Skan
483290075Sobrienrtx
4833132718Skansimplify_rtx (rtx x)
483490075Sobrien{
483590075Sobrien  enum rtx_code code = GET_CODE (x);
483690075Sobrien  enum machine_mode mode = GET_MODE (x);
483790075Sobrien
483890075Sobrien  switch (GET_RTX_CLASS (code))
483990075Sobrien    {
4840169689Skan    case RTX_UNARY:
484190075Sobrien      return simplify_unary_operation (code, mode,
484290075Sobrien				       XEXP (x, 0), GET_MODE (XEXP (x, 0)));
4843169689Skan    case RTX_COMM_ARITH:
484490075Sobrien      if (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
4845132718Skan	return simplify_gen_binary (code, mode, XEXP (x, 1), XEXP (x, 0));
484690075Sobrien
4847132718Skan      /* Fall through....  */
484890075Sobrien
4849169689Skan    case RTX_BIN_ARITH:
485090075Sobrien      return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
485190075Sobrien
4852169689Skan    case RTX_TERNARY:
4853169689Skan    case RTX_BITFIELD_OPS:
485490075Sobrien      return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)),
485590075Sobrien					 XEXP (x, 0), XEXP (x, 1),
485690075Sobrien					 XEXP (x, 2));
485790075Sobrien
4858169689Skan    case RTX_COMPARE:
4859169689Skan    case RTX_COMM_COMPARE:
4860169689Skan      return simplify_relational_operation (code, mode,
4861169689Skan                                            ((GET_MODE (XEXP (x, 0))
4862169689Skan                                             != VOIDmode)
4863169689Skan                                            ? GET_MODE (XEXP (x, 0))
4864169689Skan                                            : GET_MODE (XEXP (x, 1))),
4865169689Skan                                            XEXP (x, 0),
4866169689Skan                                            XEXP (x, 1));
4867132718Skan
4868169689Skan    case RTX_EXTRA:
486990075Sobrien      if (code == SUBREG)
4870117395Skan	return simplify_gen_subreg (mode, SUBREG_REG (x),
487190075Sobrien				    GET_MODE (SUBREG_REG (x)),
487290075Sobrien				    SUBREG_BYTE (x));
4873132718Skan      break;
4874132718Skan
4875169689Skan    case RTX_OBJ:
4876132718Skan      if (code == LO_SUM)
4877132718Skan	{
4878132718Skan	  /* Convert (lo_sum (high FOO) FOO) to FOO.  */
4879132718Skan	  if (GET_CODE (XEXP (x, 0)) == HIGH
4880132718Skan	      && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1)))
4881132718Skan	  return XEXP (x, 1);
4882132718Skan	}
4883132718Skan      break;
4884132718Skan
488590075Sobrien    default:
4886132718Skan      break;
488790075Sobrien    }
4888132718Skan  return NULL;
488990075Sobrien}
4890169689Skan
4891