xref: /dflybsd-src/contrib/gcc-4.7/gcc/simplify-rtx.c (revision 0a8dc9fc45f4d0b236341a473fac4a486375f60c)
1e4b17023SJohn Marino /* RTL simplification functions for GNU compiler.
2e4b17023SJohn Marino    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3e4b17023SJohn Marino    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
45ce9237cSJohn Marino    2011, 2012  Free Software Foundation, Inc.
5e4b17023SJohn Marino 
6e4b17023SJohn Marino This file is part of GCC.
7e4b17023SJohn Marino 
8e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
9e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
10e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
11e4b17023SJohn Marino version.
12e4b17023SJohn Marino 
13e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
15e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16e4b17023SJohn Marino for more details.
17e4b17023SJohn Marino 
18e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
20e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
21e4b17023SJohn Marino 
22e4b17023SJohn Marino 
23e4b17023SJohn Marino #include "config.h"
24e4b17023SJohn Marino #include "system.h"
25e4b17023SJohn Marino #include "coretypes.h"
26e4b17023SJohn Marino #include "tm.h"
27e4b17023SJohn Marino #include "rtl.h"
28e4b17023SJohn Marino #include "tree.h"
29e4b17023SJohn Marino #include "tm_p.h"
30e4b17023SJohn Marino #include "regs.h"
31e4b17023SJohn Marino #include "hard-reg-set.h"
32e4b17023SJohn Marino #include "flags.h"
33e4b17023SJohn Marino #include "insn-config.h"
34e4b17023SJohn Marino #include "recog.h"
35e4b17023SJohn Marino #include "function.h"
36e4b17023SJohn Marino #include "expr.h"
37e4b17023SJohn Marino #include "diagnostic-core.h"
38e4b17023SJohn Marino #include "output.h"
39e4b17023SJohn Marino #include "ggc.h"
40e4b17023SJohn Marino #include "target.h"
41e4b17023SJohn Marino 
42e4b17023SJohn Marino /* Simplification and canonicalization of RTL.  */
43e4b17023SJohn Marino 
44e4b17023SJohn Marino /* Much code operates on (low, high) pairs; the low value is an
45e4b17023SJohn Marino    unsigned wide int, the high value a signed wide int.  We
46e4b17023SJohn Marino    occasionally need to sign extend from low to high as if low were a
47e4b17023SJohn Marino    signed wide int.  */
48e4b17023SJohn Marino #define HWI_SIGN_EXTEND(low) \
49e4b17023SJohn Marino  ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
50e4b17023SJohn Marino 
51e4b17023SJohn Marino static rtx neg_const_int (enum machine_mode, const_rtx);
52e4b17023SJohn Marino static bool plus_minus_operand_p (const_rtx);
53e4b17023SJohn Marino static bool simplify_plus_minus_op_data_cmp (rtx, rtx);
54e4b17023SJohn Marino static rtx simplify_plus_minus (enum rtx_code, enum machine_mode, rtx, rtx);
55e4b17023SJohn Marino static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode,
56e4b17023SJohn Marino 				  unsigned int);
57e4b17023SJohn Marino static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
58e4b17023SJohn Marino 					   rtx, rtx);
59e4b17023SJohn Marino static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
60e4b17023SJohn Marino 					    enum machine_mode, rtx, rtx);
61e4b17023SJohn Marino static rtx simplify_unary_operation_1 (enum rtx_code, enum machine_mode, rtx);
62e4b17023SJohn Marino static rtx simplify_binary_operation_1 (enum rtx_code, enum machine_mode,
63e4b17023SJohn Marino 					rtx, rtx, rtx, rtx);
64e4b17023SJohn Marino 
65e4b17023SJohn Marino /* Negate a CONST_INT rtx, truncating (because a conversion from a
66e4b17023SJohn Marino    maximally negative number can overflow).  */
67e4b17023SJohn Marino static rtx
neg_const_int(enum machine_mode mode,const_rtx i)68e4b17023SJohn Marino neg_const_int (enum machine_mode mode, const_rtx i)
69e4b17023SJohn Marino {
70e4b17023SJohn Marino   return gen_int_mode (- INTVAL (i), mode);
71e4b17023SJohn Marino }
72e4b17023SJohn Marino 
73e4b17023SJohn Marino /* Test whether expression, X, is an immediate constant that represents
74e4b17023SJohn Marino    the most significant bit of machine mode MODE.  */
75e4b17023SJohn Marino 
76e4b17023SJohn Marino bool
mode_signbit_p(enum machine_mode mode,const_rtx x)77e4b17023SJohn Marino mode_signbit_p (enum machine_mode mode, const_rtx x)
78e4b17023SJohn Marino {
79e4b17023SJohn Marino   unsigned HOST_WIDE_INT val;
80e4b17023SJohn Marino   unsigned int width;
81e4b17023SJohn Marino 
82e4b17023SJohn Marino   if (GET_MODE_CLASS (mode) != MODE_INT)
83e4b17023SJohn Marino     return false;
84e4b17023SJohn Marino 
85e4b17023SJohn Marino   width = GET_MODE_PRECISION (mode);
86e4b17023SJohn Marino   if (width == 0)
87e4b17023SJohn Marino     return false;
88e4b17023SJohn Marino 
89e4b17023SJohn Marino   if (width <= HOST_BITS_PER_WIDE_INT
90e4b17023SJohn Marino       && CONST_INT_P (x))
91e4b17023SJohn Marino     val = INTVAL (x);
92e4b17023SJohn Marino   else if (width <= 2 * HOST_BITS_PER_WIDE_INT
93e4b17023SJohn Marino 	   && GET_CODE (x) == CONST_DOUBLE
94e4b17023SJohn Marino 	   && CONST_DOUBLE_LOW (x) == 0)
95e4b17023SJohn Marino     {
96e4b17023SJohn Marino       val = CONST_DOUBLE_HIGH (x);
97e4b17023SJohn Marino       width -= HOST_BITS_PER_WIDE_INT;
98e4b17023SJohn Marino     }
99e4b17023SJohn Marino   else
100e4b17023SJohn Marino     return false;
101e4b17023SJohn Marino 
102e4b17023SJohn Marino   if (width < HOST_BITS_PER_WIDE_INT)
103e4b17023SJohn Marino     val &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
104e4b17023SJohn Marino   return val == ((unsigned HOST_WIDE_INT) 1 << (width - 1));
105e4b17023SJohn Marino }
106e4b17023SJohn Marino 
107e4b17023SJohn Marino /* Test whether VAL is equal to the most significant bit of mode MODE
108e4b17023SJohn Marino    (after masking with the mode mask of MODE).  Returns false if the
109e4b17023SJohn Marino    precision of MODE is too large to handle.  */
110e4b17023SJohn Marino 
111e4b17023SJohn Marino bool
val_signbit_p(enum machine_mode mode,unsigned HOST_WIDE_INT val)112e4b17023SJohn Marino val_signbit_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
113e4b17023SJohn Marino {
114e4b17023SJohn Marino   unsigned int width;
115e4b17023SJohn Marino 
116e4b17023SJohn Marino   if (GET_MODE_CLASS (mode) != MODE_INT)
117e4b17023SJohn Marino     return false;
118e4b17023SJohn Marino 
119e4b17023SJohn Marino   width = GET_MODE_PRECISION (mode);
120e4b17023SJohn Marino   if (width == 0 || width > HOST_BITS_PER_WIDE_INT)
121e4b17023SJohn Marino     return false;
122e4b17023SJohn Marino 
123e4b17023SJohn Marino   val &= GET_MODE_MASK (mode);
124e4b17023SJohn Marino   return val == ((unsigned HOST_WIDE_INT) 1 << (width - 1));
125e4b17023SJohn Marino }
126e4b17023SJohn Marino 
127e4b17023SJohn Marino /* Test whether the most significant bit of mode MODE is set in VAL.
128e4b17023SJohn Marino    Returns false if the precision of MODE is too large to handle.  */
129e4b17023SJohn Marino bool
val_signbit_known_set_p(enum machine_mode mode,unsigned HOST_WIDE_INT val)130e4b17023SJohn Marino val_signbit_known_set_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
131e4b17023SJohn Marino {
132e4b17023SJohn Marino   unsigned int width;
133e4b17023SJohn Marino 
134e4b17023SJohn Marino   if (GET_MODE_CLASS (mode) != MODE_INT)
135e4b17023SJohn Marino     return false;
136e4b17023SJohn Marino 
137e4b17023SJohn Marino   width = GET_MODE_PRECISION (mode);
138e4b17023SJohn Marino   if (width == 0 || width > HOST_BITS_PER_WIDE_INT)
139e4b17023SJohn Marino     return false;
140e4b17023SJohn Marino 
141e4b17023SJohn Marino   val &= (unsigned HOST_WIDE_INT) 1 << (width - 1);
142e4b17023SJohn Marino   return val != 0;
143e4b17023SJohn Marino }
144e4b17023SJohn Marino 
145e4b17023SJohn Marino /* Test whether the most significant bit of mode MODE is clear in VAL.
146e4b17023SJohn Marino    Returns false if the precision of MODE is too large to handle.  */
147e4b17023SJohn Marino bool
val_signbit_known_clear_p(enum machine_mode mode,unsigned HOST_WIDE_INT val)148e4b17023SJohn Marino val_signbit_known_clear_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
149e4b17023SJohn Marino {
150e4b17023SJohn Marino   unsigned int width;
151e4b17023SJohn Marino 
152e4b17023SJohn Marino   if (GET_MODE_CLASS (mode) != MODE_INT)
153e4b17023SJohn Marino     return false;
154e4b17023SJohn Marino 
155e4b17023SJohn Marino   width = GET_MODE_PRECISION (mode);
156e4b17023SJohn Marino   if (width == 0 || width > HOST_BITS_PER_WIDE_INT)
157e4b17023SJohn Marino     return false;
158e4b17023SJohn Marino 
159e4b17023SJohn Marino   val &= (unsigned HOST_WIDE_INT) 1 << (width - 1);
160e4b17023SJohn Marino   return val == 0;
161e4b17023SJohn Marino }
162e4b17023SJohn Marino 
163e4b17023SJohn Marino /* Make a binary operation by properly ordering the operands and
164e4b17023SJohn Marino    seeing if the expression folds.  */
165e4b17023SJohn Marino 
166e4b17023SJohn Marino rtx
simplify_gen_binary(enum rtx_code code,enum machine_mode mode,rtx op0,rtx op1)167e4b17023SJohn Marino simplify_gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0,
168e4b17023SJohn Marino 		     rtx op1)
169e4b17023SJohn Marino {
170e4b17023SJohn Marino   rtx tem;
171e4b17023SJohn Marino 
172e4b17023SJohn Marino   /* If this simplifies, do it.  */
173e4b17023SJohn Marino   tem = simplify_binary_operation (code, mode, op0, op1);
174e4b17023SJohn Marino   if (tem)
175e4b17023SJohn Marino     return tem;
176e4b17023SJohn Marino 
177e4b17023SJohn Marino   /* Put complex operands first and constants second if commutative.  */
178e4b17023SJohn Marino   if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
179e4b17023SJohn Marino       && swap_commutative_operands_p (op0, op1))
180e4b17023SJohn Marino     tem = op0, op0 = op1, op1 = tem;
181e4b17023SJohn Marino 
182e4b17023SJohn Marino   return gen_rtx_fmt_ee (code, mode, op0, op1);
183e4b17023SJohn Marino }
184e4b17023SJohn Marino 
185e4b17023SJohn Marino /* If X is a MEM referencing the constant pool, return the real value.
186e4b17023SJohn Marino    Otherwise return X.  */
187e4b17023SJohn Marino rtx
avoid_constant_pool_reference(rtx x)188e4b17023SJohn Marino avoid_constant_pool_reference (rtx x)
189e4b17023SJohn Marino {
190e4b17023SJohn Marino   rtx c, tmp, addr;
191e4b17023SJohn Marino   enum machine_mode cmode;
192e4b17023SJohn Marino   HOST_WIDE_INT offset = 0;
193e4b17023SJohn Marino 
194e4b17023SJohn Marino   switch (GET_CODE (x))
195e4b17023SJohn Marino     {
196e4b17023SJohn Marino     case MEM:
197e4b17023SJohn Marino       break;
198e4b17023SJohn Marino 
199e4b17023SJohn Marino     case FLOAT_EXTEND:
200e4b17023SJohn Marino       /* Handle float extensions of constant pool references.  */
201e4b17023SJohn Marino       tmp = XEXP (x, 0);
202e4b17023SJohn Marino       c = avoid_constant_pool_reference (tmp);
203e4b17023SJohn Marino       if (c != tmp && GET_CODE (c) == CONST_DOUBLE)
204e4b17023SJohn Marino 	{
205e4b17023SJohn Marino 	  REAL_VALUE_TYPE d;
206e4b17023SJohn Marino 
207e4b17023SJohn Marino 	  REAL_VALUE_FROM_CONST_DOUBLE (d, c);
208e4b17023SJohn Marino 	  return CONST_DOUBLE_FROM_REAL_VALUE (d, GET_MODE (x));
209e4b17023SJohn Marino 	}
210e4b17023SJohn Marino       return x;
211e4b17023SJohn Marino 
212e4b17023SJohn Marino     default:
213e4b17023SJohn Marino       return x;
214e4b17023SJohn Marino     }
215e4b17023SJohn Marino 
216e4b17023SJohn Marino   if (GET_MODE (x) == BLKmode)
217e4b17023SJohn Marino     return x;
218e4b17023SJohn Marino 
219e4b17023SJohn Marino   addr = XEXP (x, 0);
220e4b17023SJohn Marino 
221e4b17023SJohn Marino   /* Call target hook to avoid the effects of -fpic etc....  */
222e4b17023SJohn Marino   addr = targetm.delegitimize_address (addr);
223e4b17023SJohn Marino 
224e4b17023SJohn Marino   /* Split the address into a base and integer offset.  */
225e4b17023SJohn Marino   if (GET_CODE (addr) == CONST
226e4b17023SJohn Marino       && GET_CODE (XEXP (addr, 0)) == PLUS
227e4b17023SJohn Marino       && CONST_INT_P (XEXP (XEXP (addr, 0), 1)))
228e4b17023SJohn Marino     {
229e4b17023SJohn Marino       offset = INTVAL (XEXP (XEXP (addr, 0), 1));
230e4b17023SJohn Marino       addr = XEXP (XEXP (addr, 0), 0);
231e4b17023SJohn Marino     }
232e4b17023SJohn Marino 
233e4b17023SJohn Marino   if (GET_CODE (addr) == LO_SUM)
234e4b17023SJohn Marino     addr = XEXP (addr, 1);
235e4b17023SJohn Marino 
236e4b17023SJohn Marino   /* If this is a constant pool reference, we can turn it into its
237e4b17023SJohn Marino      constant and hope that simplifications happen.  */
238e4b17023SJohn Marino   if (GET_CODE (addr) == SYMBOL_REF
239e4b17023SJohn Marino       && CONSTANT_POOL_ADDRESS_P (addr))
240e4b17023SJohn Marino     {
241e4b17023SJohn Marino       c = get_pool_constant (addr);
242e4b17023SJohn Marino       cmode = get_pool_mode (addr);
243e4b17023SJohn Marino 
244e4b17023SJohn Marino       /* If we're accessing the constant in a different mode than it was
245e4b17023SJohn Marino          originally stored, attempt to fix that up via subreg simplifications.
246e4b17023SJohn Marino          If that fails we have no choice but to return the original memory.  */
2475ce9237cSJohn Marino       if ((offset != 0 || cmode != GET_MODE (x))
2485ce9237cSJohn Marino 	  && offset >= 0 && offset < GET_MODE_SIZE (cmode))
249e4b17023SJohn Marino         {
250e4b17023SJohn Marino           rtx tem = simplify_subreg (GET_MODE (x), c, cmode, offset);
251e4b17023SJohn Marino           if (tem && CONSTANT_P (tem))
252e4b17023SJohn Marino             return tem;
253e4b17023SJohn Marino         }
254e4b17023SJohn Marino       else
255e4b17023SJohn Marino         return c;
256e4b17023SJohn Marino     }
257e4b17023SJohn Marino 
258e4b17023SJohn Marino   return x;
259e4b17023SJohn Marino }
260e4b17023SJohn Marino 
261e4b17023SJohn Marino /* Simplify a MEM based on its attributes.  This is the default
262e4b17023SJohn Marino    delegitimize_address target hook, and it's recommended that every
263e4b17023SJohn Marino    overrider call it.  */
264e4b17023SJohn Marino 
265e4b17023SJohn Marino rtx
delegitimize_mem_from_attrs(rtx x)266e4b17023SJohn Marino delegitimize_mem_from_attrs (rtx x)
267e4b17023SJohn Marino {
268e4b17023SJohn Marino   /* MEMs without MEM_OFFSETs may have been offset, so we can't just
269e4b17023SJohn Marino      use their base addresses as equivalent.  */
270e4b17023SJohn Marino   if (MEM_P (x)
271e4b17023SJohn Marino       && MEM_EXPR (x)
272e4b17023SJohn Marino       && MEM_OFFSET_KNOWN_P (x))
273e4b17023SJohn Marino     {
274e4b17023SJohn Marino       tree decl = MEM_EXPR (x);
275e4b17023SJohn Marino       enum machine_mode mode = GET_MODE (x);
276e4b17023SJohn Marino       HOST_WIDE_INT offset = 0;
277e4b17023SJohn Marino 
278e4b17023SJohn Marino       switch (TREE_CODE (decl))
279e4b17023SJohn Marino 	{
280e4b17023SJohn Marino 	default:
281e4b17023SJohn Marino 	  decl = NULL;
282e4b17023SJohn Marino 	  break;
283e4b17023SJohn Marino 
284e4b17023SJohn Marino 	case VAR_DECL:
285e4b17023SJohn Marino 	  break;
286e4b17023SJohn Marino 
287e4b17023SJohn Marino 	case ARRAY_REF:
288e4b17023SJohn Marino 	case ARRAY_RANGE_REF:
289e4b17023SJohn Marino 	case COMPONENT_REF:
290e4b17023SJohn Marino 	case BIT_FIELD_REF:
291e4b17023SJohn Marino 	case REALPART_EXPR:
292e4b17023SJohn Marino 	case IMAGPART_EXPR:
293e4b17023SJohn Marino 	case VIEW_CONVERT_EXPR:
294e4b17023SJohn Marino 	  {
295e4b17023SJohn Marino 	    HOST_WIDE_INT bitsize, bitpos;
296e4b17023SJohn Marino 	    tree toffset;
297e4b17023SJohn Marino 	    int unsignedp = 0, volatilep = 0;
298e4b17023SJohn Marino 
299e4b17023SJohn Marino 	    decl = get_inner_reference (decl, &bitsize, &bitpos, &toffset,
300e4b17023SJohn Marino 					&mode, &unsignedp, &volatilep, false);
301e4b17023SJohn Marino 	    if (bitsize != GET_MODE_BITSIZE (mode)
302e4b17023SJohn Marino 		|| (bitpos % BITS_PER_UNIT)
303e4b17023SJohn Marino 		|| (toffset && !host_integerp (toffset, 0)))
304e4b17023SJohn Marino 	      decl = NULL;
305e4b17023SJohn Marino 	    else
306e4b17023SJohn Marino 	      {
307e4b17023SJohn Marino 		offset += bitpos / BITS_PER_UNIT;
308e4b17023SJohn Marino 		if (toffset)
309e4b17023SJohn Marino 		  offset += TREE_INT_CST_LOW (toffset);
310e4b17023SJohn Marino 	      }
311e4b17023SJohn Marino 	    break;
312e4b17023SJohn Marino 	  }
313e4b17023SJohn Marino 	}
314e4b17023SJohn Marino 
315e4b17023SJohn Marino       if (decl
316e4b17023SJohn Marino 	  && mode == GET_MODE (x)
317e4b17023SJohn Marino 	  && TREE_CODE (decl) == VAR_DECL
318e4b17023SJohn Marino 	  && (TREE_STATIC (decl)
319e4b17023SJohn Marino 	      || DECL_THREAD_LOCAL_P (decl))
320e4b17023SJohn Marino 	  && DECL_RTL_SET_P (decl)
321e4b17023SJohn Marino 	  && MEM_P (DECL_RTL (decl)))
322e4b17023SJohn Marino 	{
323e4b17023SJohn Marino 	  rtx newx;
324e4b17023SJohn Marino 
325e4b17023SJohn Marino 	  offset += MEM_OFFSET (x);
326e4b17023SJohn Marino 
327e4b17023SJohn Marino 	  newx = DECL_RTL (decl);
328e4b17023SJohn Marino 
329e4b17023SJohn Marino 	  if (MEM_P (newx))
330e4b17023SJohn Marino 	    {
331e4b17023SJohn Marino 	      rtx n = XEXP (newx, 0), o = XEXP (x, 0);
332e4b17023SJohn Marino 
333e4b17023SJohn Marino 	      /* Avoid creating a new MEM needlessly if we already had
334e4b17023SJohn Marino 		 the same address.  We do if there's no OFFSET and the
335e4b17023SJohn Marino 		 old address X is identical to NEWX, or if X is of the
336e4b17023SJohn Marino 		 form (plus NEWX OFFSET), or the NEWX is of the form
337e4b17023SJohn Marino 		 (plus Y (const_int Z)) and X is that with the offset
338e4b17023SJohn Marino 		 added: (plus Y (const_int Z+OFFSET)).  */
339e4b17023SJohn Marino 	      if (!((offset == 0
340e4b17023SJohn Marino 		     || (GET_CODE (o) == PLUS
341e4b17023SJohn Marino 			 && GET_CODE (XEXP (o, 1)) == CONST_INT
342e4b17023SJohn Marino 			 && (offset == INTVAL (XEXP (o, 1))
343e4b17023SJohn Marino 			     || (GET_CODE (n) == PLUS
344e4b17023SJohn Marino 				 && GET_CODE (XEXP (n, 1)) == CONST_INT
345e4b17023SJohn Marino 				 && (INTVAL (XEXP (n, 1)) + offset
346e4b17023SJohn Marino 				     == INTVAL (XEXP (o, 1)))
347e4b17023SJohn Marino 				 && (n = XEXP (n, 0))))
348e4b17023SJohn Marino 			 && (o = XEXP (o, 0))))
349e4b17023SJohn Marino 		    && rtx_equal_p (o, n)))
350e4b17023SJohn Marino 		x = adjust_address_nv (newx, mode, offset);
351e4b17023SJohn Marino 	    }
352e4b17023SJohn Marino 	  else if (GET_MODE (x) == GET_MODE (newx)
353e4b17023SJohn Marino 		   && offset == 0)
354e4b17023SJohn Marino 	    x = newx;
355e4b17023SJohn Marino 	}
356e4b17023SJohn Marino     }
357e4b17023SJohn Marino 
358e4b17023SJohn Marino   return x;
359e4b17023SJohn Marino }
360e4b17023SJohn Marino 
361e4b17023SJohn Marino /* Make a unary operation by first seeing if it folds and otherwise making
362e4b17023SJohn Marino    the specified operation.  */
363e4b17023SJohn Marino 
364e4b17023SJohn Marino rtx
simplify_gen_unary(enum rtx_code code,enum machine_mode mode,rtx op,enum machine_mode op_mode)365e4b17023SJohn Marino simplify_gen_unary (enum rtx_code code, enum machine_mode mode, rtx op,
366e4b17023SJohn Marino 		    enum machine_mode op_mode)
367e4b17023SJohn Marino {
368e4b17023SJohn Marino   rtx tem;
369e4b17023SJohn Marino 
370e4b17023SJohn Marino   /* If this simplifies, use it.  */
371e4b17023SJohn Marino   if ((tem = simplify_unary_operation (code, mode, op, op_mode)) != 0)
372e4b17023SJohn Marino     return tem;
373e4b17023SJohn Marino 
374e4b17023SJohn Marino   return gen_rtx_fmt_e (code, mode, op);
375e4b17023SJohn Marino }
376e4b17023SJohn Marino 
377e4b17023SJohn Marino /* Likewise for ternary operations.  */
378e4b17023SJohn Marino 
379e4b17023SJohn Marino rtx
simplify_gen_ternary(enum rtx_code code,enum machine_mode mode,enum machine_mode op0_mode,rtx op0,rtx op1,rtx op2)380e4b17023SJohn Marino simplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
381e4b17023SJohn Marino 		      enum machine_mode op0_mode, rtx op0, rtx op1, rtx op2)
382e4b17023SJohn Marino {
383e4b17023SJohn Marino   rtx tem;
384e4b17023SJohn Marino 
385e4b17023SJohn Marino   /* If this simplifies, use it.  */
386e4b17023SJohn Marino   if (0 != (tem = simplify_ternary_operation (code, mode, op0_mode,
387e4b17023SJohn Marino 					      op0, op1, op2)))
388e4b17023SJohn Marino     return tem;
389e4b17023SJohn Marino 
390e4b17023SJohn Marino   return gen_rtx_fmt_eee (code, mode, op0, op1, op2);
391e4b17023SJohn Marino }
392e4b17023SJohn Marino 
393e4b17023SJohn Marino /* Likewise, for relational operations.
394e4b17023SJohn Marino    CMP_MODE specifies mode comparison is done in.  */
395e4b17023SJohn Marino 
396e4b17023SJohn Marino rtx
simplify_gen_relational(enum rtx_code code,enum machine_mode mode,enum machine_mode cmp_mode,rtx op0,rtx op1)397e4b17023SJohn Marino simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
398e4b17023SJohn Marino 			 enum machine_mode cmp_mode, rtx op0, rtx op1)
399e4b17023SJohn Marino {
400e4b17023SJohn Marino   rtx tem;
401e4b17023SJohn Marino 
402e4b17023SJohn Marino   if (0 != (tem = simplify_relational_operation (code, mode, cmp_mode,
403e4b17023SJohn Marino 						 op0, op1)))
404e4b17023SJohn Marino     return tem;
405e4b17023SJohn Marino 
406e4b17023SJohn Marino   return gen_rtx_fmt_ee (code, mode, op0, op1);
407e4b17023SJohn Marino }
408e4b17023SJohn Marino 
409e4b17023SJohn Marino /* If FN is NULL, replace all occurrences of OLD_RTX in X with copy_rtx (DATA)
410e4b17023SJohn Marino    and simplify the result.  If FN is non-NULL, call this callback on each
411e4b17023SJohn Marino    X, if it returns non-NULL, replace X with its return value and simplify the
412e4b17023SJohn Marino    result.  */
413e4b17023SJohn Marino 
414e4b17023SJohn Marino rtx
simplify_replace_fn_rtx(rtx x,const_rtx old_rtx,rtx (* fn)(rtx,const_rtx,void *),void * data)415e4b17023SJohn Marino simplify_replace_fn_rtx (rtx x, const_rtx old_rtx,
416e4b17023SJohn Marino 			 rtx (*fn) (rtx, const_rtx, void *), void *data)
417e4b17023SJohn Marino {
418e4b17023SJohn Marino   enum rtx_code code = GET_CODE (x);
419e4b17023SJohn Marino   enum machine_mode mode = GET_MODE (x);
420e4b17023SJohn Marino   enum machine_mode op_mode;
421e4b17023SJohn Marino   const char *fmt;
422e4b17023SJohn Marino   rtx op0, op1, op2, newx, op;
423e4b17023SJohn Marino   rtvec vec, newvec;
424e4b17023SJohn Marino   int i, j;
425e4b17023SJohn Marino 
426e4b17023SJohn Marino   if (__builtin_expect (fn != NULL, 0))
427e4b17023SJohn Marino     {
428e4b17023SJohn Marino       newx = fn (x, old_rtx, data);
429e4b17023SJohn Marino       if (newx)
430e4b17023SJohn Marino 	return newx;
431e4b17023SJohn Marino     }
432e4b17023SJohn Marino   else if (rtx_equal_p (x, old_rtx))
433e4b17023SJohn Marino     return copy_rtx ((rtx) data);
434e4b17023SJohn Marino 
435e4b17023SJohn Marino   switch (GET_RTX_CLASS (code))
436e4b17023SJohn Marino     {
437e4b17023SJohn Marino     case RTX_UNARY:
438e4b17023SJohn Marino       op0 = XEXP (x, 0);
439e4b17023SJohn Marino       op_mode = GET_MODE (op0);
440e4b17023SJohn Marino       op0 = simplify_replace_fn_rtx (op0, old_rtx, fn, data);
441e4b17023SJohn Marino       if (op0 == XEXP (x, 0))
442e4b17023SJohn Marino 	return x;
443e4b17023SJohn Marino       return simplify_gen_unary (code, mode, op0, op_mode);
444e4b17023SJohn Marino 
445e4b17023SJohn Marino     case RTX_BIN_ARITH:
446e4b17023SJohn Marino     case RTX_COMM_ARITH:
447e4b17023SJohn Marino       op0 = simplify_replace_fn_rtx (XEXP (x, 0), old_rtx, fn, data);
448e4b17023SJohn Marino       op1 = simplify_replace_fn_rtx (XEXP (x, 1), old_rtx, fn, data);
449e4b17023SJohn Marino       if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
450e4b17023SJohn Marino 	return x;
451e4b17023SJohn Marino       return simplify_gen_binary (code, mode, op0, op1);
452e4b17023SJohn Marino 
453e4b17023SJohn Marino     case RTX_COMPARE:
454e4b17023SJohn Marino     case RTX_COMM_COMPARE:
455e4b17023SJohn Marino       op0 = XEXP (x, 0);
456e4b17023SJohn Marino       op1 = XEXP (x, 1);
457e4b17023SJohn Marino       op_mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1);
458e4b17023SJohn Marino       op0 = simplify_replace_fn_rtx (op0, old_rtx, fn, data);
459e4b17023SJohn Marino       op1 = simplify_replace_fn_rtx (op1, old_rtx, fn, data);
460e4b17023SJohn Marino       if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
461e4b17023SJohn Marino 	return x;
462e4b17023SJohn Marino       return simplify_gen_relational (code, mode, op_mode, op0, op1);
463e4b17023SJohn Marino 
464e4b17023SJohn Marino     case RTX_TERNARY:
465e4b17023SJohn Marino     case RTX_BITFIELD_OPS:
466e4b17023SJohn Marino       op0 = XEXP (x, 0);
467e4b17023SJohn Marino       op_mode = GET_MODE (op0);
468e4b17023SJohn Marino       op0 = simplify_replace_fn_rtx (op0, old_rtx, fn, data);
469e4b17023SJohn Marino       op1 = simplify_replace_fn_rtx (XEXP (x, 1), old_rtx, fn, data);
470e4b17023SJohn Marino       op2 = simplify_replace_fn_rtx (XEXP (x, 2), old_rtx, fn, data);
471e4b17023SJohn Marino       if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1) && op2 == XEXP (x, 2))
472e4b17023SJohn Marino 	return x;
473e4b17023SJohn Marino       if (op_mode == VOIDmode)
474e4b17023SJohn Marino 	op_mode = GET_MODE (op0);
475e4b17023SJohn Marino       return simplify_gen_ternary (code, mode, op_mode, op0, op1, op2);
476e4b17023SJohn Marino 
477e4b17023SJohn Marino     case RTX_EXTRA:
478e4b17023SJohn Marino       if (code == SUBREG)
479e4b17023SJohn Marino 	{
480e4b17023SJohn Marino 	  op0 = simplify_replace_fn_rtx (SUBREG_REG (x), old_rtx, fn, data);
481e4b17023SJohn Marino 	  if (op0 == SUBREG_REG (x))
482e4b17023SJohn Marino 	    return x;
483e4b17023SJohn Marino 	  op0 = simplify_gen_subreg (GET_MODE (x), op0,
484e4b17023SJohn Marino 				     GET_MODE (SUBREG_REG (x)),
485e4b17023SJohn Marino 				     SUBREG_BYTE (x));
486e4b17023SJohn Marino 	  return op0 ? op0 : x;
487e4b17023SJohn Marino 	}
488e4b17023SJohn Marino       break;
489e4b17023SJohn Marino 
490e4b17023SJohn Marino     case RTX_OBJ:
491e4b17023SJohn Marino       if (code == MEM)
492e4b17023SJohn Marino 	{
493e4b17023SJohn Marino 	  op0 = simplify_replace_fn_rtx (XEXP (x, 0), old_rtx, fn, data);
494e4b17023SJohn Marino 	  if (op0 == XEXP (x, 0))
495e4b17023SJohn Marino 	    return x;
496e4b17023SJohn Marino 	  return replace_equiv_address_nv (x, op0);
497e4b17023SJohn Marino 	}
498e4b17023SJohn Marino       else if (code == LO_SUM)
499e4b17023SJohn Marino 	{
500e4b17023SJohn Marino 	  op0 = simplify_replace_fn_rtx (XEXP (x, 0), old_rtx, fn, data);
501e4b17023SJohn Marino 	  op1 = simplify_replace_fn_rtx (XEXP (x, 1), old_rtx, fn, data);
502e4b17023SJohn Marino 
503e4b17023SJohn Marino 	  /* (lo_sum (high x) x) -> x  */
504e4b17023SJohn Marino 	  if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
505e4b17023SJohn Marino 	    return op1;
506e4b17023SJohn Marino 
507e4b17023SJohn Marino 	  if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
508e4b17023SJohn Marino 	    return x;
509e4b17023SJohn Marino 	  return gen_rtx_LO_SUM (mode, op0, op1);
510e4b17023SJohn Marino 	}
511e4b17023SJohn Marino       break;
512e4b17023SJohn Marino 
513e4b17023SJohn Marino     default:
514e4b17023SJohn Marino       break;
515e4b17023SJohn Marino     }
516e4b17023SJohn Marino 
517e4b17023SJohn Marino   newx = x;
518e4b17023SJohn Marino   fmt = GET_RTX_FORMAT (code);
519e4b17023SJohn Marino   for (i = 0; fmt[i]; i++)
520e4b17023SJohn Marino     switch (fmt[i])
521e4b17023SJohn Marino       {
522e4b17023SJohn Marino       case 'E':
523e4b17023SJohn Marino 	vec = XVEC (x, i);
524e4b17023SJohn Marino 	newvec = XVEC (newx, i);
525e4b17023SJohn Marino 	for (j = 0; j < GET_NUM_ELEM (vec); j++)
526e4b17023SJohn Marino 	  {
527e4b17023SJohn Marino 	    op = simplify_replace_fn_rtx (RTVEC_ELT (vec, j),
528e4b17023SJohn Marino 					  old_rtx, fn, data);
529e4b17023SJohn Marino 	    if (op != RTVEC_ELT (vec, j))
530e4b17023SJohn Marino 	      {
531e4b17023SJohn Marino 		if (newvec == vec)
532e4b17023SJohn Marino 		  {
533e4b17023SJohn Marino 		    newvec = shallow_copy_rtvec (vec);
534e4b17023SJohn Marino 		    if (x == newx)
535e4b17023SJohn Marino 		      newx = shallow_copy_rtx (x);
536e4b17023SJohn Marino 		    XVEC (newx, i) = newvec;
537e4b17023SJohn Marino 		  }
538e4b17023SJohn Marino 		RTVEC_ELT (newvec, j) = op;
539e4b17023SJohn Marino 	      }
540e4b17023SJohn Marino 	  }
541e4b17023SJohn Marino 	break;
542e4b17023SJohn Marino 
543e4b17023SJohn Marino       case 'e':
544e4b17023SJohn Marino 	if (XEXP (x, i))
545e4b17023SJohn Marino 	  {
546e4b17023SJohn Marino 	    op = simplify_replace_fn_rtx (XEXP (x, i), old_rtx, fn, data);
547e4b17023SJohn Marino 	    if (op != XEXP (x, i))
548e4b17023SJohn Marino 	      {
549e4b17023SJohn Marino 		if (x == newx)
550e4b17023SJohn Marino 		  newx = shallow_copy_rtx (x);
551e4b17023SJohn Marino 		XEXP (newx, i) = op;
552e4b17023SJohn Marino 	      }
553e4b17023SJohn Marino 	  }
554e4b17023SJohn Marino 	break;
555e4b17023SJohn Marino       }
556e4b17023SJohn Marino   return newx;
557e4b17023SJohn Marino }
558e4b17023SJohn Marino 
559e4b17023SJohn Marino /* Replace all occurrences of OLD_RTX in X with NEW_RTX and try to simplify the
560e4b17023SJohn Marino    resulting RTX.  Return a new RTX which is as simplified as possible.  */
561e4b17023SJohn Marino 
562e4b17023SJohn Marino rtx
simplify_replace_rtx(rtx x,const_rtx old_rtx,rtx new_rtx)563e4b17023SJohn Marino simplify_replace_rtx (rtx x, const_rtx old_rtx, rtx new_rtx)
564e4b17023SJohn Marino {
565e4b17023SJohn Marino   return simplify_replace_fn_rtx (x, old_rtx, 0, new_rtx);
566e4b17023SJohn Marino }
567e4b17023SJohn Marino 
568e4b17023SJohn Marino /* Try to simplify a unary operation CODE whose output mode is to be
569e4b17023SJohn Marino    MODE with input operand OP whose mode was originally OP_MODE.
570e4b17023SJohn Marino    Return zero if no simplification can be made.  */
571e4b17023SJohn Marino rtx
simplify_unary_operation(enum rtx_code code,enum machine_mode mode,rtx op,enum machine_mode op_mode)572e4b17023SJohn Marino simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
573e4b17023SJohn Marino 			  rtx op, enum machine_mode op_mode)
574e4b17023SJohn Marino {
575e4b17023SJohn Marino   rtx trueop, tem;
576e4b17023SJohn Marino 
577e4b17023SJohn Marino   trueop = avoid_constant_pool_reference (op);
578e4b17023SJohn Marino 
579e4b17023SJohn Marino   tem = simplify_const_unary_operation (code, mode, trueop, op_mode);
580e4b17023SJohn Marino   if (tem)
581e4b17023SJohn Marino     return tem;
582e4b17023SJohn Marino 
583e4b17023SJohn Marino   return simplify_unary_operation_1 (code, mode, op);
584e4b17023SJohn Marino }
585e4b17023SJohn Marino 
586e4b17023SJohn Marino /* Perform some simplifications we can do even if the operands
587e4b17023SJohn Marino    aren't constant.  */
588e4b17023SJohn Marino static rtx
simplify_unary_operation_1(enum rtx_code code,enum machine_mode mode,rtx op)589e4b17023SJohn Marino simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
590e4b17023SJohn Marino {
591e4b17023SJohn Marino   enum rtx_code reversed;
592e4b17023SJohn Marino   rtx temp;
593e4b17023SJohn Marino 
594e4b17023SJohn Marino   switch (code)
595e4b17023SJohn Marino     {
596e4b17023SJohn Marino     case NOT:
597e4b17023SJohn Marino       /* (not (not X)) == X.  */
598e4b17023SJohn Marino       if (GET_CODE (op) == NOT)
599e4b17023SJohn Marino 	return XEXP (op, 0);
600e4b17023SJohn Marino 
601e4b17023SJohn Marino       /* (not (eq X Y)) == (ne X Y), etc. if BImode or the result of the
602e4b17023SJohn Marino 	 comparison is all ones.   */
603e4b17023SJohn Marino       if (COMPARISON_P (op)
604e4b17023SJohn Marino 	  && (mode == BImode || STORE_FLAG_VALUE == -1)
605e4b17023SJohn Marino 	  && ((reversed = reversed_comparison_code (op, NULL_RTX)) != UNKNOWN))
606e4b17023SJohn Marino 	return simplify_gen_relational (reversed, mode, VOIDmode,
607e4b17023SJohn Marino 					XEXP (op, 0), XEXP (op, 1));
608e4b17023SJohn Marino 
609e4b17023SJohn Marino       /* (not (plus X -1)) can become (neg X).  */
610e4b17023SJohn Marino       if (GET_CODE (op) == PLUS
611e4b17023SJohn Marino 	  && XEXP (op, 1) == constm1_rtx)
612e4b17023SJohn Marino 	return simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
613e4b17023SJohn Marino 
614e4b17023SJohn Marino       /* Similarly, (not (neg X)) is (plus X -1).  */
615e4b17023SJohn Marino       if (GET_CODE (op) == NEG)
616e4b17023SJohn Marino 	return plus_constant (XEXP (op, 0), -1);
617e4b17023SJohn Marino 
618e4b17023SJohn Marino       /* (not (xor X C)) for C constant is (xor X D) with D = ~C.  */
619e4b17023SJohn Marino       if (GET_CODE (op) == XOR
620e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op, 1))
621e4b17023SJohn Marino 	  && (temp = simplify_unary_operation (NOT, mode,
622e4b17023SJohn Marino 					       XEXP (op, 1), mode)) != 0)
623e4b17023SJohn Marino 	return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp);
624e4b17023SJohn Marino 
625e4b17023SJohn Marino       /* (not (plus X C)) for signbit C is (xor X D) with D = ~C.  */
626e4b17023SJohn Marino       if (GET_CODE (op) == PLUS
627e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op, 1))
628e4b17023SJohn Marino 	  && mode_signbit_p (mode, XEXP (op, 1))
629e4b17023SJohn Marino 	  && (temp = simplify_unary_operation (NOT, mode,
630e4b17023SJohn Marino 					       XEXP (op, 1), mode)) != 0)
631e4b17023SJohn Marino 	return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp);
632e4b17023SJohn Marino 
633e4b17023SJohn Marino 
634e4b17023SJohn Marino       /* (not (ashift 1 X)) is (rotate ~1 X).  We used to do this for
635e4b17023SJohn Marino 	 operands other than 1, but that is not valid.  We could do a
636e4b17023SJohn Marino 	 similar simplification for (not (lshiftrt C X)) where C is
637e4b17023SJohn Marino 	 just the sign bit, but this doesn't seem common enough to
638e4b17023SJohn Marino 	 bother with.  */
639e4b17023SJohn Marino       if (GET_CODE (op) == ASHIFT
640e4b17023SJohn Marino 	  && XEXP (op, 0) == const1_rtx)
641e4b17023SJohn Marino 	{
642e4b17023SJohn Marino 	  temp = simplify_gen_unary (NOT, mode, const1_rtx, mode);
643e4b17023SJohn Marino 	  return simplify_gen_binary (ROTATE, mode, temp, XEXP (op, 1));
644e4b17023SJohn Marino 	}
645e4b17023SJohn Marino 
646e4b17023SJohn Marino       /* (not (ashiftrt foo C)) where C is the number of bits in FOO
647e4b17023SJohn Marino 	 minus 1 is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1,
648e4b17023SJohn Marino 	 so we can perform the above simplification.  */
649e4b17023SJohn Marino 
650e4b17023SJohn Marino       if (STORE_FLAG_VALUE == -1
651e4b17023SJohn Marino 	  && GET_CODE (op) == ASHIFTRT
652e4b17023SJohn Marino 	  && GET_CODE (XEXP (op, 1))
653e4b17023SJohn Marino 	  && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
654e4b17023SJohn Marino 	return simplify_gen_relational (GE, mode, VOIDmode,
655e4b17023SJohn Marino 					XEXP (op, 0), const0_rtx);
656e4b17023SJohn Marino 
657e4b17023SJohn Marino 
658e4b17023SJohn Marino       if (GET_CODE (op) == SUBREG
659e4b17023SJohn Marino 	  && subreg_lowpart_p (op)
660e4b17023SJohn Marino 	  && (GET_MODE_SIZE (GET_MODE (op))
661e4b17023SJohn Marino 	      < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
662e4b17023SJohn Marino 	  && GET_CODE (SUBREG_REG (op)) == ASHIFT
663e4b17023SJohn Marino 	  && XEXP (SUBREG_REG (op), 0) == const1_rtx)
664e4b17023SJohn Marino 	{
665e4b17023SJohn Marino 	  enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op));
666e4b17023SJohn Marino 	  rtx x;
667e4b17023SJohn Marino 
668e4b17023SJohn Marino 	  x = gen_rtx_ROTATE (inner_mode,
669e4b17023SJohn Marino 			      simplify_gen_unary (NOT, inner_mode, const1_rtx,
670e4b17023SJohn Marino 						  inner_mode),
671e4b17023SJohn Marino 			      XEXP (SUBREG_REG (op), 1));
672e4b17023SJohn Marino 	  return rtl_hooks.gen_lowpart_no_emit (mode, x);
673e4b17023SJohn Marino 	}
674e4b17023SJohn Marino 
675e4b17023SJohn Marino       /* Apply De Morgan's laws to reduce number of patterns for machines
676e4b17023SJohn Marino 	 with negating logical insns (and-not, nand, etc.).  If result has
677e4b17023SJohn Marino 	 only one NOT, put it first, since that is how the patterns are
678e4b17023SJohn Marino 	 coded.  */
679e4b17023SJohn Marino 
680e4b17023SJohn Marino       if (GET_CODE (op) == IOR || GET_CODE (op) == AND)
681e4b17023SJohn Marino 	{
682e4b17023SJohn Marino 	  rtx in1 = XEXP (op, 0), in2 = XEXP (op, 1);
683e4b17023SJohn Marino 	  enum machine_mode op_mode;
684e4b17023SJohn Marino 
685e4b17023SJohn Marino 	  op_mode = GET_MODE (in1);
686e4b17023SJohn Marino 	  in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
687e4b17023SJohn Marino 
688e4b17023SJohn Marino 	  op_mode = GET_MODE (in2);
689e4b17023SJohn Marino 	  if (op_mode == VOIDmode)
690e4b17023SJohn Marino 	    op_mode = mode;
691e4b17023SJohn Marino 	  in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
692e4b17023SJohn Marino 
693e4b17023SJohn Marino 	  if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
694e4b17023SJohn Marino 	    {
695e4b17023SJohn Marino 	      rtx tem = in2;
696e4b17023SJohn Marino 	      in2 = in1; in1 = tem;
697e4b17023SJohn Marino 	    }
698e4b17023SJohn Marino 
699e4b17023SJohn Marino 	  return gen_rtx_fmt_ee (GET_CODE (op) == IOR ? AND : IOR,
700e4b17023SJohn Marino 				 mode, in1, in2);
701e4b17023SJohn Marino 	}
702e4b17023SJohn Marino       break;
703e4b17023SJohn Marino 
704e4b17023SJohn Marino     case NEG:
705e4b17023SJohn Marino       /* (neg (neg X)) == X.  */
706e4b17023SJohn Marino       if (GET_CODE (op) == NEG)
707e4b17023SJohn Marino 	return XEXP (op, 0);
708e4b17023SJohn Marino 
709e4b17023SJohn Marino       /* (neg (plus X 1)) can become (not X).  */
710e4b17023SJohn Marino       if (GET_CODE (op) == PLUS
711e4b17023SJohn Marino 	  && XEXP (op, 1) == const1_rtx)
712e4b17023SJohn Marino 	return simplify_gen_unary (NOT, mode, XEXP (op, 0), mode);
713e4b17023SJohn Marino 
714e4b17023SJohn Marino       /* Similarly, (neg (not X)) is (plus X 1).  */
715e4b17023SJohn Marino       if (GET_CODE (op) == NOT)
716e4b17023SJohn Marino 	return plus_constant (XEXP (op, 0), 1);
717e4b17023SJohn Marino 
718e4b17023SJohn Marino       /* (neg (minus X Y)) can become (minus Y X).  This transformation
719e4b17023SJohn Marino 	 isn't safe for modes with signed zeros, since if X and Y are
720e4b17023SJohn Marino 	 both +0, (minus Y X) is the same as (minus X Y).  If the
721e4b17023SJohn Marino 	 rounding mode is towards +infinity (or -infinity) then the two
722e4b17023SJohn Marino 	 expressions will be rounded differently.  */
723e4b17023SJohn Marino       if (GET_CODE (op) == MINUS
724e4b17023SJohn Marino 	  && !HONOR_SIGNED_ZEROS (mode)
725e4b17023SJohn Marino 	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
726e4b17023SJohn Marino 	return simplify_gen_binary (MINUS, mode, XEXP (op, 1), XEXP (op, 0));
727e4b17023SJohn Marino 
728e4b17023SJohn Marino       if (GET_CODE (op) == PLUS
729e4b17023SJohn Marino 	  && !HONOR_SIGNED_ZEROS (mode)
730e4b17023SJohn Marino 	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
731e4b17023SJohn Marino 	{
732e4b17023SJohn Marino 	  /* (neg (plus A C)) is simplified to (minus -C A).  */
733e4b17023SJohn Marino 	  if (CONST_INT_P (XEXP (op, 1))
734e4b17023SJohn Marino 	      || GET_CODE (XEXP (op, 1)) == CONST_DOUBLE)
735e4b17023SJohn Marino 	    {
736e4b17023SJohn Marino 	      temp = simplify_unary_operation (NEG, mode, XEXP (op, 1), mode);
737e4b17023SJohn Marino 	      if (temp)
738e4b17023SJohn Marino 		return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 0));
739e4b17023SJohn Marino 	    }
740e4b17023SJohn Marino 
741e4b17023SJohn Marino 	  /* (neg (plus A B)) is canonicalized to (minus (neg A) B).  */
742e4b17023SJohn Marino 	  temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
743e4b17023SJohn Marino 	  return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 1));
744e4b17023SJohn Marino 	}
745e4b17023SJohn Marino 
746e4b17023SJohn Marino       /* (neg (mult A B)) becomes (mult A (neg B)).
747e4b17023SJohn Marino 	 This works even for floating-point values.  */
748e4b17023SJohn Marino       if (GET_CODE (op) == MULT
749e4b17023SJohn Marino 	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
750e4b17023SJohn Marino 	{
751e4b17023SJohn Marino 	  temp = simplify_gen_unary (NEG, mode, XEXP (op, 1), mode);
752e4b17023SJohn Marino 	  return simplify_gen_binary (MULT, mode, XEXP (op, 0), temp);
753e4b17023SJohn Marino 	}
754e4b17023SJohn Marino 
755e4b17023SJohn Marino       /* NEG commutes with ASHIFT since it is multiplication.  Only do
756e4b17023SJohn Marino 	 this if we can then eliminate the NEG (e.g., if the operand
757e4b17023SJohn Marino 	 is a constant).  */
758e4b17023SJohn Marino       if (GET_CODE (op) == ASHIFT)
759e4b17023SJohn Marino 	{
760e4b17023SJohn Marino 	  temp = simplify_unary_operation (NEG, mode, XEXP (op, 0), mode);
761e4b17023SJohn Marino 	  if (temp)
762e4b17023SJohn Marino 	    return simplify_gen_binary (ASHIFT, mode, temp, XEXP (op, 1));
763e4b17023SJohn Marino 	}
764e4b17023SJohn Marino 
765e4b17023SJohn Marino       /* (neg (ashiftrt X C)) can be replaced by (lshiftrt X C) when
766e4b17023SJohn Marino 	 C is equal to the width of MODE minus 1.  */
767e4b17023SJohn Marino       if (GET_CODE (op) == ASHIFTRT
768e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op, 1))
769e4b17023SJohn Marino 	  && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
770e4b17023SJohn Marino 	return simplify_gen_binary (LSHIFTRT, mode,
771e4b17023SJohn Marino 				    XEXP (op, 0), XEXP (op, 1));
772e4b17023SJohn Marino 
773e4b17023SJohn Marino       /* (neg (lshiftrt X C)) can be replaced by (ashiftrt X C) when
774e4b17023SJohn Marino 	 C is equal to the width of MODE minus 1.  */
775e4b17023SJohn Marino       if (GET_CODE (op) == LSHIFTRT
776e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op, 1))
777e4b17023SJohn Marino 	  && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
778e4b17023SJohn Marino 	return simplify_gen_binary (ASHIFTRT, mode,
779e4b17023SJohn Marino 				    XEXP (op, 0), XEXP (op, 1));
780e4b17023SJohn Marino 
781e4b17023SJohn Marino       /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1.  */
782e4b17023SJohn Marino       if (GET_CODE (op) == XOR
783e4b17023SJohn Marino 	  && XEXP (op, 1) == const1_rtx
784e4b17023SJohn Marino 	  && nonzero_bits (XEXP (op, 0), mode) == 1)
785e4b17023SJohn Marino 	return plus_constant (XEXP (op, 0), -1);
786e4b17023SJohn Marino 
787e4b17023SJohn Marino       /* (neg (lt x 0)) is (ashiftrt X C) if STORE_FLAG_VALUE is 1.  */
788e4b17023SJohn Marino       /* (neg (lt x 0)) is (lshiftrt X C) if STORE_FLAG_VALUE is -1.  */
789e4b17023SJohn Marino       if (GET_CODE (op) == LT
790e4b17023SJohn Marino 	  && XEXP (op, 1) == const0_rtx
791e4b17023SJohn Marino 	  && SCALAR_INT_MODE_P (GET_MODE (XEXP (op, 0))))
792e4b17023SJohn Marino 	{
793e4b17023SJohn Marino 	  enum machine_mode inner = GET_MODE (XEXP (op, 0));
794e4b17023SJohn Marino 	  int isize = GET_MODE_PRECISION (inner);
795e4b17023SJohn Marino 	  if (STORE_FLAG_VALUE == 1)
796e4b17023SJohn Marino 	    {
797e4b17023SJohn Marino 	      temp = simplify_gen_binary (ASHIFTRT, inner, XEXP (op, 0),
798e4b17023SJohn Marino 					  GEN_INT (isize - 1));
799e4b17023SJohn Marino 	      if (mode == inner)
800e4b17023SJohn Marino 		return temp;
801e4b17023SJohn Marino 	      if (GET_MODE_PRECISION (mode) > isize)
802e4b17023SJohn Marino 		return simplify_gen_unary (SIGN_EXTEND, mode, temp, inner);
803e4b17023SJohn Marino 	      return simplify_gen_unary (TRUNCATE, mode, temp, inner);
804e4b17023SJohn Marino 	    }
805e4b17023SJohn Marino 	  else if (STORE_FLAG_VALUE == -1)
806e4b17023SJohn Marino 	    {
807e4b17023SJohn Marino 	      temp = simplify_gen_binary (LSHIFTRT, inner, XEXP (op, 0),
808e4b17023SJohn Marino 					  GEN_INT (isize - 1));
809e4b17023SJohn Marino 	      if (mode == inner)
810e4b17023SJohn Marino 		return temp;
811e4b17023SJohn Marino 	      if (GET_MODE_PRECISION (mode) > isize)
812e4b17023SJohn Marino 		return simplify_gen_unary (ZERO_EXTEND, mode, temp, inner);
813e4b17023SJohn Marino 	      return simplify_gen_unary (TRUNCATE, mode, temp, inner);
814e4b17023SJohn Marino 	    }
815e4b17023SJohn Marino 	}
816e4b17023SJohn Marino       break;
817e4b17023SJohn Marino 
818e4b17023SJohn Marino     case TRUNCATE:
819e4b17023SJohn Marino       /* We can't handle truncation to a partial integer mode here
820e4b17023SJohn Marino          because we don't know the real bitsize of the partial
821e4b17023SJohn Marino          integer mode.  */
822e4b17023SJohn Marino       if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
823e4b17023SJohn Marino         break;
824e4b17023SJohn Marino 
825e4b17023SJohn Marino       /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI.  */
826e4b17023SJohn Marino       if ((GET_CODE (op) == SIGN_EXTEND
827e4b17023SJohn Marino 	   || GET_CODE (op) == ZERO_EXTEND)
828e4b17023SJohn Marino 	  && GET_MODE (XEXP (op, 0)) == mode)
829e4b17023SJohn Marino 	return XEXP (op, 0);
830e4b17023SJohn Marino 
831e4b17023SJohn Marino       /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
832e4b17023SJohn Marino 	 (OP:SI foo:SI) if OP is NEG or ABS.  */
833e4b17023SJohn Marino       if ((GET_CODE (op) == ABS
834e4b17023SJohn Marino 	   || GET_CODE (op) == NEG)
835e4b17023SJohn Marino 	  && (GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
836e4b17023SJohn Marino 	      || GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
837e4b17023SJohn Marino 	  && GET_MODE (XEXP (XEXP (op, 0), 0)) == mode)
838e4b17023SJohn Marino 	return simplify_gen_unary (GET_CODE (op), mode,
839e4b17023SJohn Marino 				   XEXP (XEXP (op, 0), 0), mode);
840e4b17023SJohn Marino 
841e4b17023SJohn Marino       /* (truncate:A (subreg:B (truncate:C X) 0)) is
842e4b17023SJohn Marino 	 (truncate:A X).  */
843e4b17023SJohn Marino       if (GET_CODE (op) == SUBREG
844e4b17023SJohn Marino 	  && GET_CODE (SUBREG_REG (op)) == TRUNCATE
845e4b17023SJohn Marino 	  && subreg_lowpart_p (op))
846e4b17023SJohn Marino 	return simplify_gen_unary (TRUNCATE, mode, XEXP (SUBREG_REG (op), 0),
847e4b17023SJohn Marino 				   GET_MODE (XEXP (SUBREG_REG (op), 0)));
848e4b17023SJohn Marino 
849e4b17023SJohn Marino       /* If we know that the value is already truncated, we can
850e4b17023SJohn Marino          replace the TRUNCATE with a SUBREG.  Note that this is also
851e4b17023SJohn Marino          valid if TRULY_NOOP_TRUNCATION is false for the corresponding
852e4b17023SJohn Marino          modes we just have to apply a different definition for
853e4b17023SJohn Marino          truncation.  But don't do this for an (LSHIFTRT (MULT ...))
854e4b17023SJohn Marino          since this will cause problems with the umulXi3_highpart
855e4b17023SJohn Marino          patterns.  */
856e4b17023SJohn Marino       if ((TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op))
857e4b17023SJohn Marino 	   ? (num_sign_bit_copies (op, GET_MODE (op))
858e4b17023SJohn Marino 	      > (unsigned int) (GET_MODE_PRECISION (GET_MODE (op))
859e4b17023SJohn Marino 				- GET_MODE_PRECISION (mode)))
860e4b17023SJohn Marino 	   : truncated_to_mode (mode, op))
861e4b17023SJohn Marino 	  && ! (GET_CODE (op) == LSHIFTRT
862e4b17023SJohn Marino 		&& GET_CODE (XEXP (op, 0)) == MULT))
863e4b17023SJohn Marino 	return rtl_hooks.gen_lowpart_no_emit (mode, op);
864e4b17023SJohn Marino 
865e4b17023SJohn Marino       /* A truncate of a comparison can be replaced with a subreg if
866e4b17023SJohn Marino          STORE_FLAG_VALUE permits.  This is like the previous test,
867e4b17023SJohn Marino          but it works even if the comparison is done in a mode larger
868e4b17023SJohn Marino          than HOST_BITS_PER_WIDE_INT.  */
869e4b17023SJohn Marino       if (HWI_COMPUTABLE_MODE_P (mode)
870e4b17023SJohn Marino 	  && COMPARISON_P (op)
871e4b17023SJohn Marino 	  && (STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
872e4b17023SJohn Marino 	return rtl_hooks.gen_lowpart_no_emit (mode, op);
873e4b17023SJohn Marino       break;
874e4b17023SJohn Marino 
875e4b17023SJohn Marino     case FLOAT_TRUNCATE:
876e4b17023SJohn Marino       if (DECIMAL_FLOAT_MODE_P (mode))
877e4b17023SJohn Marino 	break;
878e4b17023SJohn Marino 
879e4b17023SJohn Marino       /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF.  */
880e4b17023SJohn Marino       if (GET_CODE (op) == FLOAT_EXTEND
881e4b17023SJohn Marino 	  && GET_MODE (XEXP (op, 0)) == mode)
882e4b17023SJohn Marino 	return XEXP (op, 0);
883e4b17023SJohn Marino 
884e4b17023SJohn Marino       /* (float_truncate:SF (float_truncate:DF foo:XF))
885e4b17023SJohn Marino          = (float_truncate:SF foo:XF).
886e4b17023SJohn Marino 	 This may eliminate double rounding, so it is unsafe.
887e4b17023SJohn Marino 
888e4b17023SJohn Marino          (float_truncate:SF (float_extend:XF foo:DF))
889e4b17023SJohn Marino          = (float_truncate:SF foo:DF).
890e4b17023SJohn Marino 
891e4b17023SJohn Marino          (float_truncate:DF (float_extend:XF foo:SF))
892e4b17023SJohn Marino          = (float_extend:SF foo:DF).  */
893e4b17023SJohn Marino       if ((GET_CODE (op) == FLOAT_TRUNCATE
894e4b17023SJohn Marino 	   && flag_unsafe_math_optimizations)
895e4b17023SJohn Marino 	  || GET_CODE (op) == FLOAT_EXTEND)
896e4b17023SJohn Marino 	return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (op,
897e4b17023SJohn Marino 							    0)))
898e4b17023SJohn Marino 				   > GET_MODE_SIZE (mode)
899e4b17023SJohn Marino 				   ? FLOAT_TRUNCATE : FLOAT_EXTEND,
900e4b17023SJohn Marino 				   mode,
901e4b17023SJohn Marino 				   XEXP (op, 0), mode);
902e4b17023SJohn Marino 
903e4b17023SJohn Marino       /*  (float_truncate (float x)) is (float x)  */
904e4b17023SJohn Marino       if (GET_CODE (op) == FLOAT
905e4b17023SJohn Marino 	  && (flag_unsafe_math_optimizations
906e4b17023SJohn Marino 	      || (SCALAR_FLOAT_MODE_P (GET_MODE (op))
907e4b17023SJohn Marino 		  && ((unsigned)significand_size (GET_MODE (op))
908e4b17023SJohn Marino 		      >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
909e4b17023SJohn Marino 			  - num_sign_bit_copies (XEXP (op, 0),
910e4b17023SJohn Marino 						 GET_MODE (XEXP (op, 0))))))))
911e4b17023SJohn Marino 	return simplify_gen_unary (FLOAT, mode,
912e4b17023SJohn Marino 				   XEXP (op, 0),
913e4b17023SJohn Marino 				   GET_MODE (XEXP (op, 0)));
914e4b17023SJohn Marino 
915e4b17023SJohn Marino       /* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is
916e4b17023SJohn Marino 	 (OP:SF foo:SF) if OP is NEG or ABS.  */
917e4b17023SJohn Marino       if ((GET_CODE (op) == ABS
918e4b17023SJohn Marino 	   || GET_CODE (op) == NEG)
919e4b17023SJohn Marino 	  && GET_CODE (XEXP (op, 0)) == FLOAT_EXTEND
920e4b17023SJohn Marino 	  && GET_MODE (XEXP (XEXP (op, 0), 0)) == mode)
921e4b17023SJohn Marino 	return simplify_gen_unary (GET_CODE (op), mode,
922e4b17023SJohn Marino 				   XEXP (XEXP (op, 0), 0), mode);
923e4b17023SJohn Marino 
924e4b17023SJohn Marino       /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0))
925e4b17023SJohn Marino 	 is (float_truncate:SF x).  */
926e4b17023SJohn Marino       if (GET_CODE (op) == SUBREG
927e4b17023SJohn Marino 	  && subreg_lowpart_p (op)
928e4b17023SJohn Marino 	  && GET_CODE (SUBREG_REG (op)) == FLOAT_TRUNCATE)
929e4b17023SJohn Marino 	return SUBREG_REG (op);
930e4b17023SJohn Marino       break;
931e4b17023SJohn Marino 
932e4b17023SJohn Marino     case FLOAT_EXTEND:
933e4b17023SJohn Marino       if (DECIMAL_FLOAT_MODE_P (mode))
934e4b17023SJohn Marino 	break;
935e4b17023SJohn Marino 
936e4b17023SJohn Marino       /*  (float_extend (float_extend x)) is (float_extend x)
937e4b17023SJohn Marino 
938e4b17023SJohn Marino 	  (float_extend (float x)) is (float x) assuming that double
939e4b17023SJohn Marino 	  rounding can't happen.
940e4b17023SJohn Marino           */
941e4b17023SJohn Marino       if (GET_CODE (op) == FLOAT_EXTEND
942e4b17023SJohn Marino 	  || (GET_CODE (op) == FLOAT
943e4b17023SJohn Marino 	      && SCALAR_FLOAT_MODE_P (GET_MODE (op))
944e4b17023SJohn Marino 	      && ((unsigned)significand_size (GET_MODE (op))
945e4b17023SJohn Marino 		  >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
946e4b17023SJohn Marino 		      - num_sign_bit_copies (XEXP (op, 0),
947e4b17023SJohn Marino 					     GET_MODE (XEXP (op, 0)))))))
948e4b17023SJohn Marino 	return simplify_gen_unary (GET_CODE (op), mode,
949e4b17023SJohn Marino 				   XEXP (op, 0),
950e4b17023SJohn Marino 				   GET_MODE (XEXP (op, 0)));
951e4b17023SJohn Marino 
952e4b17023SJohn Marino       break;
953e4b17023SJohn Marino 
954e4b17023SJohn Marino     case ABS:
955e4b17023SJohn Marino       /* (abs (neg <foo>)) -> (abs <foo>) */
956e4b17023SJohn Marino       if (GET_CODE (op) == NEG)
957e4b17023SJohn Marino 	return simplify_gen_unary (ABS, mode, XEXP (op, 0),
958e4b17023SJohn Marino 				   GET_MODE (XEXP (op, 0)));
959e4b17023SJohn Marino 
960e4b17023SJohn Marino       /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS),
961e4b17023SJohn Marino          do nothing.  */
962e4b17023SJohn Marino       if (GET_MODE (op) == VOIDmode)
963e4b17023SJohn Marino 	break;
964e4b17023SJohn Marino 
965e4b17023SJohn Marino       /* If operand is something known to be positive, ignore the ABS.  */
966e4b17023SJohn Marino       if (GET_CODE (op) == FFS || GET_CODE (op) == ABS
967e4b17023SJohn Marino 	  || val_signbit_known_clear_p (GET_MODE (op),
968e4b17023SJohn Marino 					nonzero_bits (op, GET_MODE (op))))
969e4b17023SJohn Marino 	return op;
970e4b17023SJohn Marino 
971e4b17023SJohn Marino       /* If operand is known to be only -1 or 0, convert ABS to NEG.  */
972e4b17023SJohn Marino       if (num_sign_bit_copies (op, mode) == GET_MODE_PRECISION (mode))
973e4b17023SJohn Marino 	return gen_rtx_NEG (mode, op);
974e4b17023SJohn Marino 
975e4b17023SJohn Marino       break;
976e4b17023SJohn Marino 
977e4b17023SJohn Marino     case FFS:
978e4b17023SJohn Marino       /* (ffs (*_extend <X>)) = (ffs <X>) */
979e4b17023SJohn Marino       if (GET_CODE (op) == SIGN_EXTEND
980e4b17023SJohn Marino 	  || GET_CODE (op) == ZERO_EXTEND)
981e4b17023SJohn Marino 	return simplify_gen_unary (FFS, mode, XEXP (op, 0),
982e4b17023SJohn Marino 				   GET_MODE (XEXP (op, 0)));
983e4b17023SJohn Marino       break;
984e4b17023SJohn Marino 
985e4b17023SJohn Marino     case POPCOUNT:
986e4b17023SJohn Marino       switch (GET_CODE (op))
987e4b17023SJohn Marino 	{
988e4b17023SJohn Marino 	case BSWAP:
989e4b17023SJohn Marino 	case ZERO_EXTEND:
990e4b17023SJohn Marino 	  /* (popcount (zero_extend <X>)) = (popcount <X>) */
991e4b17023SJohn Marino 	  return simplify_gen_unary (POPCOUNT, mode, XEXP (op, 0),
992e4b17023SJohn Marino 				     GET_MODE (XEXP (op, 0)));
993e4b17023SJohn Marino 
994e4b17023SJohn Marino 	case ROTATE:
995e4b17023SJohn Marino 	case ROTATERT:
996e4b17023SJohn Marino 	  /* Rotations don't affect popcount.  */
997e4b17023SJohn Marino 	  if (!side_effects_p (XEXP (op, 1)))
998e4b17023SJohn Marino 	    return simplify_gen_unary (POPCOUNT, mode, XEXP (op, 0),
999e4b17023SJohn Marino 				       GET_MODE (XEXP (op, 0)));
1000e4b17023SJohn Marino 	  break;
1001e4b17023SJohn Marino 
1002e4b17023SJohn Marino 	default:
1003e4b17023SJohn Marino 	  break;
1004e4b17023SJohn Marino 	}
1005e4b17023SJohn Marino       break;
1006e4b17023SJohn Marino 
1007e4b17023SJohn Marino     case PARITY:
1008e4b17023SJohn Marino       switch (GET_CODE (op))
1009e4b17023SJohn Marino 	{
1010e4b17023SJohn Marino 	case NOT:
1011e4b17023SJohn Marino 	case BSWAP:
1012e4b17023SJohn Marino 	case ZERO_EXTEND:
1013e4b17023SJohn Marino 	case SIGN_EXTEND:
1014e4b17023SJohn Marino 	  return simplify_gen_unary (PARITY, mode, XEXP (op, 0),
1015e4b17023SJohn Marino 				     GET_MODE (XEXP (op, 0)));
1016e4b17023SJohn Marino 
1017e4b17023SJohn Marino 	case ROTATE:
1018e4b17023SJohn Marino 	case ROTATERT:
1019e4b17023SJohn Marino 	  /* Rotations don't affect parity.  */
1020e4b17023SJohn Marino 	  if (!side_effects_p (XEXP (op, 1)))
1021e4b17023SJohn Marino 	    return simplify_gen_unary (PARITY, mode, XEXP (op, 0),
1022e4b17023SJohn Marino 				       GET_MODE (XEXP (op, 0)));
1023e4b17023SJohn Marino 	  break;
1024e4b17023SJohn Marino 
1025e4b17023SJohn Marino 	default:
1026e4b17023SJohn Marino 	  break;
1027e4b17023SJohn Marino 	}
1028e4b17023SJohn Marino       break;
1029e4b17023SJohn Marino 
1030e4b17023SJohn Marino     case BSWAP:
1031e4b17023SJohn Marino       /* (bswap (bswap x)) -> x.  */
1032e4b17023SJohn Marino       if (GET_CODE (op) == BSWAP)
1033e4b17023SJohn Marino 	return XEXP (op, 0);
1034e4b17023SJohn Marino       break;
1035e4b17023SJohn Marino 
1036e4b17023SJohn Marino     case FLOAT:
1037e4b17023SJohn Marino       /* (float (sign_extend <X>)) = (float <X>).  */
1038e4b17023SJohn Marino       if (GET_CODE (op) == SIGN_EXTEND)
1039e4b17023SJohn Marino 	return simplify_gen_unary (FLOAT, mode, XEXP (op, 0),
1040e4b17023SJohn Marino 				   GET_MODE (XEXP (op, 0)));
1041e4b17023SJohn Marino       break;
1042e4b17023SJohn Marino 
1043e4b17023SJohn Marino     case SIGN_EXTEND:
1044e4b17023SJohn Marino       /* (sign_extend (truncate (minus (label_ref L1) (label_ref L2))))
1045e4b17023SJohn Marino 	 becomes just the MINUS if its mode is MODE.  This allows
1046e4b17023SJohn Marino 	 folding switch statements on machines using casesi (such as
1047e4b17023SJohn Marino 	 the VAX).  */
1048e4b17023SJohn Marino       if (GET_CODE (op) == TRUNCATE
1049e4b17023SJohn Marino 	  && GET_MODE (XEXP (op, 0)) == mode
1050e4b17023SJohn Marino 	  && GET_CODE (XEXP (op, 0)) == MINUS
1051e4b17023SJohn Marino 	  && GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF
1052e4b17023SJohn Marino 	  && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
1053e4b17023SJohn Marino 	return XEXP (op, 0);
1054e4b17023SJohn Marino 
1055e4b17023SJohn Marino       /* Extending a widening multiplication should be canonicalized to
1056e4b17023SJohn Marino 	 a wider widening multiplication.  */
1057e4b17023SJohn Marino       if (GET_CODE (op) == MULT)
1058e4b17023SJohn Marino 	{
1059e4b17023SJohn Marino 	  rtx lhs = XEXP (op, 0);
1060e4b17023SJohn Marino 	  rtx rhs = XEXP (op, 1);
1061e4b17023SJohn Marino 	  enum rtx_code lcode = GET_CODE (lhs);
1062e4b17023SJohn Marino 	  enum rtx_code rcode = GET_CODE (rhs);
1063e4b17023SJohn Marino 
1064e4b17023SJohn Marino 	  /* Widening multiplies usually extend both operands, but sometimes
1065e4b17023SJohn Marino 	     they use a shift to extract a portion of a register.  */
1066e4b17023SJohn Marino 	  if ((lcode == SIGN_EXTEND
1067e4b17023SJohn Marino 	       || (lcode == ASHIFTRT && CONST_INT_P (XEXP (lhs, 1))))
1068e4b17023SJohn Marino 	      && (rcode == SIGN_EXTEND
1069e4b17023SJohn Marino 		  || (rcode == ASHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
1070e4b17023SJohn Marino 	    {
1071e4b17023SJohn Marino 	      enum machine_mode lmode = GET_MODE (lhs);
1072e4b17023SJohn Marino 	      enum machine_mode rmode = GET_MODE (rhs);
1073e4b17023SJohn Marino 	      int bits;
1074e4b17023SJohn Marino 
1075e4b17023SJohn Marino 	      if (lcode == ASHIFTRT)
1076e4b17023SJohn Marino 		/* Number of bits not shifted off the end.  */
1077e4b17023SJohn Marino 		bits = GET_MODE_PRECISION (lmode) - INTVAL (XEXP (lhs, 1));
1078e4b17023SJohn Marino 	      else /* lcode == SIGN_EXTEND */
1079e4b17023SJohn Marino 		/* Size of inner mode.  */
1080e4b17023SJohn Marino 		bits = GET_MODE_PRECISION (GET_MODE (XEXP (lhs, 0)));
1081e4b17023SJohn Marino 
1082e4b17023SJohn Marino 	      if (rcode == ASHIFTRT)
1083e4b17023SJohn Marino 		bits += GET_MODE_PRECISION (rmode) - INTVAL (XEXP (rhs, 1));
1084e4b17023SJohn Marino 	      else /* rcode == SIGN_EXTEND */
1085e4b17023SJohn Marino 		bits += GET_MODE_PRECISION (GET_MODE (XEXP (rhs, 0)));
1086e4b17023SJohn Marino 
1087e4b17023SJohn Marino 	      /* We can only widen multiplies if the result is mathematiclly
1088e4b17023SJohn Marino 		 equivalent.  I.e. if overflow was impossible.  */
1089e4b17023SJohn Marino 	      if (bits <= GET_MODE_PRECISION (GET_MODE (op)))
1090e4b17023SJohn Marino 		return simplify_gen_binary
1091e4b17023SJohn Marino 			 (MULT, mode,
1092e4b17023SJohn Marino 			  simplify_gen_unary (SIGN_EXTEND, mode, lhs, lmode),
1093e4b17023SJohn Marino 			  simplify_gen_unary (SIGN_EXTEND, mode, rhs, rmode));
1094e4b17023SJohn Marino 	    }
1095e4b17023SJohn Marino 	}
1096e4b17023SJohn Marino 
1097e4b17023SJohn Marino       /* Check for a sign extension of a subreg of a promoted
1098e4b17023SJohn Marino 	 variable, where the promotion is sign-extended, and the
1099e4b17023SJohn Marino 	 target mode is the same as the variable's promotion.  */
1100e4b17023SJohn Marino       if (GET_CODE (op) == SUBREG
1101e4b17023SJohn Marino 	  && SUBREG_PROMOTED_VAR_P (op)
1102e4b17023SJohn Marino 	  && ! SUBREG_PROMOTED_UNSIGNED_P (op)
1103e4b17023SJohn Marino 	  && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
1104e4b17023SJohn Marino 	return rtl_hooks.gen_lowpart_no_emit (mode, op);
1105e4b17023SJohn Marino 
1106e4b17023SJohn Marino       /* (sign_extend:M (sign_extend:N <X>)) is (sign_extend:M <X>).
1107e4b17023SJohn Marino 	 (sign_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>).  */
1108e4b17023SJohn Marino       if (GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND)
1109e4b17023SJohn Marino 	{
1110e4b17023SJohn Marino 	  gcc_assert (GET_MODE_BITSIZE (mode)
1111e4b17023SJohn Marino 		      > GET_MODE_BITSIZE (GET_MODE (op)));
1112e4b17023SJohn Marino 	  return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0),
1113e4b17023SJohn Marino 				     GET_MODE (XEXP (op, 0)));
1114e4b17023SJohn Marino 	}
1115e4b17023SJohn Marino 
1116e4b17023SJohn Marino       /* (sign_extend:M (ashiftrt:N (ashift <X> (const_int I)) (const_int I)))
1117e4b17023SJohn Marino 	 is (sign_extend:M (subreg:O <X>)) if there is mode with
1118e4b17023SJohn Marino 	 GET_MODE_BITSIZE (N) - I bits.
1119e4b17023SJohn Marino 	 (sign_extend:M (lshiftrt:N (ashift <X> (const_int I)) (const_int I)))
1120e4b17023SJohn Marino 	 is similarly (zero_extend:M (subreg:O <X>)).  */
1121e4b17023SJohn Marino       if ((GET_CODE (op) == ASHIFTRT || GET_CODE (op) == LSHIFTRT)
1122e4b17023SJohn Marino 	  && GET_CODE (XEXP (op, 0)) == ASHIFT
1123e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op, 1))
1124e4b17023SJohn Marino 	  && XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
1125e4b17023SJohn Marino 	  && GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
1126e4b17023SJohn Marino 	{
1127e4b17023SJohn Marino 	  enum machine_mode tmode
1128e4b17023SJohn Marino 	    = mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
1129e4b17023SJohn Marino 			     - INTVAL (XEXP (op, 1)), MODE_INT, 1);
1130e4b17023SJohn Marino 	  gcc_assert (GET_MODE_BITSIZE (mode)
1131e4b17023SJohn Marino 		      > GET_MODE_BITSIZE (GET_MODE (op)));
1132e4b17023SJohn Marino 	  if (tmode != BLKmode)
1133e4b17023SJohn Marino 	    {
1134e4b17023SJohn Marino 	      rtx inner =
1135e4b17023SJohn Marino 		rtl_hooks.gen_lowpart_no_emit (tmode, XEXP (XEXP (op, 0), 0));
1136e4b17023SJohn Marino 	      return simplify_gen_unary (GET_CODE (op) == ASHIFTRT
1137e4b17023SJohn Marino 					 ? SIGN_EXTEND : ZERO_EXTEND,
1138e4b17023SJohn Marino 					 mode, inner, tmode);
1139e4b17023SJohn Marino 	    }
1140e4b17023SJohn Marino 	}
1141e4b17023SJohn Marino 
1142e4b17023SJohn Marino #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
1143e4b17023SJohn Marino       /* As we do not know which address space the pointer is refering to,
1144e4b17023SJohn Marino 	 we can do this only if the target does not support different pointer
1145e4b17023SJohn Marino 	 or address modes depending on the address space.  */
1146e4b17023SJohn Marino       if (target_default_pointer_address_modes_p ()
1147e4b17023SJohn Marino 	  && ! POINTERS_EXTEND_UNSIGNED
1148e4b17023SJohn Marino 	  && mode == Pmode && GET_MODE (op) == ptr_mode
1149e4b17023SJohn Marino 	  && (CONSTANT_P (op)
1150e4b17023SJohn Marino 	      || (GET_CODE (op) == SUBREG
1151e4b17023SJohn Marino 		  && REG_P (SUBREG_REG (op))
1152e4b17023SJohn Marino 		  && REG_POINTER (SUBREG_REG (op))
1153e4b17023SJohn Marino 		  && GET_MODE (SUBREG_REG (op)) == Pmode)))
1154e4b17023SJohn Marino 	return convert_memory_address (Pmode, op);
1155e4b17023SJohn Marino #endif
1156e4b17023SJohn Marino       break;
1157e4b17023SJohn Marino 
1158e4b17023SJohn Marino     case ZERO_EXTEND:
1159e4b17023SJohn Marino       /* Check for a zero extension of a subreg of a promoted
1160e4b17023SJohn Marino 	 variable, where the promotion is zero-extended, and the
1161e4b17023SJohn Marino 	 target mode is the same as the variable's promotion.  */
1162e4b17023SJohn Marino       if (GET_CODE (op) == SUBREG
1163e4b17023SJohn Marino 	  && SUBREG_PROMOTED_VAR_P (op)
1164e4b17023SJohn Marino 	  && SUBREG_PROMOTED_UNSIGNED_P (op) > 0
1165e4b17023SJohn Marino 	  && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
1166e4b17023SJohn Marino 	return rtl_hooks.gen_lowpart_no_emit (mode, op);
1167e4b17023SJohn Marino 
1168e4b17023SJohn Marino       /* Extending a widening multiplication should be canonicalized to
1169e4b17023SJohn Marino 	 a wider widening multiplication.  */
1170e4b17023SJohn Marino       if (GET_CODE (op) == MULT)
1171e4b17023SJohn Marino 	{
1172e4b17023SJohn Marino 	  rtx lhs = XEXP (op, 0);
1173e4b17023SJohn Marino 	  rtx rhs = XEXP (op, 1);
1174e4b17023SJohn Marino 	  enum rtx_code lcode = GET_CODE (lhs);
1175e4b17023SJohn Marino 	  enum rtx_code rcode = GET_CODE (rhs);
1176e4b17023SJohn Marino 
1177e4b17023SJohn Marino 	  /* Widening multiplies usually extend both operands, but sometimes
1178e4b17023SJohn Marino 	     they use a shift to extract a portion of a register.  */
1179e4b17023SJohn Marino 	  if ((lcode == ZERO_EXTEND
1180e4b17023SJohn Marino 	       || (lcode == LSHIFTRT && CONST_INT_P (XEXP (lhs, 1))))
1181e4b17023SJohn Marino 	      && (rcode == ZERO_EXTEND
1182e4b17023SJohn Marino 		  || (rcode == LSHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
1183e4b17023SJohn Marino 	    {
1184e4b17023SJohn Marino 	      enum machine_mode lmode = GET_MODE (lhs);
1185e4b17023SJohn Marino 	      enum machine_mode rmode = GET_MODE (rhs);
1186e4b17023SJohn Marino 	      int bits;
1187e4b17023SJohn Marino 
1188e4b17023SJohn Marino 	      if (lcode == LSHIFTRT)
1189e4b17023SJohn Marino 		/* Number of bits not shifted off the end.  */
1190e4b17023SJohn Marino 		bits = GET_MODE_PRECISION (lmode) - INTVAL (XEXP (lhs, 1));
1191e4b17023SJohn Marino 	      else /* lcode == ZERO_EXTEND */
1192e4b17023SJohn Marino 		/* Size of inner mode.  */
1193e4b17023SJohn Marino 		bits = GET_MODE_PRECISION (GET_MODE (XEXP (lhs, 0)));
1194e4b17023SJohn Marino 
1195e4b17023SJohn Marino 	      if (rcode == LSHIFTRT)
1196e4b17023SJohn Marino 		bits += GET_MODE_PRECISION (rmode) - INTVAL (XEXP (rhs, 1));
1197e4b17023SJohn Marino 	      else /* rcode == ZERO_EXTEND */
1198e4b17023SJohn Marino 		bits += GET_MODE_PRECISION (GET_MODE (XEXP (rhs, 0)));
1199e4b17023SJohn Marino 
1200e4b17023SJohn Marino 	      /* We can only widen multiplies if the result is mathematiclly
1201e4b17023SJohn Marino 		 equivalent.  I.e. if overflow was impossible.  */
1202e4b17023SJohn Marino 	      if (bits <= GET_MODE_PRECISION (GET_MODE (op)))
1203e4b17023SJohn Marino 		return simplify_gen_binary
1204e4b17023SJohn Marino 			 (MULT, mode,
1205e4b17023SJohn Marino 			  simplify_gen_unary (ZERO_EXTEND, mode, lhs, lmode),
1206e4b17023SJohn Marino 			  simplify_gen_unary (ZERO_EXTEND, mode, rhs, rmode));
1207e4b17023SJohn Marino 	    }
1208e4b17023SJohn Marino 	}
1209e4b17023SJohn Marino 
1210e4b17023SJohn Marino       /* (zero_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>).  */
1211e4b17023SJohn Marino       if (GET_CODE (op) == ZERO_EXTEND)
1212e4b17023SJohn Marino 	return simplify_gen_unary (ZERO_EXTEND, mode, XEXP (op, 0),
1213e4b17023SJohn Marino 				   GET_MODE (XEXP (op, 0)));
1214e4b17023SJohn Marino 
1215e4b17023SJohn Marino       /* (zero_extend:M (lshiftrt:N (ashift <X> (const_int I)) (const_int I)))
1216e4b17023SJohn Marino 	 is (zero_extend:M (subreg:O <X>)) if there is mode with
1217e4b17023SJohn Marino 	 GET_MODE_BITSIZE (N) - I bits.  */
1218e4b17023SJohn Marino       if (GET_CODE (op) == LSHIFTRT
1219e4b17023SJohn Marino 	  && GET_CODE (XEXP (op, 0)) == ASHIFT
1220e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op, 1))
1221e4b17023SJohn Marino 	  && XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
1222e4b17023SJohn Marino 	  && GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
1223e4b17023SJohn Marino 	{
1224e4b17023SJohn Marino 	  enum machine_mode tmode
1225e4b17023SJohn Marino 	    = mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
1226e4b17023SJohn Marino 			     - INTVAL (XEXP (op, 1)), MODE_INT, 1);
1227e4b17023SJohn Marino 	  if (tmode != BLKmode)
1228e4b17023SJohn Marino 	    {
1229e4b17023SJohn Marino 	      rtx inner =
1230e4b17023SJohn Marino 		rtl_hooks.gen_lowpart_no_emit (tmode, XEXP (XEXP (op, 0), 0));
1231e4b17023SJohn Marino 	      return simplify_gen_unary (ZERO_EXTEND, mode, inner, tmode);
1232e4b17023SJohn Marino 	    }
1233e4b17023SJohn Marino 	}
1234e4b17023SJohn Marino 
1235e4b17023SJohn Marino #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
1236e4b17023SJohn Marino       /* As we do not know which address space the pointer is refering to,
1237e4b17023SJohn Marino 	 we can do this only if the target does not support different pointer
1238e4b17023SJohn Marino 	 or address modes depending on the address space.  */
1239e4b17023SJohn Marino       if (target_default_pointer_address_modes_p ()
1240e4b17023SJohn Marino 	  && POINTERS_EXTEND_UNSIGNED > 0
1241e4b17023SJohn Marino 	  && mode == Pmode && GET_MODE (op) == ptr_mode
1242e4b17023SJohn Marino 	  && (CONSTANT_P (op)
1243e4b17023SJohn Marino 	      || (GET_CODE (op) == SUBREG
1244e4b17023SJohn Marino 		  && REG_P (SUBREG_REG (op))
1245e4b17023SJohn Marino 		  && REG_POINTER (SUBREG_REG (op))
1246e4b17023SJohn Marino 		  && GET_MODE (SUBREG_REG (op)) == Pmode)))
1247e4b17023SJohn Marino 	return convert_memory_address (Pmode, op);
1248e4b17023SJohn Marino #endif
1249e4b17023SJohn Marino       break;
1250e4b17023SJohn Marino 
1251e4b17023SJohn Marino     default:
1252e4b17023SJohn Marino       break;
1253e4b17023SJohn Marino     }
1254e4b17023SJohn Marino 
1255e4b17023SJohn Marino   return 0;
1256e4b17023SJohn Marino }
1257e4b17023SJohn Marino 
1258e4b17023SJohn Marino /* Try to compute the value of a unary operation CODE whose output mode is to
1259e4b17023SJohn Marino    be MODE with input operand OP whose mode was originally OP_MODE.
1260e4b17023SJohn Marino    Return zero if the value cannot be computed.  */
1261e4b17023SJohn Marino rtx
simplify_const_unary_operation(enum rtx_code code,enum machine_mode mode,rtx op,enum machine_mode op_mode)1262e4b17023SJohn Marino simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
1263e4b17023SJohn Marino 				rtx op, enum machine_mode op_mode)
1264e4b17023SJohn Marino {
1265e4b17023SJohn Marino   unsigned int width = GET_MODE_PRECISION (mode);
1266e4b17023SJohn Marino   unsigned int op_width = GET_MODE_PRECISION (op_mode);
1267e4b17023SJohn Marino 
1268e4b17023SJohn Marino   if (code == VEC_DUPLICATE)
1269e4b17023SJohn Marino     {
1270e4b17023SJohn Marino       gcc_assert (VECTOR_MODE_P (mode));
1271e4b17023SJohn Marino       if (GET_MODE (op) != VOIDmode)
1272e4b17023SJohn Marino       {
1273e4b17023SJohn Marino 	if (!VECTOR_MODE_P (GET_MODE (op)))
1274e4b17023SJohn Marino 	  gcc_assert (GET_MODE_INNER (mode) == GET_MODE (op));
1275e4b17023SJohn Marino 	else
1276e4b17023SJohn Marino 	  gcc_assert (GET_MODE_INNER (mode) == GET_MODE_INNER
1277e4b17023SJohn Marino 						(GET_MODE (op)));
1278e4b17023SJohn Marino       }
1279e4b17023SJohn Marino       if (CONST_INT_P (op) || GET_CODE (op) == CONST_DOUBLE
1280e4b17023SJohn Marino 	  || GET_CODE (op) == CONST_VECTOR)
1281e4b17023SJohn Marino 	{
1282e4b17023SJohn Marino           int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
1283e4b17023SJohn Marino           unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
1284e4b17023SJohn Marino 	  rtvec v = rtvec_alloc (n_elts);
1285e4b17023SJohn Marino 	  unsigned int i;
1286e4b17023SJohn Marino 
1287e4b17023SJohn Marino 	  if (GET_CODE (op) != CONST_VECTOR)
1288e4b17023SJohn Marino 	    for (i = 0; i < n_elts; i++)
1289e4b17023SJohn Marino 	      RTVEC_ELT (v, i) = op;
1290e4b17023SJohn Marino 	  else
1291e4b17023SJohn Marino 	    {
1292e4b17023SJohn Marino 	      enum machine_mode inmode = GET_MODE (op);
1293e4b17023SJohn Marino               int in_elt_size = GET_MODE_SIZE (GET_MODE_INNER (inmode));
1294e4b17023SJohn Marino               unsigned in_n_elts = (GET_MODE_SIZE (inmode) / in_elt_size);
1295e4b17023SJohn Marino 
1296e4b17023SJohn Marino 	      gcc_assert (in_n_elts < n_elts);
1297e4b17023SJohn Marino 	      gcc_assert ((n_elts % in_n_elts) == 0);
1298e4b17023SJohn Marino 	      for (i = 0; i < n_elts; i++)
1299e4b17023SJohn Marino 	        RTVEC_ELT (v, i) = CONST_VECTOR_ELT (op, i % in_n_elts);
1300e4b17023SJohn Marino 	    }
1301e4b17023SJohn Marino 	  return gen_rtx_CONST_VECTOR (mode, v);
1302e4b17023SJohn Marino 	}
1303e4b17023SJohn Marino     }
1304e4b17023SJohn Marino 
1305e4b17023SJohn Marino   if (VECTOR_MODE_P (mode) && GET_CODE (op) == CONST_VECTOR)
1306e4b17023SJohn Marino     {
1307e4b17023SJohn Marino       int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
1308e4b17023SJohn Marino       unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
1309e4b17023SJohn Marino       enum machine_mode opmode = GET_MODE (op);
1310e4b17023SJohn Marino       int op_elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
1311e4b17023SJohn Marino       unsigned op_n_elts = (GET_MODE_SIZE (opmode) / op_elt_size);
1312e4b17023SJohn Marino       rtvec v = rtvec_alloc (n_elts);
1313e4b17023SJohn Marino       unsigned int i;
1314e4b17023SJohn Marino 
1315e4b17023SJohn Marino       gcc_assert (op_n_elts == n_elts);
1316e4b17023SJohn Marino       for (i = 0; i < n_elts; i++)
1317e4b17023SJohn Marino 	{
1318e4b17023SJohn Marino 	  rtx x = simplify_unary_operation (code, GET_MODE_INNER (mode),
1319e4b17023SJohn Marino 					    CONST_VECTOR_ELT (op, i),
1320e4b17023SJohn Marino 					    GET_MODE_INNER (opmode));
1321e4b17023SJohn Marino 	  if (!x)
1322e4b17023SJohn Marino 	    return 0;
1323e4b17023SJohn Marino 	  RTVEC_ELT (v, i) = x;
1324e4b17023SJohn Marino 	}
1325e4b17023SJohn Marino       return gen_rtx_CONST_VECTOR (mode, v);
1326e4b17023SJohn Marino     }
1327e4b17023SJohn Marino 
1328e4b17023SJohn Marino   /* The order of these tests is critical so that, for example, we don't
1329e4b17023SJohn Marino      check the wrong mode (input vs. output) for a conversion operation,
1330e4b17023SJohn Marino      such as FIX.  At some point, this should be simplified.  */
1331e4b17023SJohn Marino 
1332e4b17023SJohn Marino   if (code == FLOAT && GET_MODE (op) == VOIDmode
1333e4b17023SJohn Marino       && (GET_CODE (op) == CONST_DOUBLE || CONST_INT_P (op)))
1334e4b17023SJohn Marino     {
1335e4b17023SJohn Marino       HOST_WIDE_INT hv, lv;
1336e4b17023SJohn Marino       REAL_VALUE_TYPE d;
1337e4b17023SJohn Marino 
1338e4b17023SJohn Marino       if (CONST_INT_P (op))
1339e4b17023SJohn Marino 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
1340e4b17023SJohn Marino       else
1341e4b17023SJohn Marino 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
1342e4b17023SJohn Marino 
1343e4b17023SJohn Marino       REAL_VALUE_FROM_INT (d, lv, hv, mode);
1344e4b17023SJohn Marino       d = real_value_truncate (mode, d);
1345e4b17023SJohn Marino       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
1346e4b17023SJohn Marino     }
1347e4b17023SJohn Marino   else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode
1348e4b17023SJohn Marino 	   && (GET_CODE (op) == CONST_DOUBLE
1349e4b17023SJohn Marino 	       || CONST_INT_P (op)))
1350e4b17023SJohn Marino     {
1351e4b17023SJohn Marino       HOST_WIDE_INT hv, lv;
1352e4b17023SJohn Marino       REAL_VALUE_TYPE d;
1353e4b17023SJohn Marino 
1354e4b17023SJohn Marino       if (CONST_INT_P (op))
1355e4b17023SJohn Marino 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
1356e4b17023SJohn Marino       else
1357e4b17023SJohn Marino 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
1358e4b17023SJohn Marino 
1359e4b17023SJohn Marino       if (op_mode == VOIDmode)
1360e4b17023SJohn Marino 	{
1361e4b17023SJohn Marino 	  /* We don't know how to interpret negative-looking numbers in
1362e4b17023SJohn Marino 	     this case, so don't try to fold those.  */
1363e4b17023SJohn Marino 	  if (hv < 0)
1364e4b17023SJohn Marino 	    return 0;
1365e4b17023SJohn Marino 	}
1366e4b17023SJohn Marino       else if (GET_MODE_PRECISION (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
1367e4b17023SJohn Marino 	;
1368e4b17023SJohn Marino       else
1369e4b17023SJohn Marino 	hv = 0, lv &= GET_MODE_MASK (op_mode);
1370e4b17023SJohn Marino 
1371e4b17023SJohn Marino       REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
1372e4b17023SJohn Marino       d = real_value_truncate (mode, d);
1373e4b17023SJohn Marino       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
1374e4b17023SJohn Marino     }
1375e4b17023SJohn Marino 
1376e4b17023SJohn Marino   if (CONST_INT_P (op)
1377e4b17023SJohn Marino       && width <= HOST_BITS_PER_WIDE_INT && width > 0)
1378e4b17023SJohn Marino     {
1379e4b17023SJohn Marino       HOST_WIDE_INT arg0 = INTVAL (op);
1380e4b17023SJohn Marino       HOST_WIDE_INT val;
1381e4b17023SJohn Marino 
1382e4b17023SJohn Marino       switch (code)
1383e4b17023SJohn Marino 	{
1384e4b17023SJohn Marino 	case NOT:
1385e4b17023SJohn Marino 	  val = ~ arg0;
1386e4b17023SJohn Marino 	  break;
1387e4b17023SJohn Marino 
1388e4b17023SJohn Marino 	case NEG:
1389e4b17023SJohn Marino 	  val = - arg0;
1390e4b17023SJohn Marino 	  break;
1391e4b17023SJohn Marino 
1392e4b17023SJohn Marino 	case ABS:
1393e4b17023SJohn Marino 	  val = (arg0 >= 0 ? arg0 : - arg0);
1394e4b17023SJohn Marino 	  break;
1395e4b17023SJohn Marino 
1396e4b17023SJohn Marino 	case FFS:
1397e4b17023SJohn Marino 	  arg0 &= GET_MODE_MASK (mode);
1398e4b17023SJohn Marino 	  val = ffs_hwi (arg0);
1399e4b17023SJohn Marino 	  break;
1400e4b17023SJohn Marino 
1401e4b17023SJohn Marino 	case CLZ:
1402e4b17023SJohn Marino 	  arg0 &= GET_MODE_MASK (mode);
1403e4b17023SJohn Marino 	  if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
1404e4b17023SJohn Marino 	    ;
1405e4b17023SJohn Marino 	  else
1406e4b17023SJohn Marino 	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 1;
1407e4b17023SJohn Marino 	  break;
1408e4b17023SJohn Marino 
1409e4b17023SJohn Marino 	case CLRSB:
1410e4b17023SJohn Marino 	  arg0 &= GET_MODE_MASK (mode);
1411e4b17023SJohn Marino 	  if (arg0 == 0)
1412e4b17023SJohn Marino 	    val = GET_MODE_PRECISION (mode) - 1;
1413e4b17023SJohn Marino 	  else if (arg0 >= 0)
1414e4b17023SJohn Marino 	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 2;
1415e4b17023SJohn Marino 	  else if (arg0 < 0)
1416e4b17023SJohn Marino 	    val = GET_MODE_PRECISION (mode) - floor_log2 (~arg0) - 2;
1417e4b17023SJohn Marino 	  break;
1418e4b17023SJohn Marino 
1419e4b17023SJohn Marino 	case CTZ:
1420e4b17023SJohn Marino 	  arg0 &= GET_MODE_MASK (mode);
1421e4b17023SJohn Marino 	  if (arg0 == 0)
1422e4b17023SJohn Marino 	    {
1423e4b17023SJohn Marino 	      /* Even if the value at zero is undefined, we have to come
1424e4b17023SJohn Marino 		 up with some replacement.  Seems good enough.  */
1425e4b17023SJohn Marino 	      if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
1426e4b17023SJohn Marino 		val = GET_MODE_PRECISION (mode);
1427e4b17023SJohn Marino 	    }
1428e4b17023SJohn Marino 	  else
1429e4b17023SJohn Marino 	    val = ctz_hwi (arg0);
1430e4b17023SJohn Marino 	  break;
1431e4b17023SJohn Marino 
1432e4b17023SJohn Marino 	case POPCOUNT:
1433e4b17023SJohn Marino 	  arg0 &= GET_MODE_MASK (mode);
1434e4b17023SJohn Marino 	  val = 0;
1435e4b17023SJohn Marino 	  while (arg0)
1436e4b17023SJohn Marino 	    val++, arg0 &= arg0 - 1;
1437e4b17023SJohn Marino 	  break;
1438e4b17023SJohn Marino 
1439e4b17023SJohn Marino 	case PARITY:
1440e4b17023SJohn Marino 	  arg0 &= GET_MODE_MASK (mode);
1441e4b17023SJohn Marino 	  val = 0;
1442e4b17023SJohn Marino 	  while (arg0)
1443e4b17023SJohn Marino 	    val++, arg0 &= arg0 - 1;
1444e4b17023SJohn Marino 	  val &= 1;
1445e4b17023SJohn Marino 	  break;
1446e4b17023SJohn Marino 
1447e4b17023SJohn Marino 	case BSWAP:
1448e4b17023SJohn Marino 	  {
1449e4b17023SJohn Marino 	    unsigned int s;
1450e4b17023SJohn Marino 
1451e4b17023SJohn Marino 	    val = 0;
1452e4b17023SJohn Marino 	    for (s = 0; s < width; s += 8)
1453e4b17023SJohn Marino 	      {
1454e4b17023SJohn Marino 		unsigned int d = width - s - 8;
1455e4b17023SJohn Marino 		unsigned HOST_WIDE_INT byte;
1456e4b17023SJohn Marino 		byte = (arg0 >> s) & 0xff;
1457e4b17023SJohn Marino 		val |= byte << d;
1458e4b17023SJohn Marino 	      }
1459e4b17023SJohn Marino 	  }
1460e4b17023SJohn Marino 	  break;
1461e4b17023SJohn Marino 
1462e4b17023SJohn Marino 	case TRUNCATE:
1463e4b17023SJohn Marino 	  val = arg0;
1464e4b17023SJohn Marino 	  break;
1465e4b17023SJohn Marino 
1466e4b17023SJohn Marino 	case ZERO_EXTEND:
1467e4b17023SJohn Marino 	  /* When zero-extending a CONST_INT, we need to know its
1468e4b17023SJohn Marino              original mode.  */
1469e4b17023SJohn Marino 	  gcc_assert (op_mode != VOIDmode);
1470e4b17023SJohn Marino 	  if (op_width == HOST_BITS_PER_WIDE_INT)
1471e4b17023SJohn Marino 	    {
1472e4b17023SJohn Marino 	      /* If we were really extending the mode,
1473e4b17023SJohn Marino 		 we would have to distinguish between zero-extension
1474e4b17023SJohn Marino 		 and sign-extension.  */
1475e4b17023SJohn Marino 	      gcc_assert (width == op_width);
1476e4b17023SJohn Marino 	      val = arg0;
1477e4b17023SJohn Marino 	    }
1478e4b17023SJohn Marino 	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
1479e4b17023SJohn Marino 	    val = arg0 & GET_MODE_MASK (op_mode);
1480e4b17023SJohn Marino 	  else
1481e4b17023SJohn Marino 	    return 0;
1482e4b17023SJohn Marino 	  break;
1483e4b17023SJohn Marino 
1484e4b17023SJohn Marino 	case SIGN_EXTEND:
1485e4b17023SJohn Marino 	  if (op_mode == VOIDmode)
1486e4b17023SJohn Marino 	    op_mode = mode;
1487e4b17023SJohn Marino 	  op_width = GET_MODE_PRECISION (op_mode);
1488e4b17023SJohn Marino 	  if (op_width == HOST_BITS_PER_WIDE_INT)
1489e4b17023SJohn Marino 	    {
1490e4b17023SJohn Marino 	      /* If we were really extending the mode,
1491e4b17023SJohn Marino 		 we would have to distinguish between zero-extension
1492e4b17023SJohn Marino 		 and sign-extension.  */
1493e4b17023SJohn Marino 	      gcc_assert (width == op_width);
1494e4b17023SJohn Marino 	      val = arg0;
1495e4b17023SJohn Marino 	    }
1496e4b17023SJohn Marino 	  else if (op_width < HOST_BITS_PER_WIDE_INT)
1497e4b17023SJohn Marino 	    {
1498e4b17023SJohn Marino 	      val = arg0 & GET_MODE_MASK (op_mode);
1499e4b17023SJohn Marino 	      if (val_signbit_known_set_p (op_mode, val))
1500e4b17023SJohn Marino 		val |= ~GET_MODE_MASK (op_mode);
1501e4b17023SJohn Marino 	    }
1502e4b17023SJohn Marino 	  else
1503e4b17023SJohn Marino 	    return 0;
1504e4b17023SJohn Marino 	  break;
1505e4b17023SJohn Marino 
1506e4b17023SJohn Marino 	case SQRT:
1507e4b17023SJohn Marino 	case FLOAT_EXTEND:
1508e4b17023SJohn Marino 	case FLOAT_TRUNCATE:
1509e4b17023SJohn Marino 	case SS_TRUNCATE:
1510e4b17023SJohn Marino 	case US_TRUNCATE:
1511e4b17023SJohn Marino 	case SS_NEG:
1512e4b17023SJohn Marino 	case US_NEG:
1513e4b17023SJohn Marino 	case SS_ABS:
1514e4b17023SJohn Marino 	  return 0;
1515e4b17023SJohn Marino 
1516e4b17023SJohn Marino 	default:
1517e4b17023SJohn Marino 	  gcc_unreachable ();
1518e4b17023SJohn Marino 	}
1519e4b17023SJohn Marino 
1520e4b17023SJohn Marino       return gen_int_mode (val, mode);
1521e4b17023SJohn Marino     }
1522e4b17023SJohn Marino 
1523e4b17023SJohn Marino   /* We can do some operations on integer CONST_DOUBLEs.  Also allow
1524e4b17023SJohn Marino      for a DImode operation on a CONST_INT.  */
1525e4b17023SJohn Marino   else if (GET_MODE (op) == VOIDmode
1526e4b17023SJohn Marino 	   && width <= HOST_BITS_PER_WIDE_INT * 2
1527e4b17023SJohn Marino 	   && (GET_CODE (op) == CONST_DOUBLE
1528e4b17023SJohn Marino 	       || CONST_INT_P (op)))
1529e4b17023SJohn Marino     {
1530e4b17023SJohn Marino       unsigned HOST_WIDE_INT l1, lv;
1531e4b17023SJohn Marino       HOST_WIDE_INT h1, hv;
1532e4b17023SJohn Marino 
1533e4b17023SJohn Marino       if (GET_CODE (op) == CONST_DOUBLE)
1534e4b17023SJohn Marino 	l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
1535e4b17023SJohn Marino       else
1536e4b17023SJohn Marino 	l1 = INTVAL (op), h1 = HWI_SIGN_EXTEND (l1);
1537e4b17023SJohn Marino 
1538e4b17023SJohn Marino       switch (code)
1539e4b17023SJohn Marino 	{
1540e4b17023SJohn Marino 	case NOT:
1541e4b17023SJohn Marino 	  lv = ~ l1;
1542e4b17023SJohn Marino 	  hv = ~ h1;
1543e4b17023SJohn Marino 	  break;
1544e4b17023SJohn Marino 
1545e4b17023SJohn Marino 	case NEG:
1546e4b17023SJohn Marino 	  neg_double (l1, h1, &lv, &hv);
1547e4b17023SJohn Marino 	  break;
1548e4b17023SJohn Marino 
1549e4b17023SJohn Marino 	case ABS:
1550e4b17023SJohn Marino 	  if (h1 < 0)
1551e4b17023SJohn Marino 	    neg_double (l1, h1, &lv, &hv);
1552e4b17023SJohn Marino 	  else
1553e4b17023SJohn Marino 	    lv = l1, hv = h1;
1554e4b17023SJohn Marino 	  break;
1555e4b17023SJohn Marino 
1556e4b17023SJohn Marino 	case FFS:
1557e4b17023SJohn Marino 	  hv = 0;
1558e4b17023SJohn Marino 	  if (l1 != 0)
1559e4b17023SJohn Marino 	    lv = ffs_hwi (l1);
1560e4b17023SJohn Marino 	  else if (h1 != 0)
1561e4b17023SJohn Marino 	    lv = HOST_BITS_PER_WIDE_INT + ffs_hwi (h1);
1562e4b17023SJohn Marino 	  else
1563e4b17023SJohn Marino 	    lv = 0;
1564e4b17023SJohn Marino 	  break;
1565e4b17023SJohn Marino 
1566e4b17023SJohn Marino 	case CLZ:
1567e4b17023SJohn Marino 	  hv = 0;
1568e4b17023SJohn Marino 	  if (h1 != 0)
1569e4b17023SJohn Marino 	    lv = GET_MODE_PRECISION (mode) - floor_log2 (h1) - 1
1570e4b17023SJohn Marino 	      - HOST_BITS_PER_WIDE_INT;
1571e4b17023SJohn Marino 	  else if (l1 != 0)
1572e4b17023SJohn Marino 	    lv = GET_MODE_PRECISION (mode) - floor_log2 (l1) - 1;
1573e4b17023SJohn Marino 	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, lv))
1574e4b17023SJohn Marino 	    lv = GET_MODE_PRECISION (mode);
1575e4b17023SJohn Marino 	  break;
1576e4b17023SJohn Marino 
1577e4b17023SJohn Marino 	case CTZ:
1578e4b17023SJohn Marino 	  hv = 0;
1579e4b17023SJohn Marino 	  if (l1 != 0)
1580e4b17023SJohn Marino 	    lv = ctz_hwi (l1);
1581e4b17023SJohn Marino 	  else if (h1 != 0)
1582e4b17023SJohn Marino 	    lv = HOST_BITS_PER_WIDE_INT + ctz_hwi (h1);
1583e4b17023SJohn Marino 	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, lv))
1584e4b17023SJohn Marino 	    lv = GET_MODE_PRECISION (mode);
1585e4b17023SJohn Marino 	  break;
1586e4b17023SJohn Marino 
1587e4b17023SJohn Marino 	case POPCOUNT:
1588e4b17023SJohn Marino 	  hv = 0;
1589e4b17023SJohn Marino 	  lv = 0;
1590e4b17023SJohn Marino 	  while (l1)
1591e4b17023SJohn Marino 	    lv++, l1 &= l1 - 1;
1592e4b17023SJohn Marino 	  while (h1)
1593e4b17023SJohn Marino 	    lv++, h1 &= h1 - 1;
1594e4b17023SJohn Marino 	  break;
1595e4b17023SJohn Marino 
1596e4b17023SJohn Marino 	case PARITY:
1597e4b17023SJohn Marino 	  hv = 0;
1598e4b17023SJohn Marino 	  lv = 0;
1599e4b17023SJohn Marino 	  while (l1)
1600e4b17023SJohn Marino 	    lv++, l1 &= l1 - 1;
1601e4b17023SJohn Marino 	  while (h1)
1602e4b17023SJohn Marino 	    lv++, h1 &= h1 - 1;
1603e4b17023SJohn Marino 	  lv &= 1;
1604e4b17023SJohn Marino 	  break;
1605e4b17023SJohn Marino 
1606e4b17023SJohn Marino 	case BSWAP:
1607e4b17023SJohn Marino 	  {
1608e4b17023SJohn Marino 	    unsigned int s;
1609e4b17023SJohn Marino 
1610e4b17023SJohn Marino 	    hv = 0;
1611e4b17023SJohn Marino 	    lv = 0;
1612e4b17023SJohn Marino 	    for (s = 0; s < width; s += 8)
1613e4b17023SJohn Marino 	      {
1614e4b17023SJohn Marino 		unsigned int d = width - s - 8;
1615e4b17023SJohn Marino 		unsigned HOST_WIDE_INT byte;
1616e4b17023SJohn Marino 
1617e4b17023SJohn Marino 		if (s < HOST_BITS_PER_WIDE_INT)
1618e4b17023SJohn Marino 		  byte = (l1 >> s) & 0xff;
1619e4b17023SJohn Marino 		else
1620e4b17023SJohn Marino 		  byte = (h1 >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
1621e4b17023SJohn Marino 
1622e4b17023SJohn Marino 		if (d < HOST_BITS_PER_WIDE_INT)
1623e4b17023SJohn Marino 		  lv |= byte << d;
1624e4b17023SJohn Marino 		else
1625e4b17023SJohn Marino 		  hv |= byte << (d - HOST_BITS_PER_WIDE_INT);
1626e4b17023SJohn Marino 	      }
1627e4b17023SJohn Marino 	  }
1628e4b17023SJohn Marino 	  break;
1629e4b17023SJohn Marino 
1630e4b17023SJohn Marino 	case TRUNCATE:
1631e4b17023SJohn Marino 	  /* This is just a change-of-mode, so do nothing.  */
1632e4b17023SJohn Marino 	  lv = l1, hv = h1;
1633e4b17023SJohn Marino 	  break;
1634e4b17023SJohn Marino 
1635e4b17023SJohn Marino 	case ZERO_EXTEND:
1636e4b17023SJohn Marino 	  gcc_assert (op_mode != VOIDmode);
1637e4b17023SJohn Marino 
1638e4b17023SJohn Marino 	  if (op_width > HOST_BITS_PER_WIDE_INT)
1639e4b17023SJohn Marino 	    return 0;
1640e4b17023SJohn Marino 
1641e4b17023SJohn Marino 	  hv = 0;
1642e4b17023SJohn Marino 	  lv = l1 & GET_MODE_MASK (op_mode);
1643e4b17023SJohn Marino 	  break;
1644e4b17023SJohn Marino 
1645e4b17023SJohn Marino 	case SIGN_EXTEND:
1646e4b17023SJohn Marino 	  if (op_mode == VOIDmode
1647e4b17023SJohn Marino 	      || op_width > HOST_BITS_PER_WIDE_INT)
1648e4b17023SJohn Marino 	    return 0;
1649e4b17023SJohn Marino 	  else
1650e4b17023SJohn Marino 	    {
1651e4b17023SJohn Marino 	      lv = l1 & GET_MODE_MASK (op_mode);
1652e4b17023SJohn Marino 	      if (val_signbit_known_set_p (op_mode, lv))
1653e4b17023SJohn Marino 		lv |= ~GET_MODE_MASK (op_mode);
1654e4b17023SJohn Marino 
1655e4b17023SJohn Marino 	      hv = HWI_SIGN_EXTEND (lv);
1656e4b17023SJohn Marino 	    }
1657e4b17023SJohn Marino 	  break;
1658e4b17023SJohn Marino 
1659e4b17023SJohn Marino 	case SQRT:
1660e4b17023SJohn Marino 	  return 0;
1661e4b17023SJohn Marino 
1662e4b17023SJohn Marino 	default:
1663e4b17023SJohn Marino 	  return 0;
1664e4b17023SJohn Marino 	}
1665e4b17023SJohn Marino 
1666e4b17023SJohn Marino       return immed_double_const (lv, hv, mode);
1667e4b17023SJohn Marino     }
1668e4b17023SJohn Marino 
1669e4b17023SJohn Marino   else if (GET_CODE (op) == CONST_DOUBLE
1670e4b17023SJohn Marino 	   && SCALAR_FLOAT_MODE_P (mode)
1671e4b17023SJohn Marino 	   && SCALAR_FLOAT_MODE_P (GET_MODE (op)))
1672e4b17023SJohn Marino     {
1673e4b17023SJohn Marino       REAL_VALUE_TYPE d, t;
1674e4b17023SJohn Marino       REAL_VALUE_FROM_CONST_DOUBLE (d, op);
1675e4b17023SJohn Marino 
1676e4b17023SJohn Marino       switch (code)
1677e4b17023SJohn Marino 	{
1678e4b17023SJohn Marino 	case SQRT:
1679e4b17023SJohn Marino 	  if (HONOR_SNANS (mode) && real_isnan (&d))
1680e4b17023SJohn Marino 	    return 0;
1681e4b17023SJohn Marino 	  real_sqrt (&t, mode, &d);
1682e4b17023SJohn Marino 	  d = t;
1683e4b17023SJohn Marino 	  break;
1684e4b17023SJohn Marino 	case ABS:
1685e4b17023SJohn Marino 	  d = real_value_abs (&d);
1686e4b17023SJohn Marino 	  break;
1687e4b17023SJohn Marino 	case NEG:
1688e4b17023SJohn Marino 	  d = real_value_negate (&d);
1689e4b17023SJohn Marino 	  break;
1690e4b17023SJohn Marino 	case FLOAT_TRUNCATE:
1691e4b17023SJohn Marino 	  d = real_value_truncate (mode, d);
1692e4b17023SJohn Marino 	  break;
1693e4b17023SJohn Marino 	case FLOAT_EXTEND:
1694e4b17023SJohn Marino 	  /* All this does is change the mode, unless changing
1695e4b17023SJohn Marino 	     mode class.  */
1696e4b17023SJohn Marino 	  if (GET_MODE_CLASS (mode) != GET_MODE_CLASS (GET_MODE (op)))
1697e4b17023SJohn Marino 	    real_convert (&d, mode, &d);
1698e4b17023SJohn Marino 	  break;
1699e4b17023SJohn Marino 	case FIX:
1700e4b17023SJohn Marino 	  real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
1701e4b17023SJohn Marino 	  break;
1702e4b17023SJohn Marino 	case NOT:
1703e4b17023SJohn Marino 	  {
1704e4b17023SJohn Marino 	    long tmp[4];
1705e4b17023SJohn Marino 	    int i;
1706e4b17023SJohn Marino 
1707e4b17023SJohn Marino 	    real_to_target (tmp, &d, GET_MODE (op));
1708e4b17023SJohn Marino 	    for (i = 0; i < 4; i++)
1709e4b17023SJohn Marino 	      tmp[i] = ~tmp[i];
1710e4b17023SJohn Marino 	    real_from_target (&d, tmp, mode);
1711e4b17023SJohn Marino 	    break;
1712e4b17023SJohn Marino 	  }
1713e4b17023SJohn Marino 	default:
1714e4b17023SJohn Marino 	  gcc_unreachable ();
1715e4b17023SJohn Marino 	}
1716e4b17023SJohn Marino       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
1717e4b17023SJohn Marino     }
1718e4b17023SJohn Marino 
1719e4b17023SJohn Marino   else if (GET_CODE (op) == CONST_DOUBLE
1720e4b17023SJohn Marino 	   && SCALAR_FLOAT_MODE_P (GET_MODE (op))
1721e4b17023SJohn Marino 	   && GET_MODE_CLASS (mode) == MODE_INT
1722e4b17023SJohn Marino 	   && width <= 2*HOST_BITS_PER_WIDE_INT && width > 0)
1723e4b17023SJohn Marino     {
1724e4b17023SJohn Marino       /* Although the overflow semantics of RTL's FIX and UNSIGNED_FIX
1725e4b17023SJohn Marino 	 operators are intentionally left unspecified (to ease implementation
1726e4b17023SJohn Marino 	 by target backends), for consistency, this routine implements the
1727e4b17023SJohn Marino 	 same semantics for constant folding as used by the middle-end.  */
1728e4b17023SJohn Marino 
1729e4b17023SJohn Marino       /* This was formerly used only for non-IEEE float.
1730e4b17023SJohn Marino 	 eggert@twinsun.com says it is safe for IEEE also.  */
1731e4b17023SJohn Marino       HOST_WIDE_INT xh, xl, th, tl;
1732e4b17023SJohn Marino       REAL_VALUE_TYPE x, t;
1733e4b17023SJohn Marino       REAL_VALUE_FROM_CONST_DOUBLE (x, op);
1734e4b17023SJohn Marino       switch (code)
1735e4b17023SJohn Marino 	{
1736e4b17023SJohn Marino 	case FIX:
1737e4b17023SJohn Marino 	  if (REAL_VALUE_ISNAN (x))
1738e4b17023SJohn Marino 	    return const0_rtx;
1739e4b17023SJohn Marino 
1740e4b17023SJohn Marino 	  /* Test against the signed upper bound.  */
1741e4b17023SJohn Marino 	  if (width > HOST_BITS_PER_WIDE_INT)
1742e4b17023SJohn Marino 	    {
1743e4b17023SJohn Marino 	      th = ((unsigned HOST_WIDE_INT) 1
1744e4b17023SJohn Marino 		    << (width - HOST_BITS_PER_WIDE_INT - 1)) - 1;
1745e4b17023SJohn Marino 	      tl = -1;
1746e4b17023SJohn Marino 	    }
1747e4b17023SJohn Marino 	  else
1748e4b17023SJohn Marino 	    {
1749e4b17023SJohn Marino 	      th = 0;
1750e4b17023SJohn Marino 	      tl = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1;
1751e4b17023SJohn Marino 	    }
1752e4b17023SJohn Marino 	  real_from_integer (&t, VOIDmode, tl, th, 0);
1753e4b17023SJohn Marino 	  if (REAL_VALUES_LESS (t, x))
1754e4b17023SJohn Marino 	    {
1755e4b17023SJohn Marino 	      xh = th;
1756e4b17023SJohn Marino 	      xl = tl;
1757e4b17023SJohn Marino 	      break;
1758e4b17023SJohn Marino 	    }
1759e4b17023SJohn Marino 
1760e4b17023SJohn Marino 	  /* Test against the signed lower bound.  */
1761e4b17023SJohn Marino 	  if (width > HOST_BITS_PER_WIDE_INT)
1762e4b17023SJohn Marino 	    {
1763e4b17023SJohn Marino 	      th = (unsigned HOST_WIDE_INT) (-1)
1764e4b17023SJohn Marino 		   << (width - HOST_BITS_PER_WIDE_INT - 1);
1765e4b17023SJohn Marino 	      tl = 0;
1766e4b17023SJohn Marino 	    }
1767e4b17023SJohn Marino 	  else
1768e4b17023SJohn Marino 	    {
1769e4b17023SJohn Marino 	      th = -1;
1770e4b17023SJohn Marino 	      tl = (unsigned HOST_WIDE_INT) (-1) << (width - 1);
1771e4b17023SJohn Marino 	    }
1772e4b17023SJohn Marino 	  real_from_integer (&t, VOIDmode, tl, th, 0);
1773e4b17023SJohn Marino 	  if (REAL_VALUES_LESS (x, t))
1774e4b17023SJohn Marino 	    {
1775e4b17023SJohn Marino 	      xh = th;
1776e4b17023SJohn Marino 	      xl = tl;
1777e4b17023SJohn Marino 	      break;
1778e4b17023SJohn Marino 	    }
1779e4b17023SJohn Marino 	  REAL_VALUE_TO_INT (&xl, &xh, x);
1780e4b17023SJohn Marino 	  break;
1781e4b17023SJohn Marino 
1782e4b17023SJohn Marino 	case UNSIGNED_FIX:
1783e4b17023SJohn Marino 	  if (REAL_VALUE_ISNAN (x) || REAL_VALUE_NEGATIVE (x))
1784e4b17023SJohn Marino 	    return const0_rtx;
1785e4b17023SJohn Marino 
1786e4b17023SJohn Marino 	  /* Test against the unsigned upper bound.  */
1787e4b17023SJohn Marino 	  if (width == 2*HOST_BITS_PER_WIDE_INT)
1788e4b17023SJohn Marino 	    {
1789e4b17023SJohn Marino 	      th = -1;
1790e4b17023SJohn Marino 	      tl = -1;
1791e4b17023SJohn Marino 	    }
1792e4b17023SJohn Marino 	  else if (width >= HOST_BITS_PER_WIDE_INT)
1793e4b17023SJohn Marino 	    {
1794e4b17023SJohn Marino 	      th = ((unsigned HOST_WIDE_INT) 1
1795e4b17023SJohn Marino 		    << (width - HOST_BITS_PER_WIDE_INT)) - 1;
1796e4b17023SJohn Marino 	      tl = -1;
1797e4b17023SJohn Marino 	    }
1798e4b17023SJohn Marino 	  else
1799e4b17023SJohn Marino 	    {
1800e4b17023SJohn Marino 	      th = 0;
1801e4b17023SJohn Marino 	      tl = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
1802e4b17023SJohn Marino 	    }
1803e4b17023SJohn Marino 	  real_from_integer (&t, VOIDmode, tl, th, 1);
1804e4b17023SJohn Marino 	  if (REAL_VALUES_LESS (t, x))
1805e4b17023SJohn Marino 	    {
1806e4b17023SJohn Marino 	      xh = th;
1807e4b17023SJohn Marino 	      xl = tl;
1808e4b17023SJohn Marino 	      break;
1809e4b17023SJohn Marino 	    }
1810e4b17023SJohn Marino 
1811e4b17023SJohn Marino 	  REAL_VALUE_TO_INT (&xl, &xh, x);
1812e4b17023SJohn Marino 	  break;
1813e4b17023SJohn Marino 
1814e4b17023SJohn Marino 	default:
1815e4b17023SJohn Marino 	  gcc_unreachable ();
1816e4b17023SJohn Marino 	}
1817e4b17023SJohn Marino       return immed_double_const (xl, xh, mode);
1818e4b17023SJohn Marino     }
1819e4b17023SJohn Marino 
1820e4b17023SJohn Marino   return NULL_RTX;
1821e4b17023SJohn Marino }
1822e4b17023SJohn Marino 
1823e4b17023SJohn Marino /* Subroutine of simplify_binary_operation to simplify a commutative,
1824e4b17023SJohn Marino    associative binary operation CODE with result mode MODE, operating
1825e4b17023SJohn Marino    on OP0 and OP1.  CODE is currently one of PLUS, MULT, AND, IOR, XOR,
1826e4b17023SJohn Marino    SMIN, SMAX, UMIN or UMAX.  Return zero if no simplification or
1827e4b17023SJohn Marino    canonicalization is possible.  */
1828e4b17023SJohn Marino 
1829e4b17023SJohn Marino static rtx
simplify_associative_operation(enum rtx_code code,enum machine_mode mode,rtx op0,rtx op1)1830e4b17023SJohn Marino simplify_associative_operation (enum rtx_code code, enum machine_mode mode,
1831e4b17023SJohn Marino 				rtx op0, rtx op1)
1832e4b17023SJohn Marino {
1833e4b17023SJohn Marino   rtx tem;
1834e4b17023SJohn Marino 
1835e4b17023SJohn Marino   /* Linearize the operator to the left.  */
1836e4b17023SJohn Marino   if (GET_CODE (op1) == code)
1837e4b17023SJohn Marino     {
1838e4b17023SJohn Marino       /* "(a op b) op (c op d)" becomes "((a op b) op c) op d)".  */
1839e4b17023SJohn Marino       if (GET_CODE (op0) == code)
1840e4b17023SJohn Marino 	{
1841e4b17023SJohn Marino 	  tem = simplify_gen_binary (code, mode, op0, XEXP (op1, 0));
1842e4b17023SJohn Marino 	  return simplify_gen_binary (code, mode, tem, XEXP (op1, 1));
1843e4b17023SJohn Marino 	}
1844e4b17023SJohn Marino 
1845e4b17023SJohn Marino       /* "a op (b op c)" becomes "(b op c) op a".  */
1846e4b17023SJohn Marino       if (! swap_commutative_operands_p (op1, op0))
1847e4b17023SJohn Marino 	return simplify_gen_binary (code, mode, op1, op0);
1848e4b17023SJohn Marino 
1849e4b17023SJohn Marino       tem = op0;
1850e4b17023SJohn Marino       op0 = op1;
1851e4b17023SJohn Marino       op1 = tem;
1852e4b17023SJohn Marino     }
1853e4b17023SJohn Marino 
1854e4b17023SJohn Marino   if (GET_CODE (op0) == code)
1855e4b17023SJohn Marino     {
1856e4b17023SJohn Marino       /* Canonicalize "(x op c) op y" as "(x op y) op c".  */
1857e4b17023SJohn Marino       if (swap_commutative_operands_p (XEXP (op0, 1), op1))
1858e4b17023SJohn Marino 	{
1859e4b17023SJohn Marino 	  tem = simplify_gen_binary (code, mode, XEXP (op0, 0), op1);
1860e4b17023SJohn Marino 	  return simplify_gen_binary (code, mode, tem, XEXP (op0, 1));
1861e4b17023SJohn Marino 	}
1862e4b17023SJohn Marino 
1863e4b17023SJohn Marino       /* Attempt to simplify "(a op b) op c" as "a op (b op c)".  */
1864e4b17023SJohn Marino       tem = simplify_binary_operation (code, mode, XEXP (op0, 1), op1);
1865e4b17023SJohn Marino       if (tem != 0)
1866e4b17023SJohn Marino         return simplify_gen_binary (code, mode, XEXP (op0, 0), tem);
1867e4b17023SJohn Marino 
1868e4b17023SJohn Marino       /* Attempt to simplify "(a op b) op c" as "(a op c) op b".  */
1869e4b17023SJohn Marino       tem = simplify_binary_operation (code, mode, XEXP (op0, 0), op1);
1870e4b17023SJohn Marino       if (tem != 0)
1871e4b17023SJohn Marino         return simplify_gen_binary (code, mode, tem, XEXP (op0, 1));
1872e4b17023SJohn Marino     }
1873e4b17023SJohn Marino 
1874e4b17023SJohn Marino   return 0;
1875e4b17023SJohn Marino }
1876e4b17023SJohn Marino 
1877e4b17023SJohn Marino 
1878e4b17023SJohn Marino /* Simplify a binary operation CODE with result mode MODE, operating on OP0
1879e4b17023SJohn Marino    and OP1.  Return 0 if no simplification is possible.
1880e4b17023SJohn Marino 
1881e4b17023SJohn Marino    Don't use this for relational operations such as EQ or LT.
1882e4b17023SJohn Marino    Use simplify_relational_operation instead.  */
1883e4b17023SJohn Marino rtx
simplify_binary_operation(enum rtx_code code,enum machine_mode mode,rtx op0,rtx op1)1884e4b17023SJohn Marino simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
1885e4b17023SJohn Marino 			   rtx op0, rtx op1)
1886e4b17023SJohn Marino {
1887e4b17023SJohn Marino   rtx trueop0, trueop1;
1888e4b17023SJohn Marino   rtx tem;
1889e4b17023SJohn Marino 
1890e4b17023SJohn Marino   /* Relational operations don't work here.  We must know the mode
1891e4b17023SJohn Marino      of the operands in order to do the comparison correctly.
1892e4b17023SJohn Marino      Assuming a full word can give incorrect results.
1893e4b17023SJohn Marino      Consider comparing 128 with -128 in QImode.  */
1894e4b17023SJohn Marino   gcc_assert (GET_RTX_CLASS (code) != RTX_COMPARE);
1895e4b17023SJohn Marino   gcc_assert (GET_RTX_CLASS (code) != RTX_COMM_COMPARE);
1896e4b17023SJohn Marino 
1897e4b17023SJohn Marino   /* Make sure the constant is second.  */
1898e4b17023SJohn Marino   if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
1899e4b17023SJohn Marino       && swap_commutative_operands_p (op0, op1))
1900e4b17023SJohn Marino     {
1901e4b17023SJohn Marino       tem = op0, op0 = op1, op1 = tem;
1902e4b17023SJohn Marino     }
1903e4b17023SJohn Marino 
1904e4b17023SJohn Marino   trueop0 = avoid_constant_pool_reference (op0);
1905e4b17023SJohn Marino   trueop1 = avoid_constant_pool_reference (op1);
1906e4b17023SJohn Marino 
1907e4b17023SJohn Marino   tem = simplify_const_binary_operation (code, mode, trueop0, trueop1);
1908e4b17023SJohn Marino   if (tem)
1909e4b17023SJohn Marino     return tem;
1910e4b17023SJohn Marino   return simplify_binary_operation_1 (code, mode, op0, op1, trueop0, trueop1);
1911e4b17023SJohn Marino }
1912e4b17023SJohn Marino 
1913e4b17023SJohn Marino /* Subroutine of simplify_binary_operation.  Simplify a binary operation
1914e4b17023SJohn Marino    CODE with result mode MODE, operating on OP0 and OP1.  If OP0 and/or
1915e4b17023SJohn Marino    OP1 are constant pool references, TRUEOP0 and TRUEOP1 represent the
1916e4b17023SJohn Marino    actual constants.  */
1917e4b17023SJohn Marino 
1918e4b17023SJohn Marino static rtx
simplify_binary_operation_1(enum rtx_code code,enum machine_mode mode,rtx op0,rtx op1,rtx trueop0,rtx trueop1)1919e4b17023SJohn Marino simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
1920e4b17023SJohn Marino 			     rtx op0, rtx op1, rtx trueop0, rtx trueop1)
1921e4b17023SJohn Marino {
1922e4b17023SJohn Marino   rtx tem, reversed, opleft, opright;
1923e4b17023SJohn Marino   HOST_WIDE_INT val;
1924e4b17023SJohn Marino   unsigned int width = GET_MODE_PRECISION (mode);
1925e4b17023SJohn Marino 
1926e4b17023SJohn Marino   /* Even if we can't compute a constant result,
1927e4b17023SJohn Marino      there are some cases worth simplifying.  */
1928e4b17023SJohn Marino 
1929e4b17023SJohn Marino   switch (code)
1930e4b17023SJohn Marino     {
1931e4b17023SJohn Marino     case PLUS:
1932e4b17023SJohn Marino       /* Maybe simplify x + 0 to x.  The two expressions are equivalent
1933e4b17023SJohn Marino 	 when x is NaN, infinite, or finite and nonzero.  They aren't
1934e4b17023SJohn Marino 	 when x is -0 and the rounding mode is not towards -infinity,
1935e4b17023SJohn Marino 	 since (-0) + 0 is then 0.  */
1936e4b17023SJohn Marino       if (!HONOR_SIGNED_ZEROS (mode) && trueop1 == CONST0_RTX (mode))
1937e4b17023SJohn Marino 	return op0;
1938e4b17023SJohn Marino 
1939e4b17023SJohn Marino       /* ((-a) + b) -> (b - a) and similarly for (a + (-b)).  These
1940e4b17023SJohn Marino 	 transformations are safe even for IEEE.  */
1941e4b17023SJohn Marino       if (GET_CODE (op0) == NEG)
1942e4b17023SJohn Marino 	return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
1943e4b17023SJohn Marino       else if (GET_CODE (op1) == NEG)
1944e4b17023SJohn Marino 	return simplify_gen_binary (MINUS, mode, op0, XEXP (op1, 0));
1945e4b17023SJohn Marino 
1946e4b17023SJohn Marino       /* (~a) + 1 -> -a */
1947e4b17023SJohn Marino       if (INTEGRAL_MODE_P (mode)
1948e4b17023SJohn Marino 	  && GET_CODE (op0) == NOT
1949e4b17023SJohn Marino 	  && trueop1 == const1_rtx)
1950e4b17023SJohn Marino 	return simplify_gen_unary (NEG, mode, XEXP (op0, 0), mode);
1951e4b17023SJohn Marino 
1952e4b17023SJohn Marino       /* Handle both-operands-constant cases.  We can only add
1953e4b17023SJohn Marino 	 CONST_INTs to constants since the sum of relocatable symbols
1954e4b17023SJohn Marino 	 can't be handled by most assemblers.  Don't add CONST_INT
1955e4b17023SJohn Marino 	 to CONST_INT since overflow won't be computed properly if wider
1956e4b17023SJohn Marino 	 than HOST_BITS_PER_WIDE_INT.  */
1957e4b17023SJohn Marino 
1958e4b17023SJohn Marino       if ((GET_CODE (op0) == CONST
1959e4b17023SJohn Marino 	   || GET_CODE (op0) == SYMBOL_REF
1960e4b17023SJohn Marino 	   || GET_CODE (op0) == LABEL_REF)
1961e4b17023SJohn Marino 	  && CONST_INT_P (op1))
1962e4b17023SJohn Marino 	return plus_constant (op0, INTVAL (op1));
1963e4b17023SJohn Marino       else if ((GET_CODE (op1) == CONST
1964e4b17023SJohn Marino 		|| GET_CODE (op1) == SYMBOL_REF
1965e4b17023SJohn Marino 		|| GET_CODE (op1) == LABEL_REF)
1966e4b17023SJohn Marino 	       && CONST_INT_P (op0))
1967e4b17023SJohn Marino 	return plus_constant (op1, INTVAL (op0));
1968e4b17023SJohn Marino 
1969e4b17023SJohn Marino       /* See if this is something like X * C - X or vice versa or
1970e4b17023SJohn Marino 	 if the multiplication is written as a shift.  If so, we can
1971e4b17023SJohn Marino 	 distribute and make a new multiply, shift, or maybe just
1972e4b17023SJohn Marino 	 have X (if C is 2 in the example above).  But don't make
1973e4b17023SJohn Marino 	 something more expensive than we had before.  */
1974e4b17023SJohn Marino 
1975e4b17023SJohn Marino       if (SCALAR_INT_MODE_P (mode))
1976e4b17023SJohn Marino 	{
1977e4b17023SJohn Marino 	  double_int coeff0, coeff1;
1978e4b17023SJohn Marino 	  rtx lhs = op0, rhs = op1;
1979e4b17023SJohn Marino 
1980e4b17023SJohn Marino 	  coeff0 = double_int_one;
1981e4b17023SJohn Marino 	  coeff1 = double_int_one;
1982e4b17023SJohn Marino 
1983e4b17023SJohn Marino 	  if (GET_CODE (lhs) == NEG)
1984e4b17023SJohn Marino 	    {
1985e4b17023SJohn Marino 	      coeff0 = double_int_minus_one;
1986e4b17023SJohn Marino 	      lhs = XEXP (lhs, 0);
1987e4b17023SJohn Marino 	    }
1988e4b17023SJohn Marino 	  else if (GET_CODE (lhs) == MULT
1989e4b17023SJohn Marino 		   && CONST_INT_P (XEXP (lhs, 1)))
1990e4b17023SJohn Marino 	    {
1991e4b17023SJohn Marino 	      coeff0 = shwi_to_double_int (INTVAL (XEXP (lhs, 1)));
1992e4b17023SJohn Marino 	      lhs = XEXP (lhs, 0);
1993e4b17023SJohn Marino 	    }
1994e4b17023SJohn Marino 	  else if (GET_CODE (lhs) == ASHIFT
1995e4b17023SJohn Marino 		   && CONST_INT_P (XEXP (lhs, 1))
1996e4b17023SJohn Marino                    && INTVAL (XEXP (lhs, 1)) >= 0
1997e4b17023SJohn Marino 		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
1998e4b17023SJohn Marino 	    {
1999e4b17023SJohn Marino 	      coeff0 = double_int_setbit (double_int_zero,
2000e4b17023SJohn Marino 					  INTVAL (XEXP (lhs, 1)));
2001e4b17023SJohn Marino 	      lhs = XEXP (lhs, 0);
2002e4b17023SJohn Marino 	    }
2003e4b17023SJohn Marino 
2004e4b17023SJohn Marino 	  if (GET_CODE (rhs) == NEG)
2005e4b17023SJohn Marino 	    {
2006e4b17023SJohn Marino 	      coeff1 = double_int_minus_one;
2007e4b17023SJohn Marino 	      rhs = XEXP (rhs, 0);
2008e4b17023SJohn Marino 	    }
2009e4b17023SJohn Marino 	  else if (GET_CODE (rhs) == MULT
2010e4b17023SJohn Marino 		   && CONST_INT_P (XEXP (rhs, 1)))
2011e4b17023SJohn Marino 	    {
2012e4b17023SJohn Marino 	      coeff1 = shwi_to_double_int (INTVAL (XEXP (rhs, 1)));
2013e4b17023SJohn Marino 	      rhs = XEXP (rhs, 0);
2014e4b17023SJohn Marino 	    }
2015e4b17023SJohn Marino 	  else if (GET_CODE (rhs) == ASHIFT
2016e4b17023SJohn Marino 		   && CONST_INT_P (XEXP (rhs, 1))
2017e4b17023SJohn Marino 		   && INTVAL (XEXP (rhs, 1)) >= 0
2018e4b17023SJohn Marino 		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
2019e4b17023SJohn Marino 	    {
2020e4b17023SJohn Marino 	      coeff1 = double_int_setbit (double_int_zero,
2021e4b17023SJohn Marino 					  INTVAL (XEXP (rhs, 1)));
2022e4b17023SJohn Marino 	      rhs = XEXP (rhs, 0);
2023e4b17023SJohn Marino 	    }
2024e4b17023SJohn Marino 
2025e4b17023SJohn Marino 	  if (rtx_equal_p (lhs, rhs))
2026e4b17023SJohn Marino 	    {
2027e4b17023SJohn Marino 	      rtx orig = gen_rtx_PLUS (mode, op0, op1);
2028e4b17023SJohn Marino 	      rtx coeff;
2029e4b17023SJohn Marino 	      double_int val;
2030e4b17023SJohn Marino 	      bool speed = optimize_function_for_speed_p (cfun);
2031e4b17023SJohn Marino 
2032e4b17023SJohn Marino 	      val = double_int_add (coeff0, coeff1);
2033e4b17023SJohn Marino 	      coeff = immed_double_int_const (val, mode);
2034e4b17023SJohn Marino 
2035e4b17023SJohn Marino 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
2036e4b17023SJohn Marino 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
2037e4b17023SJohn Marino 		? tem : 0;
2038e4b17023SJohn Marino 	    }
2039e4b17023SJohn Marino 	}
2040e4b17023SJohn Marino 
2041e4b17023SJohn Marino       /* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit.  */
2042e4b17023SJohn Marino       if ((CONST_INT_P (op1)
2043e4b17023SJohn Marino 	   || GET_CODE (op1) == CONST_DOUBLE)
2044e4b17023SJohn Marino 	  && GET_CODE (op0) == XOR
2045e4b17023SJohn Marino 	  && (CONST_INT_P (XEXP (op0, 1))
2046e4b17023SJohn Marino 	      || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)
2047e4b17023SJohn Marino 	  && mode_signbit_p (mode, op1))
2048e4b17023SJohn Marino 	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
2049e4b17023SJohn Marino 				    simplify_gen_binary (XOR, mode, op1,
2050e4b17023SJohn Marino 							 XEXP (op0, 1)));
2051e4b17023SJohn Marino 
2052e4b17023SJohn Marino       /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).  */
2053e4b17023SJohn Marino       if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode)
2054e4b17023SJohn Marino 	  && GET_CODE (op0) == MULT
2055e4b17023SJohn Marino 	  && GET_CODE (XEXP (op0, 0)) == NEG)
2056e4b17023SJohn Marino 	{
2057e4b17023SJohn Marino 	  rtx in1, in2;
2058e4b17023SJohn Marino 
2059e4b17023SJohn Marino 	  in1 = XEXP (XEXP (op0, 0), 0);
2060e4b17023SJohn Marino 	  in2 = XEXP (op0, 1);
2061e4b17023SJohn Marino 	  return simplify_gen_binary (MINUS, mode, op1,
2062e4b17023SJohn Marino 				      simplify_gen_binary (MULT, mode,
2063e4b17023SJohn Marino 							   in1, in2));
2064e4b17023SJohn Marino 	}
2065e4b17023SJohn Marino 
2066e4b17023SJohn Marino       /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
2067e4b17023SJohn Marino 	 C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
2068e4b17023SJohn Marino 	 is 1.  */
2069e4b17023SJohn Marino       if (COMPARISON_P (op0)
2070e4b17023SJohn Marino 	  && ((STORE_FLAG_VALUE == -1 && trueop1 == const1_rtx)
2071e4b17023SJohn Marino 	      || (STORE_FLAG_VALUE == 1 && trueop1 == constm1_rtx))
2072e4b17023SJohn Marino 	  && (reversed = reversed_comparison (op0, mode)))
2073e4b17023SJohn Marino 	return
2074e4b17023SJohn Marino 	  simplify_gen_unary (NEG, mode, reversed, mode);
2075e4b17023SJohn Marino 
2076e4b17023SJohn Marino       /* If one of the operands is a PLUS or a MINUS, see if we can
2077e4b17023SJohn Marino 	 simplify this by the associative law.
2078e4b17023SJohn Marino 	 Don't use the associative law for floating point.
2079e4b17023SJohn Marino 	 The inaccuracy makes it nonassociative,
2080e4b17023SJohn Marino 	 and subtle programs can break if operations are associated.  */
2081e4b17023SJohn Marino 
2082e4b17023SJohn Marino       if (INTEGRAL_MODE_P (mode)
2083e4b17023SJohn Marino 	  && (plus_minus_operand_p (op0)
2084e4b17023SJohn Marino 	      || plus_minus_operand_p (op1))
2085e4b17023SJohn Marino 	  && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
2086e4b17023SJohn Marino 	return tem;
2087e4b17023SJohn Marino 
2088e4b17023SJohn Marino       /* Reassociate floating point addition only when the user
2089e4b17023SJohn Marino 	 specifies associative math operations.  */
2090e4b17023SJohn Marino       if (FLOAT_MODE_P (mode)
2091e4b17023SJohn Marino 	  && flag_associative_math)
2092e4b17023SJohn Marino 	{
2093e4b17023SJohn Marino 	  tem = simplify_associative_operation (code, mode, op0, op1);
2094e4b17023SJohn Marino 	  if (tem)
2095e4b17023SJohn Marino 	    return tem;
2096e4b17023SJohn Marino 	}
2097e4b17023SJohn Marino       break;
2098e4b17023SJohn Marino 
2099e4b17023SJohn Marino     case COMPARE:
2100e4b17023SJohn Marino       /* Convert (compare (gt (flags) 0) (lt (flags) 0)) to (flags).  */
2101e4b17023SJohn Marino       if (((GET_CODE (op0) == GT && GET_CODE (op1) == LT)
2102e4b17023SJohn Marino 	   || (GET_CODE (op0) == GTU && GET_CODE (op1) == LTU))
2103e4b17023SJohn Marino 	  && XEXP (op0, 1) == const0_rtx && XEXP (op1, 1) == const0_rtx)
2104e4b17023SJohn Marino 	{
2105e4b17023SJohn Marino 	  rtx xop00 = XEXP (op0, 0);
2106e4b17023SJohn Marino 	  rtx xop10 = XEXP (op1, 0);
2107e4b17023SJohn Marino 
2108e4b17023SJohn Marino #ifdef HAVE_cc0
2109e4b17023SJohn Marino 	  if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
2110e4b17023SJohn Marino #else
2111e4b17023SJohn Marino 	    if (REG_P (xop00) && REG_P (xop10)
2112e4b17023SJohn Marino 		&& GET_MODE (xop00) == GET_MODE (xop10)
2113e4b17023SJohn Marino 		&& REGNO (xop00) == REGNO (xop10)
2114e4b17023SJohn Marino 		&& GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
2115e4b17023SJohn Marino 		&& GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
2116e4b17023SJohn Marino #endif
2117e4b17023SJohn Marino 	      return xop00;
2118e4b17023SJohn Marino 	}
2119e4b17023SJohn Marino       break;
2120e4b17023SJohn Marino 
2121e4b17023SJohn Marino     case MINUS:
2122e4b17023SJohn Marino       /* We can't assume x-x is 0 even with non-IEEE floating point,
2123e4b17023SJohn Marino 	 but since it is zero except in very strange circumstances, we
2124e4b17023SJohn Marino 	 will treat it as zero with -ffinite-math-only.  */
2125e4b17023SJohn Marino       if (rtx_equal_p (trueop0, trueop1)
2126e4b17023SJohn Marino 	  && ! side_effects_p (op0)
2127e4b17023SJohn Marino 	  && (!FLOAT_MODE_P (mode) || !HONOR_NANS (mode)))
2128e4b17023SJohn Marino 	return CONST0_RTX (mode);
2129e4b17023SJohn Marino 
2130e4b17023SJohn Marino       /* Change subtraction from zero into negation.  (0 - x) is the
2131e4b17023SJohn Marino 	 same as -x when x is NaN, infinite, or finite and nonzero.
2132e4b17023SJohn Marino 	 But if the mode has signed zeros, and does not round towards
2133e4b17023SJohn Marino 	 -infinity, then 0 - 0 is 0, not -0.  */
2134e4b17023SJohn Marino       if (!HONOR_SIGNED_ZEROS (mode) && trueop0 == CONST0_RTX (mode))
2135e4b17023SJohn Marino 	return simplify_gen_unary (NEG, mode, op1, mode);
2136e4b17023SJohn Marino 
2137e4b17023SJohn Marino       /* (-1 - a) is ~a.  */
2138e4b17023SJohn Marino       if (trueop0 == constm1_rtx)
2139e4b17023SJohn Marino 	return simplify_gen_unary (NOT, mode, op1, mode);
2140e4b17023SJohn Marino 
2141e4b17023SJohn Marino       /* Subtracting 0 has no effect unless the mode has signed zeros
2142e4b17023SJohn Marino 	 and supports rounding towards -infinity.  In such a case,
2143e4b17023SJohn Marino 	 0 - 0 is -0.  */
2144e4b17023SJohn Marino       if (!(HONOR_SIGNED_ZEROS (mode)
2145e4b17023SJohn Marino 	    && HONOR_SIGN_DEPENDENT_ROUNDING (mode))
2146e4b17023SJohn Marino 	  && trueop1 == CONST0_RTX (mode))
2147e4b17023SJohn Marino 	return op0;
2148e4b17023SJohn Marino 
2149e4b17023SJohn Marino       /* See if this is something like X * C - X or vice versa or
2150e4b17023SJohn Marino 	 if the multiplication is written as a shift.  If so, we can
2151e4b17023SJohn Marino 	 distribute and make a new multiply, shift, or maybe just
2152e4b17023SJohn Marino 	 have X (if C is 2 in the example above).  But don't make
2153e4b17023SJohn Marino 	 something more expensive than we had before.  */
2154e4b17023SJohn Marino 
2155e4b17023SJohn Marino       if (SCALAR_INT_MODE_P (mode))
2156e4b17023SJohn Marino 	{
2157e4b17023SJohn Marino 	  double_int coeff0, negcoeff1;
2158e4b17023SJohn Marino 	  rtx lhs = op0, rhs = op1;
2159e4b17023SJohn Marino 
2160e4b17023SJohn Marino 	  coeff0 = double_int_one;
2161e4b17023SJohn Marino 	  negcoeff1 = double_int_minus_one;
2162e4b17023SJohn Marino 
2163e4b17023SJohn Marino 	  if (GET_CODE (lhs) == NEG)
2164e4b17023SJohn Marino 	    {
2165e4b17023SJohn Marino 	      coeff0 = double_int_minus_one;
2166e4b17023SJohn Marino 	      lhs = XEXP (lhs, 0);
2167e4b17023SJohn Marino 	    }
2168e4b17023SJohn Marino 	  else if (GET_CODE (lhs) == MULT
2169e4b17023SJohn Marino 		   && CONST_INT_P (XEXP (lhs, 1)))
2170e4b17023SJohn Marino 	    {
2171e4b17023SJohn Marino 	      coeff0 = shwi_to_double_int (INTVAL (XEXP (lhs, 1)));
2172e4b17023SJohn Marino 	      lhs = XEXP (lhs, 0);
2173e4b17023SJohn Marino 	    }
2174e4b17023SJohn Marino 	  else if (GET_CODE (lhs) == ASHIFT
2175e4b17023SJohn Marino 		   && CONST_INT_P (XEXP (lhs, 1))
2176e4b17023SJohn Marino 		   && INTVAL (XEXP (lhs, 1)) >= 0
2177e4b17023SJohn Marino 		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
2178e4b17023SJohn Marino 	    {
2179e4b17023SJohn Marino 	      coeff0 = double_int_setbit (double_int_zero,
2180e4b17023SJohn Marino 					  INTVAL (XEXP (lhs, 1)));
2181e4b17023SJohn Marino 	      lhs = XEXP (lhs, 0);
2182e4b17023SJohn Marino 	    }
2183e4b17023SJohn Marino 
2184e4b17023SJohn Marino 	  if (GET_CODE (rhs) == NEG)
2185e4b17023SJohn Marino 	    {
2186e4b17023SJohn Marino 	      negcoeff1 = double_int_one;
2187e4b17023SJohn Marino 	      rhs = XEXP (rhs, 0);
2188e4b17023SJohn Marino 	    }
2189e4b17023SJohn Marino 	  else if (GET_CODE (rhs) == MULT
2190e4b17023SJohn Marino 		   && CONST_INT_P (XEXP (rhs, 1)))
2191e4b17023SJohn Marino 	    {
2192e4b17023SJohn Marino 	      negcoeff1 = shwi_to_double_int (-INTVAL (XEXP (rhs, 1)));
2193e4b17023SJohn Marino 	      rhs = XEXP (rhs, 0);
2194e4b17023SJohn Marino 	    }
2195e4b17023SJohn Marino 	  else if (GET_CODE (rhs) == ASHIFT
2196e4b17023SJohn Marino 		   && CONST_INT_P (XEXP (rhs, 1))
2197e4b17023SJohn Marino 		   && INTVAL (XEXP (rhs, 1)) >= 0
2198e4b17023SJohn Marino 		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
2199e4b17023SJohn Marino 	    {
2200e4b17023SJohn Marino 	      negcoeff1 = double_int_setbit (double_int_zero,
2201e4b17023SJohn Marino 					     INTVAL (XEXP (rhs, 1)));
2202e4b17023SJohn Marino 	      negcoeff1 = double_int_neg (negcoeff1);
2203e4b17023SJohn Marino 	      rhs = XEXP (rhs, 0);
2204e4b17023SJohn Marino 	    }
2205e4b17023SJohn Marino 
2206e4b17023SJohn Marino 	  if (rtx_equal_p (lhs, rhs))
2207e4b17023SJohn Marino 	    {
2208e4b17023SJohn Marino 	      rtx orig = gen_rtx_MINUS (mode, op0, op1);
2209e4b17023SJohn Marino 	      rtx coeff;
2210e4b17023SJohn Marino 	      double_int val;
2211e4b17023SJohn Marino 	      bool speed = optimize_function_for_speed_p (cfun);
2212e4b17023SJohn Marino 
2213e4b17023SJohn Marino 	      val = double_int_add (coeff0, negcoeff1);
2214e4b17023SJohn Marino 	      coeff = immed_double_int_const (val, mode);
2215e4b17023SJohn Marino 
2216e4b17023SJohn Marino 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
2217e4b17023SJohn Marino 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
2218e4b17023SJohn Marino 		? tem : 0;
2219e4b17023SJohn Marino 	    }
2220e4b17023SJohn Marino 	}
2221e4b17023SJohn Marino 
2222e4b17023SJohn Marino       /* (a - (-b)) -> (a + b).  True even for IEEE.  */
2223e4b17023SJohn Marino       if (GET_CODE (op1) == NEG)
2224e4b17023SJohn Marino 	return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
2225e4b17023SJohn Marino 
2226e4b17023SJohn Marino       /* (-x - c) may be simplified as (-c - x).  */
2227e4b17023SJohn Marino       if (GET_CODE (op0) == NEG
2228e4b17023SJohn Marino 	  && (CONST_INT_P (op1)
2229e4b17023SJohn Marino 	      || GET_CODE (op1) == CONST_DOUBLE))
2230e4b17023SJohn Marino 	{
2231e4b17023SJohn Marino 	  tem = simplify_unary_operation (NEG, mode, op1, mode);
2232e4b17023SJohn Marino 	  if (tem)
2233e4b17023SJohn Marino 	    return simplify_gen_binary (MINUS, mode, tem, XEXP (op0, 0));
2234e4b17023SJohn Marino 	}
2235e4b17023SJohn Marino 
2236e4b17023SJohn Marino       /* Don't let a relocatable value get a negative coeff.  */
2237e4b17023SJohn Marino       if (CONST_INT_P (op1) && GET_MODE (op0) != VOIDmode)
2238e4b17023SJohn Marino 	return simplify_gen_binary (PLUS, mode,
2239e4b17023SJohn Marino 				    op0,
2240e4b17023SJohn Marino 				    neg_const_int (mode, op1));
2241e4b17023SJohn Marino 
2242e4b17023SJohn Marino       /* (x - (x & y)) -> (x & ~y) */
22435ce9237cSJohn Marino       if (INTEGRAL_MODE_P (mode) && GET_CODE (op1) == AND)
2244e4b17023SJohn Marino 	{
2245e4b17023SJohn Marino 	  if (rtx_equal_p (op0, XEXP (op1, 0)))
2246e4b17023SJohn Marino 	    {
2247e4b17023SJohn Marino 	      tem = simplify_gen_unary (NOT, mode, XEXP (op1, 1),
2248e4b17023SJohn Marino 					GET_MODE (XEXP (op1, 1)));
2249e4b17023SJohn Marino 	      return simplify_gen_binary (AND, mode, op0, tem);
2250e4b17023SJohn Marino 	    }
2251e4b17023SJohn Marino 	  if (rtx_equal_p (op0, XEXP (op1, 1)))
2252e4b17023SJohn Marino 	    {
2253e4b17023SJohn Marino 	      tem = simplify_gen_unary (NOT, mode, XEXP (op1, 0),
2254e4b17023SJohn Marino 					GET_MODE (XEXP (op1, 0)));
2255e4b17023SJohn Marino 	      return simplify_gen_binary (AND, mode, op0, tem);
2256e4b17023SJohn Marino 	    }
2257e4b17023SJohn Marino 	}
2258e4b17023SJohn Marino 
2259e4b17023SJohn Marino       /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
2260e4b17023SJohn Marino 	 by reversing the comparison code if valid.  */
2261e4b17023SJohn Marino       if (STORE_FLAG_VALUE == 1
2262e4b17023SJohn Marino 	  && trueop0 == const1_rtx
2263e4b17023SJohn Marino 	  && COMPARISON_P (op1)
2264e4b17023SJohn Marino 	  && (reversed = reversed_comparison (op1, mode)))
2265e4b17023SJohn Marino 	return reversed;
2266e4b17023SJohn Marino 
2267e4b17023SJohn Marino       /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).  */
2268e4b17023SJohn Marino       if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode)
2269e4b17023SJohn Marino 	  && GET_CODE (op1) == MULT
2270e4b17023SJohn Marino 	  && GET_CODE (XEXP (op1, 0)) == NEG)
2271e4b17023SJohn Marino 	{
2272e4b17023SJohn Marino 	  rtx in1, in2;
2273e4b17023SJohn Marino 
2274e4b17023SJohn Marino 	  in1 = XEXP (XEXP (op1, 0), 0);
2275e4b17023SJohn Marino 	  in2 = XEXP (op1, 1);
2276e4b17023SJohn Marino 	  return simplify_gen_binary (PLUS, mode,
2277e4b17023SJohn Marino 				      simplify_gen_binary (MULT, mode,
2278e4b17023SJohn Marino 							   in1, in2),
2279e4b17023SJohn Marino 				      op0);
2280e4b17023SJohn Marino 	}
2281e4b17023SJohn Marino 
2282e4b17023SJohn Marino       /* Canonicalize (minus (neg A) (mult B C)) to
2283e4b17023SJohn Marino 	 (minus (mult (neg B) C) A).  */
2284e4b17023SJohn Marino       if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode)
2285e4b17023SJohn Marino 	  && GET_CODE (op1) == MULT
2286e4b17023SJohn Marino 	  && GET_CODE (op0) == NEG)
2287e4b17023SJohn Marino 	{
2288e4b17023SJohn Marino 	  rtx in1, in2;
2289e4b17023SJohn Marino 
2290e4b17023SJohn Marino 	  in1 = simplify_gen_unary (NEG, mode, XEXP (op1, 0), mode);
2291e4b17023SJohn Marino 	  in2 = XEXP (op1, 1);
2292e4b17023SJohn Marino 	  return simplify_gen_binary (MINUS, mode,
2293e4b17023SJohn Marino 				      simplify_gen_binary (MULT, mode,
2294e4b17023SJohn Marino 							   in1, in2),
2295e4b17023SJohn Marino 				      XEXP (op0, 0));
2296e4b17023SJohn Marino 	}
2297e4b17023SJohn Marino 
2298e4b17023SJohn Marino       /* If one of the operands is a PLUS or a MINUS, see if we can
2299e4b17023SJohn Marino 	 simplify this by the associative law.  This will, for example,
2300e4b17023SJohn Marino          canonicalize (minus A (plus B C)) to (minus (minus A B) C).
2301e4b17023SJohn Marino 	 Don't use the associative law for floating point.
2302e4b17023SJohn Marino 	 The inaccuracy makes it nonassociative,
2303e4b17023SJohn Marino 	 and subtle programs can break if operations are associated.  */
2304e4b17023SJohn Marino 
2305e4b17023SJohn Marino       if (INTEGRAL_MODE_P (mode)
2306e4b17023SJohn Marino 	  && (plus_minus_operand_p (op0)
2307e4b17023SJohn Marino 	      || plus_minus_operand_p (op1))
2308e4b17023SJohn Marino 	  && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
2309e4b17023SJohn Marino 	return tem;
2310e4b17023SJohn Marino       break;
2311e4b17023SJohn Marino 
2312e4b17023SJohn Marino     case MULT:
2313e4b17023SJohn Marino       if (trueop1 == constm1_rtx)
2314e4b17023SJohn Marino 	return simplify_gen_unary (NEG, mode, op0, mode);
2315e4b17023SJohn Marino 
2316e4b17023SJohn Marino       if (GET_CODE (op0) == NEG)
2317e4b17023SJohn Marino 	{
2318e4b17023SJohn Marino 	  rtx temp = simplify_unary_operation (NEG, mode, op1, mode);
2319e4b17023SJohn Marino 	  /* If op1 is a MULT as well and simplify_unary_operation
2320e4b17023SJohn Marino 	     just moved the NEG to the second operand, simplify_gen_binary
2321e4b17023SJohn Marino 	     below could through simplify_associative_operation move
2322e4b17023SJohn Marino 	     the NEG around again and recurse endlessly.  */
2323e4b17023SJohn Marino 	  if (temp
2324e4b17023SJohn Marino 	      && GET_CODE (op1) == MULT
2325e4b17023SJohn Marino 	      && GET_CODE (temp) == MULT
2326e4b17023SJohn Marino 	      && XEXP (op1, 0) == XEXP (temp, 0)
2327e4b17023SJohn Marino 	      && GET_CODE (XEXP (temp, 1)) == NEG
2328e4b17023SJohn Marino 	      && XEXP (op1, 1) == XEXP (XEXP (temp, 1), 0))
2329e4b17023SJohn Marino 	    temp = NULL_RTX;
2330e4b17023SJohn Marino 	  if (temp)
2331e4b17023SJohn Marino 	    return simplify_gen_binary (MULT, mode, XEXP (op0, 0), temp);
2332e4b17023SJohn Marino 	}
2333e4b17023SJohn Marino       if (GET_CODE (op1) == NEG)
2334e4b17023SJohn Marino 	{
2335e4b17023SJohn Marino 	  rtx temp = simplify_unary_operation (NEG, mode, op0, mode);
2336e4b17023SJohn Marino 	  /* If op0 is a MULT as well and simplify_unary_operation
2337e4b17023SJohn Marino 	     just moved the NEG to the second operand, simplify_gen_binary
2338e4b17023SJohn Marino 	     below could through simplify_associative_operation move
2339e4b17023SJohn Marino 	     the NEG around again and recurse endlessly.  */
2340e4b17023SJohn Marino 	  if (temp
2341e4b17023SJohn Marino 	      && GET_CODE (op0) == MULT
2342e4b17023SJohn Marino 	      && GET_CODE (temp) == MULT
2343e4b17023SJohn Marino 	      && XEXP (op0, 0) == XEXP (temp, 0)
2344e4b17023SJohn Marino 	      && GET_CODE (XEXP (temp, 1)) == NEG
2345e4b17023SJohn Marino 	      && XEXP (op0, 1) == XEXP (XEXP (temp, 1), 0))
2346e4b17023SJohn Marino 	    temp = NULL_RTX;
2347e4b17023SJohn Marino 	  if (temp)
2348e4b17023SJohn Marino 	    return simplify_gen_binary (MULT, mode, temp, XEXP (op1, 0));
2349e4b17023SJohn Marino 	}
2350e4b17023SJohn Marino 
2351e4b17023SJohn Marino       /* Maybe simplify x * 0 to 0.  The reduction is not valid if
2352e4b17023SJohn Marino 	 x is NaN, since x * 0 is then also NaN.  Nor is it valid
2353e4b17023SJohn Marino 	 when the mode has signed zeros, since multiplying a negative
2354e4b17023SJohn Marino 	 number by 0 will give -0, not 0.  */
2355e4b17023SJohn Marino       if (!HONOR_NANS (mode)
2356e4b17023SJohn Marino 	  && !HONOR_SIGNED_ZEROS (mode)
2357e4b17023SJohn Marino 	  && trueop1 == CONST0_RTX (mode)
2358e4b17023SJohn Marino 	  && ! side_effects_p (op0))
2359e4b17023SJohn Marino 	return op1;
2360e4b17023SJohn Marino 
2361e4b17023SJohn Marino       /* In IEEE floating point, x*1 is not equivalent to x for
2362e4b17023SJohn Marino 	 signalling NaNs.  */
2363e4b17023SJohn Marino       if (!HONOR_SNANS (mode)
2364e4b17023SJohn Marino 	  && trueop1 == CONST1_RTX (mode))
2365e4b17023SJohn Marino 	return op0;
2366e4b17023SJohn Marino 
2367e4b17023SJohn Marino       /* Convert multiply by constant power of two into shift unless
2368e4b17023SJohn Marino 	 we are still generating RTL.  This test is a kludge.  */
2369e4b17023SJohn Marino       if (CONST_INT_P (trueop1)
2370e4b17023SJohn Marino 	  && (val = exact_log2 (UINTVAL (trueop1))) >= 0
2371e4b17023SJohn Marino 	  /* If the mode is larger than the host word size, and the
2372e4b17023SJohn Marino 	     uppermost bit is set, then this isn't a power of two due
2373e4b17023SJohn Marino 	     to implicit sign extension.  */
2374e4b17023SJohn Marino 	  && (width <= HOST_BITS_PER_WIDE_INT
2375e4b17023SJohn Marino 	      || val != HOST_BITS_PER_WIDE_INT - 1))
2376e4b17023SJohn Marino 	return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
2377e4b17023SJohn Marino 
2378e4b17023SJohn Marino       /* Likewise for multipliers wider than a word.  */
2379e4b17023SJohn Marino       if (GET_CODE (trueop1) == CONST_DOUBLE
2380e4b17023SJohn Marino 	  && (GET_MODE (trueop1) == VOIDmode
2381e4b17023SJohn Marino 	      || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
2382e4b17023SJohn Marino 	  && GET_MODE (op0) == mode
2383e4b17023SJohn Marino 	  && CONST_DOUBLE_LOW (trueop1) == 0
2384e4b17023SJohn Marino 	  && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
2385e4b17023SJohn Marino 	return simplify_gen_binary (ASHIFT, mode, op0,
2386e4b17023SJohn Marino 				    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
2387e4b17023SJohn Marino 
2388e4b17023SJohn Marino       /* x*2 is x+x and x*(-1) is -x */
2389e4b17023SJohn Marino       if (GET_CODE (trueop1) == CONST_DOUBLE
2390e4b17023SJohn Marino 	  && SCALAR_FLOAT_MODE_P (GET_MODE (trueop1))
2391e4b17023SJohn Marino 	  && !DECIMAL_FLOAT_MODE_P (GET_MODE (trueop1))
2392e4b17023SJohn Marino 	  && GET_MODE (op0) == mode)
2393e4b17023SJohn Marino 	{
2394e4b17023SJohn Marino 	  REAL_VALUE_TYPE d;
2395e4b17023SJohn Marino 	  REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
2396e4b17023SJohn Marino 
2397e4b17023SJohn Marino 	  if (REAL_VALUES_EQUAL (d, dconst2))
2398e4b17023SJohn Marino 	    return simplify_gen_binary (PLUS, mode, op0, copy_rtx (op0));
2399e4b17023SJohn Marino 
2400e4b17023SJohn Marino 	  if (!HONOR_SNANS (mode)
2401e4b17023SJohn Marino 	      && REAL_VALUES_EQUAL (d, dconstm1))
2402e4b17023SJohn Marino 	    return simplify_gen_unary (NEG, mode, op0, mode);
2403e4b17023SJohn Marino 	}
2404e4b17023SJohn Marino 
2405e4b17023SJohn Marino       /* Optimize -x * -x as x * x.  */
2406e4b17023SJohn Marino       if (FLOAT_MODE_P (mode)
2407e4b17023SJohn Marino 	  && GET_CODE (op0) == NEG
2408e4b17023SJohn Marino 	  && GET_CODE (op1) == NEG
2409e4b17023SJohn Marino 	  && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
2410e4b17023SJohn Marino 	  && !side_effects_p (XEXP (op0, 0)))
2411e4b17023SJohn Marino 	return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0));
2412e4b17023SJohn Marino 
2413e4b17023SJohn Marino       /* Likewise, optimize abs(x) * abs(x) as x * x.  */
2414e4b17023SJohn Marino       if (SCALAR_FLOAT_MODE_P (mode)
2415e4b17023SJohn Marino 	  && GET_CODE (op0) == ABS
2416e4b17023SJohn Marino 	  && GET_CODE (op1) == ABS
2417e4b17023SJohn Marino 	  && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
2418e4b17023SJohn Marino 	  && !side_effects_p (XEXP (op0, 0)))
2419e4b17023SJohn Marino 	return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0));
2420e4b17023SJohn Marino 
2421e4b17023SJohn Marino       /* Reassociate multiplication, but for floating point MULTs
2422e4b17023SJohn Marino 	 only when the user specifies unsafe math optimizations.  */
2423e4b17023SJohn Marino       if (! FLOAT_MODE_P (mode)
2424e4b17023SJohn Marino 	  || flag_unsafe_math_optimizations)
2425e4b17023SJohn Marino 	{
2426e4b17023SJohn Marino 	  tem = simplify_associative_operation (code, mode, op0, op1);
2427e4b17023SJohn Marino 	  if (tem)
2428e4b17023SJohn Marino 	    return tem;
2429e4b17023SJohn Marino 	}
2430e4b17023SJohn Marino       break;
2431e4b17023SJohn Marino 
2432e4b17023SJohn Marino     case IOR:
2433e4b17023SJohn Marino       if (trueop1 == CONST0_RTX (mode))
2434e4b17023SJohn Marino 	return op0;
2435e4b17023SJohn Marino       if (INTEGRAL_MODE_P (mode) && trueop1 == CONSTM1_RTX (mode))
2436e4b17023SJohn Marino 	return op1;
2437e4b17023SJohn Marino       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
2438e4b17023SJohn Marino 	return op0;
2439e4b17023SJohn Marino       /* A | (~A) -> -1 */
2440e4b17023SJohn Marino       if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
2441e4b17023SJohn Marino 	   || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
2442e4b17023SJohn Marino 	  && ! side_effects_p (op0)
2443e4b17023SJohn Marino 	  && SCALAR_INT_MODE_P (mode))
2444e4b17023SJohn Marino 	return constm1_rtx;
2445e4b17023SJohn Marino 
2446e4b17023SJohn Marino       /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
2447e4b17023SJohn Marino       if (CONST_INT_P (op1)
2448e4b17023SJohn Marino 	  && HWI_COMPUTABLE_MODE_P (mode)
2449e4b17023SJohn Marino 	  && (nonzero_bits (op0, mode) & ~UINTVAL (op1)) == 0)
2450e4b17023SJohn Marino 	return op1;
2451e4b17023SJohn Marino 
2452e4b17023SJohn Marino       /* Canonicalize (X & C1) | C2.  */
2453e4b17023SJohn Marino       if (GET_CODE (op0) == AND
2454e4b17023SJohn Marino 	  && CONST_INT_P (trueop1)
2455e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op0, 1)))
2456e4b17023SJohn Marino 	{
2457e4b17023SJohn Marino 	  HOST_WIDE_INT mask = GET_MODE_MASK (mode);
2458e4b17023SJohn Marino 	  HOST_WIDE_INT c1 = INTVAL (XEXP (op0, 1));
2459e4b17023SJohn Marino 	  HOST_WIDE_INT c2 = INTVAL (trueop1);
2460e4b17023SJohn Marino 
2461e4b17023SJohn Marino 	  /* If (C1&C2) == C1, then (X&C1)|C2 becomes X.  */
2462e4b17023SJohn Marino 	  if ((c1 & c2) == c1
2463e4b17023SJohn Marino 	      && !side_effects_p (XEXP (op0, 0)))
2464e4b17023SJohn Marino 	    return trueop1;
2465e4b17023SJohn Marino 
2466e4b17023SJohn Marino 	  /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2.  */
2467e4b17023SJohn Marino 	  if (((c1|c2) & mask) == mask)
2468e4b17023SJohn Marino 	    return simplify_gen_binary (IOR, mode, XEXP (op0, 0), op1);
2469e4b17023SJohn Marino 
2470e4b17023SJohn Marino 	  /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2.  */
2471e4b17023SJohn Marino 	  if (((c1 & ~c2) & mask) != (c1 & mask))
2472e4b17023SJohn Marino 	    {
2473e4b17023SJohn Marino 	      tem = simplify_gen_binary (AND, mode, XEXP (op0, 0),
2474e4b17023SJohn Marino 					 gen_int_mode (c1 & ~c2, mode));
2475e4b17023SJohn Marino 	      return simplify_gen_binary (IOR, mode, tem, op1);
2476e4b17023SJohn Marino 	    }
2477e4b17023SJohn Marino 	}
2478e4b17023SJohn Marino 
2479e4b17023SJohn Marino       /* Convert (A & B) | A to A.  */
2480e4b17023SJohn Marino       if (GET_CODE (op0) == AND
2481e4b17023SJohn Marino 	  && (rtx_equal_p (XEXP (op0, 0), op1)
2482e4b17023SJohn Marino 	      || rtx_equal_p (XEXP (op0, 1), op1))
2483e4b17023SJohn Marino 	  && ! side_effects_p (XEXP (op0, 0))
2484e4b17023SJohn Marino 	  && ! side_effects_p (XEXP (op0, 1)))
2485e4b17023SJohn Marino 	return op1;
2486e4b17023SJohn Marino 
2487e4b17023SJohn Marino       /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
2488e4b17023SJohn Marino          mode size to (rotate A CX).  */
2489e4b17023SJohn Marino 
2490e4b17023SJohn Marino       if (GET_CODE (op1) == ASHIFT
2491e4b17023SJohn Marino           || GET_CODE (op1) == SUBREG)
2492e4b17023SJohn Marino         {
2493e4b17023SJohn Marino 	  opleft = op1;
2494e4b17023SJohn Marino 	  opright = op0;
2495e4b17023SJohn Marino 	}
2496e4b17023SJohn Marino       else
2497e4b17023SJohn Marino         {
2498e4b17023SJohn Marino 	  opright = op1;
2499e4b17023SJohn Marino 	  opleft = op0;
2500e4b17023SJohn Marino 	}
2501e4b17023SJohn Marino 
2502e4b17023SJohn Marino       if (GET_CODE (opleft) == ASHIFT && GET_CODE (opright) == LSHIFTRT
2503e4b17023SJohn Marino           && rtx_equal_p (XEXP (opleft, 0), XEXP (opright, 0))
2504e4b17023SJohn Marino           && CONST_INT_P (XEXP (opleft, 1))
2505e4b17023SJohn Marino           && CONST_INT_P (XEXP (opright, 1))
2506e4b17023SJohn Marino           && (INTVAL (XEXP (opleft, 1)) + INTVAL (XEXP (opright, 1))
2507e4b17023SJohn Marino               == GET_MODE_PRECISION (mode)))
2508e4b17023SJohn Marino         return gen_rtx_ROTATE (mode, XEXP (opright, 0), XEXP (opleft, 1));
2509e4b17023SJohn Marino 
2510e4b17023SJohn Marino       /* Same, but for ashift that has been "simplified" to a wider mode
2511e4b17023SJohn Marino         by simplify_shift_const.  */
2512e4b17023SJohn Marino 
2513e4b17023SJohn Marino       if (GET_CODE (opleft) == SUBREG
2514e4b17023SJohn Marino           && GET_CODE (SUBREG_REG (opleft)) == ASHIFT
2515e4b17023SJohn Marino           && GET_CODE (opright) == LSHIFTRT
2516e4b17023SJohn Marino           && GET_CODE (XEXP (opright, 0)) == SUBREG
2517e4b17023SJohn Marino           && GET_MODE (opleft) == GET_MODE (XEXP (opright, 0))
2518e4b17023SJohn Marino           && SUBREG_BYTE (opleft) == SUBREG_BYTE (XEXP (opright, 0))
2519e4b17023SJohn Marino           && (GET_MODE_SIZE (GET_MODE (opleft))
2520e4b17023SJohn Marino               < GET_MODE_SIZE (GET_MODE (SUBREG_REG (opleft))))
2521e4b17023SJohn Marino           && rtx_equal_p (XEXP (SUBREG_REG (opleft), 0),
2522e4b17023SJohn Marino                           SUBREG_REG (XEXP (opright, 0)))
2523e4b17023SJohn Marino           && CONST_INT_P (XEXP (SUBREG_REG (opleft), 1))
2524e4b17023SJohn Marino           && CONST_INT_P (XEXP (opright, 1))
2525e4b17023SJohn Marino           && (INTVAL (XEXP (SUBREG_REG (opleft), 1)) + INTVAL (XEXP (opright, 1))
2526e4b17023SJohn Marino               == GET_MODE_PRECISION (mode)))
2527e4b17023SJohn Marino         return gen_rtx_ROTATE (mode, XEXP (opright, 0),
2528e4b17023SJohn Marino                                XEXP (SUBREG_REG (opleft), 1));
2529e4b17023SJohn Marino 
2530e4b17023SJohn Marino       /* If we have (ior (and (X C1) C2)), simplify this by making
2531e4b17023SJohn Marino 	 C1 as small as possible if C1 actually changes.  */
2532e4b17023SJohn Marino       if (CONST_INT_P (op1)
2533e4b17023SJohn Marino 	  && (HWI_COMPUTABLE_MODE_P (mode)
2534e4b17023SJohn Marino 	      || INTVAL (op1) > 0)
2535e4b17023SJohn Marino 	  && GET_CODE (op0) == AND
2536e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op0, 1))
2537e4b17023SJohn Marino 	  && CONST_INT_P (op1)
2538e4b17023SJohn Marino 	  && (UINTVAL (XEXP (op0, 1)) & UINTVAL (op1)) != 0)
2539e4b17023SJohn Marino 	return simplify_gen_binary (IOR, mode,
2540e4b17023SJohn Marino 				    simplify_gen_binary
2541e4b17023SJohn Marino 					  (AND, mode, XEXP (op0, 0),
2542e4b17023SJohn Marino 					   GEN_INT (UINTVAL (XEXP (op0, 1))
2543e4b17023SJohn Marino 						    & ~UINTVAL (op1))),
2544e4b17023SJohn Marino 				    op1);
2545e4b17023SJohn Marino 
2546e4b17023SJohn Marino       /* If OP0 is (ashiftrt (plus ...) C), it might actually be
2547e4b17023SJohn Marino          a (sign_extend (plus ...)).  Then check if OP1 is a CONST_INT and
2548e4b17023SJohn Marino 	 the PLUS does not affect any of the bits in OP1: then we can do
2549e4b17023SJohn Marino 	 the IOR as a PLUS and we can associate.  This is valid if OP1
2550e4b17023SJohn Marino          can be safely shifted left C bits.  */
2551e4b17023SJohn Marino       if (CONST_INT_P (trueop1) && GET_CODE (op0) == ASHIFTRT
2552e4b17023SJohn Marino           && GET_CODE (XEXP (op0, 0)) == PLUS
2553e4b17023SJohn Marino           && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
2554e4b17023SJohn Marino           && CONST_INT_P (XEXP (op0, 1))
2555e4b17023SJohn Marino           && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT)
2556e4b17023SJohn Marino         {
2557e4b17023SJohn Marino           int count = INTVAL (XEXP (op0, 1));
2558e4b17023SJohn Marino           HOST_WIDE_INT mask = INTVAL (trueop1) << count;
2559e4b17023SJohn Marino 
2560e4b17023SJohn Marino           if (mask >> count == INTVAL (trueop1)
2561*95d28233SJohn Marino 	      && trunc_int_for_mode (mask, mode) == mask
2562e4b17023SJohn Marino               && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
2563e4b17023SJohn Marino 	    return simplify_gen_binary (ASHIFTRT, mode,
2564e4b17023SJohn Marino 					plus_constant (XEXP (op0, 0), mask),
2565e4b17023SJohn Marino 					XEXP (op0, 1));
2566e4b17023SJohn Marino         }
2567e4b17023SJohn Marino 
2568e4b17023SJohn Marino       tem = simplify_associative_operation (code, mode, op0, op1);
2569e4b17023SJohn Marino       if (tem)
2570e4b17023SJohn Marino 	return tem;
2571e4b17023SJohn Marino       break;
2572e4b17023SJohn Marino 
2573e4b17023SJohn Marino     case XOR:
2574e4b17023SJohn Marino       if (trueop1 == CONST0_RTX (mode))
2575e4b17023SJohn Marino 	return op0;
2576e4b17023SJohn Marino       if (INTEGRAL_MODE_P (mode) && trueop1 == CONSTM1_RTX (mode))
2577e4b17023SJohn Marino 	return simplify_gen_unary (NOT, mode, op0, mode);
2578e4b17023SJohn Marino       if (rtx_equal_p (trueop0, trueop1)
2579e4b17023SJohn Marino 	  && ! side_effects_p (op0)
2580e4b17023SJohn Marino 	  && GET_MODE_CLASS (mode) != MODE_CC)
2581e4b17023SJohn Marino 	 return CONST0_RTX (mode);
2582e4b17023SJohn Marino 
2583e4b17023SJohn Marino       /* Canonicalize XOR of the most significant bit to PLUS.  */
2584e4b17023SJohn Marino       if ((CONST_INT_P (op1)
2585e4b17023SJohn Marino 	   || GET_CODE (op1) == CONST_DOUBLE)
2586e4b17023SJohn Marino 	  && mode_signbit_p (mode, op1))
2587e4b17023SJohn Marino 	return simplify_gen_binary (PLUS, mode, op0, op1);
2588e4b17023SJohn Marino       /* (xor (plus X C1) C2) is (xor X (C1^C2)) if C1 is signbit.  */
2589e4b17023SJohn Marino       if ((CONST_INT_P (op1)
2590e4b17023SJohn Marino 	   || GET_CODE (op1) == CONST_DOUBLE)
2591e4b17023SJohn Marino 	  && GET_CODE (op0) == PLUS
2592e4b17023SJohn Marino 	  && (CONST_INT_P (XEXP (op0, 1))
2593e4b17023SJohn Marino 	      || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)
2594e4b17023SJohn Marino 	  && mode_signbit_p (mode, XEXP (op0, 1)))
2595e4b17023SJohn Marino 	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
2596e4b17023SJohn Marino 				    simplify_gen_binary (XOR, mode, op1,
2597e4b17023SJohn Marino 							 XEXP (op0, 1)));
2598e4b17023SJohn Marino 
2599e4b17023SJohn Marino       /* If we are XORing two things that have no bits in common,
2600e4b17023SJohn Marino 	 convert them into an IOR.  This helps to detect rotation encoded
2601e4b17023SJohn Marino 	 using those methods and possibly other simplifications.  */
2602e4b17023SJohn Marino 
2603e4b17023SJohn Marino       if (HWI_COMPUTABLE_MODE_P (mode)
2604e4b17023SJohn Marino 	  && (nonzero_bits (op0, mode)
2605e4b17023SJohn Marino 	      & nonzero_bits (op1, mode)) == 0)
2606e4b17023SJohn Marino 	return (simplify_gen_binary (IOR, mode, op0, op1));
2607e4b17023SJohn Marino 
2608e4b17023SJohn Marino       /* Convert (XOR (NOT x) (NOT y)) to (XOR x y).
2609e4b17023SJohn Marino 	 Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for
2610e4b17023SJohn Marino 	 (NOT y).  */
2611e4b17023SJohn Marino       {
2612e4b17023SJohn Marino 	int num_negated = 0;
2613e4b17023SJohn Marino 
2614e4b17023SJohn Marino 	if (GET_CODE (op0) == NOT)
2615e4b17023SJohn Marino 	  num_negated++, op0 = XEXP (op0, 0);
2616e4b17023SJohn Marino 	if (GET_CODE (op1) == NOT)
2617e4b17023SJohn Marino 	  num_negated++, op1 = XEXP (op1, 0);
2618e4b17023SJohn Marino 
2619e4b17023SJohn Marino 	if (num_negated == 2)
2620e4b17023SJohn Marino 	  return simplify_gen_binary (XOR, mode, op0, op1);
2621e4b17023SJohn Marino 	else if (num_negated == 1)
2622e4b17023SJohn Marino 	  return simplify_gen_unary (NOT, mode,
2623e4b17023SJohn Marino 				     simplify_gen_binary (XOR, mode, op0, op1),
2624e4b17023SJohn Marino 				     mode);
2625e4b17023SJohn Marino       }
2626e4b17023SJohn Marino 
2627e4b17023SJohn Marino       /* Convert (xor (and A B) B) to (and (not A) B).  The latter may
2628e4b17023SJohn Marino 	 correspond to a machine insn or result in further simplifications
2629e4b17023SJohn Marino 	 if B is a constant.  */
2630e4b17023SJohn Marino 
2631e4b17023SJohn Marino       if (GET_CODE (op0) == AND
2632e4b17023SJohn Marino 	  && rtx_equal_p (XEXP (op0, 1), op1)
2633e4b17023SJohn Marino 	  && ! side_effects_p (op1))
2634e4b17023SJohn Marino 	return simplify_gen_binary (AND, mode,
2635e4b17023SJohn Marino 				    simplify_gen_unary (NOT, mode,
2636e4b17023SJohn Marino 							XEXP (op0, 0), mode),
2637e4b17023SJohn Marino 				    op1);
2638e4b17023SJohn Marino 
2639e4b17023SJohn Marino       else if (GET_CODE (op0) == AND
2640e4b17023SJohn Marino 	       && rtx_equal_p (XEXP (op0, 0), op1)
2641e4b17023SJohn Marino 	       && ! side_effects_p (op1))
2642e4b17023SJohn Marino 	return simplify_gen_binary (AND, mode,
2643e4b17023SJohn Marino 				    simplify_gen_unary (NOT, mode,
2644e4b17023SJohn Marino 							XEXP (op0, 1), mode),
2645e4b17023SJohn Marino 				    op1);
2646e4b17023SJohn Marino 
2647e4b17023SJohn Marino       /* Given (xor (and A B) C), using P^Q == (~P&Q) | (~Q&P),
2648e4b17023SJohn Marino 	 we can transform like this:
2649e4b17023SJohn Marino             (A&B)^C == ~(A&B)&C | ~C&(A&B)
2650e4b17023SJohn Marino                     == (~A|~B)&C | ~C&(A&B)    * DeMorgan's Law
2651e4b17023SJohn Marino                     == ~A&C | ~B&C | A&(~C&B)  * Distribute and re-order
2652e4b17023SJohn Marino 	 Attempt a few simplifications when B and C are both constants.  */
2653e4b17023SJohn Marino       if (GET_CODE (op0) == AND
2654e4b17023SJohn Marino 	  && CONST_INT_P (op1)
2655e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op0, 1)))
2656e4b17023SJohn Marino 	{
2657e4b17023SJohn Marino 	  rtx a = XEXP (op0, 0);
2658e4b17023SJohn Marino 	  rtx b = XEXP (op0, 1);
2659e4b17023SJohn Marino 	  rtx c = op1;
2660e4b17023SJohn Marino 	  HOST_WIDE_INT bval = INTVAL (b);
2661e4b17023SJohn Marino 	  HOST_WIDE_INT cval = INTVAL (c);
2662e4b17023SJohn Marino 
2663e4b17023SJohn Marino 	  rtx na_c
2664e4b17023SJohn Marino 	    = simplify_binary_operation (AND, mode,
2665e4b17023SJohn Marino 					 simplify_gen_unary (NOT, mode, a, mode),
2666e4b17023SJohn Marino 					 c);
2667e4b17023SJohn Marino 	  if ((~cval & bval) == 0)
2668e4b17023SJohn Marino 	    {
2669e4b17023SJohn Marino 	      /* Try to simplify ~A&C | ~B&C.  */
2670e4b17023SJohn Marino 	      if (na_c != NULL_RTX)
2671e4b17023SJohn Marino 		return simplify_gen_binary (IOR, mode, na_c,
2672e4b17023SJohn Marino 					    GEN_INT (~bval & cval));
2673e4b17023SJohn Marino 	    }
2674e4b17023SJohn Marino 	  else
2675e4b17023SJohn Marino 	    {
2676e4b17023SJohn Marino 	      /* If ~A&C is zero, simplify A&(~C&B) | ~B&C.  */
2677e4b17023SJohn Marino 	      if (na_c == const0_rtx)
2678e4b17023SJohn Marino 		{
2679e4b17023SJohn Marino 		  rtx a_nc_b = simplify_gen_binary (AND, mode, a,
2680e4b17023SJohn Marino 						    GEN_INT (~cval & bval));
2681e4b17023SJohn Marino 		  return simplify_gen_binary (IOR, mode, a_nc_b,
2682e4b17023SJohn Marino 					      GEN_INT (~bval & cval));
2683e4b17023SJohn Marino 		}
2684e4b17023SJohn Marino 	    }
2685e4b17023SJohn Marino 	}
2686e4b17023SJohn Marino 
2687e4b17023SJohn Marino       /* (xor (comparison foo bar) (const_int 1)) can become the reversed
2688e4b17023SJohn Marino 	 comparison if STORE_FLAG_VALUE is 1.  */
2689e4b17023SJohn Marino       if (STORE_FLAG_VALUE == 1
2690e4b17023SJohn Marino 	  && trueop1 == const1_rtx
2691e4b17023SJohn Marino 	  && COMPARISON_P (op0)
2692e4b17023SJohn Marino 	  && (reversed = reversed_comparison (op0, mode)))
2693e4b17023SJohn Marino 	return reversed;
2694e4b17023SJohn Marino 
2695e4b17023SJohn Marino       /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
2696e4b17023SJohn Marino 	 is (lt foo (const_int 0)), so we can perform the above
2697e4b17023SJohn Marino 	 simplification if STORE_FLAG_VALUE is 1.  */
2698e4b17023SJohn Marino 
2699e4b17023SJohn Marino       if (STORE_FLAG_VALUE == 1
2700e4b17023SJohn Marino 	  && trueop1 == const1_rtx
2701e4b17023SJohn Marino 	  && GET_CODE (op0) == LSHIFTRT
2702e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op0, 1))
2703e4b17023SJohn Marino 	  && INTVAL (XEXP (op0, 1)) == GET_MODE_PRECISION (mode) - 1)
2704e4b17023SJohn Marino 	return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx);
2705e4b17023SJohn Marino 
2706e4b17023SJohn Marino       /* (xor (comparison foo bar) (const_int sign-bit))
2707e4b17023SJohn Marino 	 when STORE_FLAG_VALUE is the sign bit.  */
2708e4b17023SJohn Marino       if (val_signbit_p (mode, STORE_FLAG_VALUE)
2709e4b17023SJohn Marino 	  && trueop1 == const_true_rtx
2710e4b17023SJohn Marino 	  && COMPARISON_P (op0)
2711e4b17023SJohn Marino 	  && (reversed = reversed_comparison (op0, mode)))
2712e4b17023SJohn Marino 	return reversed;
2713e4b17023SJohn Marino 
2714e4b17023SJohn Marino       tem = simplify_associative_operation (code, mode, op0, op1);
2715e4b17023SJohn Marino       if (tem)
2716e4b17023SJohn Marino 	return tem;
2717e4b17023SJohn Marino       break;
2718e4b17023SJohn Marino 
2719e4b17023SJohn Marino     case AND:
2720e4b17023SJohn Marino       if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
2721e4b17023SJohn Marino 	return trueop1;
2722e4b17023SJohn Marino       if (INTEGRAL_MODE_P (mode) && trueop1 == CONSTM1_RTX (mode))
2723e4b17023SJohn Marino 	return op0;
2724e4b17023SJohn Marino       if (HWI_COMPUTABLE_MODE_P (mode))
2725e4b17023SJohn Marino 	{
2726e4b17023SJohn Marino 	  HOST_WIDE_INT nzop0 = nonzero_bits (trueop0, mode);
2727e4b17023SJohn Marino 	  HOST_WIDE_INT nzop1;
2728e4b17023SJohn Marino 	  if (CONST_INT_P (trueop1))
2729e4b17023SJohn Marino 	    {
2730e4b17023SJohn Marino 	      HOST_WIDE_INT val1 = INTVAL (trueop1);
2731e4b17023SJohn Marino 	      /* If we are turning off bits already known off in OP0, we need
2732e4b17023SJohn Marino 		 not do an AND.  */
2733e4b17023SJohn Marino 	      if ((nzop0 & ~val1) == 0)
2734e4b17023SJohn Marino 		return op0;
2735e4b17023SJohn Marino 	    }
2736e4b17023SJohn Marino 	  nzop1 = nonzero_bits (trueop1, mode);
2737e4b17023SJohn Marino 	  /* If we are clearing all the nonzero bits, the result is zero.  */
2738e4b17023SJohn Marino 	  if ((nzop1 & nzop0) == 0
2739e4b17023SJohn Marino 	      && !side_effects_p (op0) && !side_effects_p (op1))
2740e4b17023SJohn Marino 	    return CONST0_RTX (mode);
2741e4b17023SJohn Marino 	}
2742e4b17023SJohn Marino       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)
2743e4b17023SJohn Marino 	  && GET_MODE_CLASS (mode) != MODE_CC)
2744e4b17023SJohn Marino 	return op0;
2745e4b17023SJohn Marino       /* A & (~A) -> 0 */
2746e4b17023SJohn Marino       if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
2747e4b17023SJohn Marino 	   || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
2748e4b17023SJohn Marino 	  && ! side_effects_p (op0)
2749e4b17023SJohn Marino 	  && GET_MODE_CLASS (mode) != MODE_CC)
2750e4b17023SJohn Marino 	return CONST0_RTX (mode);
2751e4b17023SJohn Marino 
2752e4b17023SJohn Marino       /* Transform (and (extend X) C) into (zero_extend (and X C)) if
2753e4b17023SJohn Marino 	 there are no nonzero bits of C outside of X's mode.  */
2754e4b17023SJohn Marino       if ((GET_CODE (op0) == SIGN_EXTEND
2755e4b17023SJohn Marino 	   || GET_CODE (op0) == ZERO_EXTEND)
2756e4b17023SJohn Marino 	  && CONST_INT_P (trueop1)
2757e4b17023SJohn Marino 	  && HWI_COMPUTABLE_MODE_P (mode)
2758e4b17023SJohn Marino 	  && (~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))
2759e4b17023SJohn Marino 	      & UINTVAL (trueop1)) == 0)
2760e4b17023SJohn Marino 	{
2761e4b17023SJohn Marino 	  enum machine_mode imode = GET_MODE (XEXP (op0, 0));
2762e4b17023SJohn Marino 	  tem = simplify_gen_binary (AND, imode, XEXP (op0, 0),
2763e4b17023SJohn Marino 				     gen_int_mode (INTVAL (trueop1),
2764e4b17023SJohn Marino 						   imode));
2765e4b17023SJohn Marino 	  return simplify_gen_unary (ZERO_EXTEND, mode, tem, imode);
2766e4b17023SJohn Marino 	}
2767e4b17023SJohn Marino 
2768e4b17023SJohn Marino       /* Transform (and (truncate X) C) into (truncate (and X C)).  This way
2769e4b17023SJohn Marino 	 we might be able to further simplify the AND with X and potentially
2770e4b17023SJohn Marino 	 remove the truncation altogether.  */
2771e4b17023SJohn Marino       if (GET_CODE (op0) == TRUNCATE && CONST_INT_P (trueop1))
2772e4b17023SJohn Marino 	{
2773e4b17023SJohn Marino 	  rtx x = XEXP (op0, 0);
2774e4b17023SJohn Marino 	  enum machine_mode xmode = GET_MODE (x);
2775e4b17023SJohn Marino 	  tem = simplify_gen_binary (AND, xmode, x,
2776e4b17023SJohn Marino 				     gen_int_mode (INTVAL (trueop1), xmode));
2777e4b17023SJohn Marino 	  return simplify_gen_unary (TRUNCATE, mode, tem, xmode);
2778e4b17023SJohn Marino 	}
2779e4b17023SJohn Marino 
2780e4b17023SJohn Marino       /* Canonicalize (A | C1) & C2 as (A & C2) | (C1 & C2).  */
2781e4b17023SJohn Marino       if (GET_CODE (op0) == IOR
2782e4b17023SJohn Marino 	  && CONST_INT_P (trueop1)
2783e4b17023SJohn Marino 	  && CONST_INT_P (XEXP (op0, 1)))
2784e4b17023SJohn Marino 	{
2785e4b17023SJohn Marino 	  HOST_WIDE_INT tmp = INTVAL (trueop1) & INTVAL (XEXP (op0, 1));
2786e4b17023SJohn Marino 	  return simplify_gen_binary (IOR, mode,
2787e4b17023SJohn Marino 				      simplify_gen_binary (AND, mode,
2788e4b17023SJohn Marino 							   XEXP (op0, 0), op1),
2789e4b17023SJohn Marino 				      gen_int_mode (tmp, mode));
2790e4b17023SJohn Marino 	}
2791e4b17023SJohn Marino 
2792e4b17023SJohn Marino       /* Convert (A ^ B) & A to A & (~B) since the latter is often a single
2793e4b17023SJohn Marino 	 insn (and may simplify more).  */
2794e4b17023SJohn Marino       if (GET_CODE (op0) == XOR
2795e4b17023SJohn Marino 	  && rtx_equal_p (XEXP (op0, 0), op1)
2796e4b17023SJohn Marino 	  && ! side_effects_p (op1))
2797e4b17023SJohn Marino 	return simplify_gen_binary (AND, mode,
2798e4b17023SJohn Marino 				    simplify_gen_unary (NOT, mode,
2799e4b17023SJohn Marino 							XEXP (op0, 1), mode),
2800e4b17023SJohn Marino 				    op1);
2801e4b17023SJohn Marino 
2802e4b17023SJohn Marino       if (GET_CODE (op0) == XOR
2803e4b17023SJohn Marino 	  && rtx_equal_p (XEXP (op0, 1), op1)
2804e4b17023SJohn Marino 	  && ! side_effects_p (op1))
2805e4b17023SJohn Marino 	return simplify_gen_binary (AND, mode,
2806e4b17023SJohn Marino 				    simplify_gen_unary (NOT, mode,
2807e4b17023SJohn Marino 							XEXP (op0, 0), mode),
2808e4b17023SJohn Marino 				    op1);
2809e4b17023SJohn Marino 
2810e4b17023SJohn Marino       /* Similarly for (~(A ^ B)) & A.  */
2811e4b17023SJohn Marino       if (GET_CODE (op0) == NOT
2812e4b17023SJohn Marino 	  && GET_CODE (XEXP (op0, 0)) == XOR
2813e4b17023SJohn Marino 	  && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1)
2814e4b17023SJohn Marino 	  && ! side_effects_p (op1))
2815e4b17023SJohn Marino 	return simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
2816e4b17023SJohn Marino 
2817e4b17023SJohn Marino       if (GET_CODE (op0) == NOT
2818e4b17023SJohn Marino 	  && GET_CODE (XEXP (op0, 0)) == XOR
2819e4b17023SJohn Marino 	  && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1)
2820e4b17023SJohn Marino 	  && ! side_effects_p (op1))
2821e4b17023SJohn Marino 	return simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
2822e4b17023SJohn Marino 
2823e4b17023SJohn Marino       /* Convert (A | B) & A to A.  */
2824e4b17023SJohn Marino       if (GET_CODE (op0) == IOR
2825e4b17023SJohn Marino 	  && (rtx_equal_p (XEXP (op0, 0), op1)
2826e4b17023SJohn Marino 	      || rtx_equal_p (XEXP (op0, 1), op1))
2827e4b17023SJohn Marino 	  && ! side_effects_p (XEXP (op0, 0))
2828e4b17023SJohn Marino 	  && ! side_effects_p (XEXP (op0, 1)))
2829e4b17023SJohn Marino 	return op1;
2830e4b17023SJohn Marino 
2831e4b17023SJohn Marino       /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
2832e4b17023SJohn Marino 	 ((A & N) + B) & M -> (A + B) & M
2833e4b17023SJohn Marino 	 Similarly if (N & M) == 0,
2834e4b17023SJohn Marino 	 ((A | N) + B) & M -> (A + B) & M
2835e4b17023SJohn Marino 	 and for - instead of + and/or ^ instead of |.
2836e4b17023SJohn Marino          Also, if (N & M) == 0, then
2837e4b17023SJohn Marino 	 (A +- N) & M -> A & M.  */
2838e4b17023SJohn Marino       if (CONST_INT_P (trueop1)
2839e4b17023SJohn Marino 	  && HWI_COMPUTABLE_MODE_P (mode)
2840e4b17023SJohn Marino 	  && ~UINTVAL (trueop1)
2841e4b17023SJohn Marino 	  && (UINTVAL (trueop1) & (UINTVAL (trueop1) + 1)) == 0
2842e4b17023SJohn Marino 	  && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS))
2843e4b17023SJohn Marino 	{
2844e4b17023SJohn Marino 	  rtx pmop[2];
2845e4b17023SJohn Marino 	  int which;
2846e4b17023SJohn Marino 
2847e4b17023SJohn Marino 	  pmop[0] = XEXP (op0, 0);
2848e4b17023SJohn Marino 	  pmop[1] = XEXP (op0, 1);
2849e4b17023SJohn Marino 
2850e4b17023SJohn Marino 	  if (CONST_INT_P (pmop[1])
2851e4b17023SJohn Marino 	      && (UINTVAL (pmop[1]) & UINTVAL (trueop1)) == 0)
2852e4b17023SJohn Marino 	    return simplify_gen_binary (AND, mode, pmop[0], op1);
2853e4b17023SJohn Marino 
2854e4b17023SJohn Marino 	  for (which = 0; which < 2; which++)
2855e4b17023SJohn Marino 	    {
2856e4b17023SJohn Marino 	      tem = pmop[which];
2857e4b17023SJohn Marino 	      switch (GET_CODE (tem))
2858e4b17023SJohn Marino 		{
2859e4b17023SJohn Marino 		case AND:
2860e4b17023SJohn Marino 		  if (CONST_INT_P (XEXP (tem, 1))
2861e4b17023SJohn Marino 		      && (UINTVAL (XEXP (tem, 1)) & UINTVAL (trueop1))
2862e4b17023SJohn Marino 		      == UINTVAL (trueop1))
2863e4b17023SJohn Marino 		    pmop[which] = XEXP (tem, 0);
2864e4b17023SJohn Marino 		  break;
2865e4b17023SJohn Marino 		case IOR:
2866e4b17023SJohn Marino 		case XOR:
2867e4b17023SJohn Marino 		  if (CONST_INT_P (XEXP (tem, 1))
2868e4b17023SJohn Marino 		      && (UINTVAL (XEXP (tem, 1)) & UINTVAL (trueop1)) == 0)
2869e4b17023SJohn Marino 		    pmop[which] = XEXP (tem, 0);
2870e4b17023SJohn Marino 		  break;
2871e4b17023SJohn Marino 		default:
2872e4b17023SJohn Marino 		  break;
2873e4b17023SJohn Marino 		}
2874e4b17023SJohn Marino 	    }
2875e4b17023SJohn Marino 
2876e4b17023SJohn Marino 	  if (pmop[0] != XEXP (op0, 0) || pmop[1] != XEXP (op0, 1))
2877e4b17023SJohn Marino 	    {
2878e4b17023SJohn Marino 	      tem = simplify_gen_binary (GET_CODE (op0), mode,
2879e4b17023SJohn Marino 					 pmop[0], pmop[1]);
2880e4b17023SJohn Marino 	      return simplify_gen_binary (code, mode, tem, op1);
2881e4b17023SJohn Marino 	    }
2882e4b17023SJohn Marino 	}
2883e4b17023SJohn Marino 
2884e4b17023SJohn Marino       /* (and X (ior (not X) Y) -> (and X Y) */
2885e4b17023SJohn Marino       if (GET_CODE (op1) == IOR
2886e4b17023SJohn Marino 	  && GET_CODE (XEXP (op1, 0)) == NOT
2887e4b17023SJohn Marino 	  && op0 == XEXP (XEXP (op1, 0), 0))
2888e4b17023SJohn Marino        return simplify_gen_binary (AND, mode, op0, XEXP (op1, 1));
2889e4b17023SJohn Marino 
2890e4b17023SJohn Marino       /* (and (ior (not X) Y) X) -> (and X Y) */
2891e4b17023SJohn Marino       if (GET_CODE (op0) == IOR
2892e4b17023SJohn Marino 	  && GET_CODE (XEXP (op0, 0)) == NOT
2893e4b17023SJohn Marino 	  && op1 == XEXP (XEXP (op0, 0), 0))
2894e4b17023SJohn Marino 	return simplify_gen_binary (AND, mode, op1, XEXP (op0, 1));
2895e4b17023SJohn Marino 
2896e4b17023SJohn Marino       tem = simplify_associative_operation (code, mode, op0, op1);
2897e4b17023SJohn Marino       if (tem)
2898e4b17023SJohn Marino 	return tem;
2899e4b17023SJohn Marino       break;
2900e4b17023SJohn Marino 
2901e4b17023SJohn Marino     case UDIV:
2902e4b17023SJohn Marino       /* 0/x is 0 (or x&0 if x has side-effects).  */
2903e4b17023SJohn Marino       if (trueop0 == CONST0_RTX (mode))
2904e4b17023SJohn Marino 	{
2905e4b17023SJohn Marino 	  if (side_effects_p (op1))
2906e4b17023SJohn Marino 	    return simplify_gen_binary (AND, mode, op1, trueop0);
2907e4b17023SJohn Marino 	  return trueop0;
2908e4b17023SJohn Marino 	}
2909e4b17023SJohn Marino       /* x/1 is x.  */
2910e4b17023SJohn Marino       if (trueop1 == CONST1_RTX (mode))
2911e4b17023SJohn Marino 	return rtl_hooks.gen_lowpart_no_emit (mode, op0);
2912e4b17023SJohn Marino       /* Convert divide by power of two into shift.  */
2913e4b17023SJohn Marino       if (CONST_INT_P (trueop1)
2914e4b17023SJohn Marino 	  && (val = exact_log2 (UINTVAL (trueop1))) > 0)
2915e4b17023SJohn Marino 	return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (val));
2916e4b17023SJohn Marino       break;
2917e4b17023SJohn Marino 
2918e4b17023SJohn Marino     case DIV:
2919e4b17023SJohn Marino       /* Handle floating point and integers separately.  */
2920e4b17023SJohn Marino       if (SCALAR_FLOAT_MODE_P (mode))
2921e4b17023SJohn Marino 	{
2922e4b17023SJohn Marino 	  /* Maybe change 0.0 / x to 0.0.  This transformation isn't
2923e4b17023SJohn Marino 	     safe for modes with NaNs, since 0.0 / 0.0 will then be
2924e4b17023SJohn Marino 	     NaN rather than 0.0.  Nor is it safe for modes with signed
2925e4b17023SJohn Marino 	     zeros, since dividing 0 by a negative number gives -0.0  */
2926e4b17023SJohn Marino 	  if (trueop0 == CONST0_RTX (mode)
2927e4b17023SJohn Marino 	      && !HONOR_NANS (mode)
2928e4b17023SJohn Marino 	      && !HONOR_SIGNED_ZEROS (mode)
2929e4b17023SJohn Marino 	      && ! side_effects_p (op1))
2930e4b17023SJohn Marino 	    return op0;
2931e4b17023SJohn Marino 	  /* x/1.0 is x.  */
2932e4b17023SJohn Marino 	  if (trueop1 == CONST1_RTX (mode)
2933e4b17023SJohn Marino 	      && !HONOR_SNANS (mode))
2934e4b17023SJohn Marino 	    return op0;
2935e4b17023SJohn Marino 
2936e4b17023SJohn Marino 	  if (GET_CODE (trueop1) == CONST_DOUBLE
2937e4b17023SJohn Marino 	      && trueop1 != CONST0_RTX (mode))
2938e4b17023SJohn Marino 	    {
2939e4b17023SJohn Marino 	      REAL_VALUE_TYPE d;
2940e4b17023SJohn Marino 	      REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
2941e4b17023SJohn Marino 
2942e4b17023SJohn Marino 	      /* x/-1.0 is -x.  */
2943e4b17023SJohn Marino 	      if (REAL_VALUES_EQUAL (d, dconstm1)
2944e4b17023SJohn Marino 		  && !HONOR_SNANS (mode))
2945e4b17023SJohn Marino 		return simplify_gen_unary (NEG, mode, op0, mode);
2946e4b17023SJohn Marino 
2947e4b17023SJohn Marino 	      /* Change FP division by a constant into multiplication.
2948e4b17023SJohn Marino 		 Only do this with -freciprocal-math.  */
2949e4b17023SJohn Marino 	      if (flag_reciprocal_math
2950e4b17023SJohn Marino 		  && !REAL_VALUES_EQUAL (d, dconst0))
2951e4b17023SJohn Marino 		{
2952e4b17023SJohn Marino 		  REAL_ARITHMETIC (d, RDIV_EXPR, dconst1, d);
2953e4b17023SJohn Marino 		  tem = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
2954e4b17023SJohn Marino 		  return simplify_gen_binary (MULT, mode, op0, tem);
2955e4b17023SJohn Marino 		}
2956e4b17023SJohn Marino 	    }
2957e4b17023SJohn Marino 	}
2958e4b17023SJohn Marino       else if (SCALAR_INT_MODE_P (mode))
2959e4b17023SJohn Marino 	{
2960e4b17023SJohn Marino 	  /* 0/x is 0 (or x&0 if x has side-effects).  */
2961e4b17023SJohn Marino 	  if (trueop0 == CONST0_RTX (mode)
2962e4b17023SJohn Marino 	      && !cfun->can_throw_non_call_exceptions)
2963e4b17023SJohn Marino 	    {
2964e4b17023SJohn Marino 	      if (side_effects_p (op1))
2965e4b17023SJohn Marino 		return simplify_gen_binary (AND, mode, op1, trueop0);
2966e4b17023SJohn Marino 	      return trueop0;
2967e4b17023SJohn Marino 	    }
2968e4b17023SJohn Marino 	  /* x/1 is x.  */
2969e4b17023SJohn Marino 	  if (trueop1 == CONST1_RTX (mode))
2970e4b17023SJohn Marino 	    return rtl_hooks.gen_lowpart_no_emit (mode, op0);
2971e4b17023SJohn Marino 	  /* x/-1 is -x.  */
2972e4b17023SJohn Marino 	  if (trueop1 == constm1_rtx)
2973e4b17023SJohn Marino 	    {
2974e4b17023SJohn Marino 	      rtx x = rtl_hooks.gen_lowpart_no_emit (mode, op0);
2975e4b17023SJohn Marino 	      return simplify_gen_unary (NEG, mode, x, mode);
2976e4b17023SJohn Marino 	    }
2977e4b17023SJohn Marino 	}
2978e4b17023SJohn Marino       break;
2979e4b17023SJohn Marino 
2980e4b17023SJohn Marino     case UMOD:
2981e4b17023SJohn Marino       /* 0%x is 0 (or x&0 if x has side-effects).  */
2982e4b17023SJohn Marino       if (trueop0 == CONST0_RTX (mode))
2983e4b17023SJohn Marino 	{
2984e4b17023SJohn Marino 	  if (side_effects_p (op1))
2985e4b17023SJohn Marino 	    return simplify_gen_binary (AND, mode, op1, trueop0);
2986e4b17023SJohn Marino 	  return trueop0;
2987e4b17023SJohn Marino 	}
2988e4b17023SJohn Marino       /* x%1 is 0 (of x&0 if x has side-effects).  */
2989e4b17023SJohn Marino       if (trueop1 == CONST1_RTX (mode))
2990e4b17023SJohn Marino 	{
2991e4b17023SJohn Marino 	  if (side_effects_p (op0))
2992e4b17023SJohn Marino 	    return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode));
2993e4b17023SJohn Marino 	  return CONST0_RTX (mode);
2994e4b17023SJohn Marino 	}
2995e4b17023SJohn Marino       /* Implement modulus by power of two as AND.  */
2996e4b17023SJohn Marino       if (CONST_INT_P (trueop1)
2997e4b17023SJohn Marino 	  && exact_log2 (UINTVAL (trueop1)) > 0)
2998e4b17023SJohn Marino 	return simplify_gen_binary (AND, mode, op0,
2999e4b17023SJohn Marino 				    GEN_INT (INTVAL (op1) - 1));
3000e4b17023SJohn Marino       break;
3001e4b17023SJohn Marino 
3002e4b17023SJohn Marino     case MOD:
3003e4b17023SJohn Marino       /* 0%x is 0 (or x&0 if x has side-effects).  */
3004e4b17023SJohn Marino       if (trueop0 == CONST0_RTX (mode))
3005e4b17023SJohn Marino 	{
3006e4b17023SJohn Marino 	  if (side_effects_p (op1))
3007e4b17023SJohn Marino 	    return simplify_gen_binary (AND, mode, op1, trueop0);
3008e4b17023SJohn Marino 	  return trueop0;
3009e4b17023SJohn Marino 	}
3010e4b17023SJohn Marino       /* x%1 and x%-1 is 0 (or x&0 if x has side-effects).  */
3011e4b17023SJohn Marino       if (trueop1 == CONST1_RTX (mode) || trueop1 == constm1_rtx)
3012e4b17023SJohn Marino 	{
3013e4b17023SJohn Marino 	  if (side_effects_p (op0))
3014e4b17023SJohn Marino 	    return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode));
3015e4b17023SJohn Marino 	  return CONST0_RTX (mode);
3016e4b17023SJohn Marino 	}
3017e4b17023SJohn Marino       break;
3018e4b17023SJohn Marino 
3019e4b17023SJohn Marino     case ROTATERT:
3020e4b17023SJohn Marino     case ROTATE:
3021e4b17023SJohn Marino     case ASHIFTRT:
3022e4b17023SJohn Marino       if (trueop1 == CONST0_RTX (mode))
3023e4b17023SJohn Marino 	return op0;
3024e4b17023SJohn Marino       if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
3025e4b17023SJohn Marino 	return op0;
3026e4b17023SJohn Marino       /* Rotating ~0 always results in ~0.  */
3027e4b17023SJohn Marino       if (CONST_INT_P (trueop0) && width <= HOST_BITS_PER_WIDE_INT
3028e4b17023SJohn Marino 	  && UINTVAL (trueop0) == GET_MODE_MASK (mode)
3029e4b17023SJohn Marino 	  && ! side_effects_p (op1))
3030e4b17023SJohn Marino 	return op0;
3031e4b17023SJohn Marino     canonicalize_shift:
3032e4b17023SJohn Marino       if (SHIFT_COUNT_TRUNCATED && CONST_INT_P (op1))
3033e4b17023SJohn Marino 	{
3034e4b17023SJohn Marino 	  val = INTVAL (op1) & (GET_MODE_BITSIZE (mode) - 1);
3035e4b17023SJohn Marino 	  if (val != INTVAL (op1))
3036e4b17023SJohn Marino 	    return simplify_gen_binary (code, mode, op0, GEN_INT (val));
3037e4b17023SJohn Marino 	}
3038e4b17023SJohn Marino       break;
3039e4b17023SJohn Marino 
3040e4b17023SJohn Marino     case ASHIFT:
3041e4b17023SJohn Marino     case SS_ASHIFT:
3042e4b17023SJohn Marino     case US_ASHIFT:
3043e4b17023SJohn Marino       if (trueop1 == CONST0_RTX (mode))
3044e4b17023SJohn Marino 	return op0;
3045e4b17023SJohn Marino       if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
3046e4b17023SJohn Marino 	return op0;
3047e4b17023SJohn Marino       goto canonicalize_shift;
3048e4b17023SJohn Marino 
3049e4b17023SJohn Marino     case LSHIFTRT:
3050e4b17023SJohn Marino       if (trueop1 == CONST0_RTX (mode))
3051e4b17023SJohn Marino 	return op0;
3052e4b17023SJohn Marino       if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
3053e4b17023SJohn Marino 	return op0;
3054e4b17023SJohn Marino       /* Optimize (lshiftrt (clz X) C) as (eq X 0).  */
3055e4b17023SJohn Marino       if (GET_CODE (op0) == CLZ
3056e4b17023SJohn Marino 	  && CONST_INT_P (trueop1)
3057e4b17023SJohn Marino 	  && STORE_FLAG_VALUE == 1
3058e4b17023SJohn Marino 	  && INTVAL (trueop1) < (HOST_WIDE_INT)width)
3059e4b17023SJohn Marino 	{
3060e4b17023SJohn Marino 	  enum machine_mode imode = GET_MODE (XEXP (op0, 0));
3061e4b17023SJohn Marino 	  unsigned HOST_WIDE_INT zero_val = 0;
3062e4b17023SJohn Marino 
3063e4b17023SJohn Marino 	  if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
3064e4b17023SJohn Marino 	      && zero_val == GET_MODE_PRECISION (imode)
3065e4b17023SJohn Marino 	      && INTVAL (trueop1) == exact_log2 (zero_val))
3066e4b17023SJohn Marino 	    return simplify_gen_relational (EQ, mode, imode,
3067e4b17023SJohn Marino 					    XEXP (op0, 0), const0_rtx);
3068e4b17023SJohn Marino 	}
3069e4b17023SJohn Marino       goto canonicalize_shift;
3070e4b17023SJohn Marino 
3071e4b17023SJohn Marino     case SMIN:
3072e4b17023SJohn Marino       if (width <= HOST_BITS_PER_WIDE_INT
3073e4b17023SJohn Marino 	  && mode_signbit_p (mode, trueop1)
3074e4b17023SJohn Marino 	  && ! side_effects_p (op0))
3075e4b17023SJohn Marino 	return op1;
3076e4b17023SJohn Marino       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
3077e4b17023SJohn Marino 	return op0;
3078e4b17023SJohn Marino       tem = simplify_associative_operation (code, mode, op0, op1);
3079e4b17023SJohn Marino       if (tem)
3080e4b17023SJohn Marino 	return tem;
3081e4b17023SJohn Marino       break;
3082e4b17023SJohn Marino 
3083e4b17023SJohn Marino     case SMAX:
3084e4b17023SJohn Marino       if (width <= HOST_BITS_PER_WIDE_INT
3085e4b17023SJohn Marino 	  && CONST_INT_P (trueop1)
3086e4b17023SJohn Marino 	  && (UINTVAL (trueop1) == GET_MODE_MASK (mode) >> 1)
3087e4b17023SJohn Marino 	  && ! side_effects_p (op0))
3088e4b17023SJohn Marino 	return op1;
3089e4b17023SJohn Marino       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
3090e4b17023SJohn Marino 	return op0;
3091e4b17023SJohn Marino       tem = simplify_associative_operation (code, mode, op0, op1);
3092e4b17023SJohn Marino       if (tem)
3093e4b17023SJohn Marino 	return tem;
3094e4b17023SJohn Marino       break;
3095e4b17023SJohn Marino 
3096e4b17023SJohn Marino     case UMIN:
3097e4b17023SJohn Marino       if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
3098e4b17023SJohn Marino 	return op1;
3099e4b17023SJohn Marino       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
3100e4b17023SJohn Marino 	return op0;
3101e4b17023SJohn Marino       tem = simplify_associative_operation (code, mode, op0, op1);
3102e4b17023SJohn Marino       if (tem)
3103e4b17023SJohn Marino 	return tem;
3104e4b17023SJohn Marino       break;
3105e4b17023SJohn Marino 
3106e4b17023SJohn Marino     case UMAX:
3107e4b17023SJohn Marino       if (trueop1 == constm1_rtx && ! side_effects_p (op0))
3108e4b17023SJohn Marino 	return op1;
3109e4b17023SJohn Marino       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
3110e4b17023SJohn Marino 	return op0;
3111e4b17023SJohn Marino       tem = simplify_associative_operation (code, mode, op0, op1);
3112e4b17023SJohn Marino       if (tem)
3113e4b17023SJohn Marino 	return tem;
3114e4b17023SJohn Marino       break;
3115e4b17023SJohn Marino 
3116e4b17023SJohn Marino     case SS_PLUS:
3117e4b17023SJohn Marino     case US_PLUS:
3118e4b17023SJohn Marino     case SS_MINUS:
3119e4b17023SJohn Marino     case US_MINUS:
3120e4b17023SJohn Marino     case SS_MULT:
3121e4b17023SJohn Marino     case US_MULT:
3122e4b17023SJohn Marino     case SS_DIV:
3123e4b17023SJohn Marino     case US_DIV:
3124e4b17023SJohn Marino       /* ??? There are simplifications that can be done.  */
3125e4b17023SJohn Marino       return 0;
3126e4b17023SJohn Marino 
3127e4b17023SJohn Marino     case VEC_SELECT:
3128e4b17023SJohn Marino       if (!VECTOR_MODE_P (mode))
3129e4b17023SJohn Marino 	{
3130e4b17023SJohn Marino 	  gcc_assert (VECTOR_MODE_P (GET_MODE (trueop0)));
3131e4b17023SJohn Marino 	  gcc_assert (mode == GET_MODE_INNER (GET_MODE (trueop0)));
3132e4b17023SJohn Marino 	  gcc_assert (GET_CODE (trueop1) == PARALLEL);
3133e4b17023SJohn Marino 	  gcc_assert (XVECLEN (trueop1, 0) == 1);
3134e4b17023SJohn Marino 	  gcc_assert (CONST_INT_P (XVECEXP (trueop1, 0, 0)));
3135e4b17023SJohn Marino 
3136e4b17023SJohn Marino 	  if (GET_CODE (trueop0) == CONST_VECTOR)
3137e4b17023SJohn Marino 	    return CONST_VECTOR_ELT (trueop0, INTVAL (XVECEXP
3138e4b17023SJohn Marino 						      (trueop1, 0, 0)));
3139e4b17023SJohn Marino 
3140e4b17023SJohn Marino 	  /* Extract a scalar element from a nested VEC_SELECT expression
3141e4b17023SJohn Marino 	     (with optional nested VEC_CONCAT expression).  Some targets
3142e4b17023SJohn Marino 	     (i386) extract scalar element from a vector using chain of
3143e4b17023SJohn Marino 	     nested VEC_SELECT expressions.  When input operand is a memory
3144e4b17023SJohn Marino 	     operand, this operation can be simplified to a simple scalar
3145e4b17023SJohn Marino 	     load from an offseted memory address.  */
3146e4b17023SJohn Marino 	  if (GET_CODE (trueop0) == VEC_SELECT)
3147e4b17023SJohn Marino 	    {
3148e4b17023SJohn Marino 	      rtx op0 = XEXP (trueop0, 0);
3149e4b17023SJohn Marino 	      rtx op1 = XEXP (trueop0, 1);
3150e4b17023SJohn Marino 
3151e4b17023SJohn Marino 	      enum machine_mode opmode = GET_MODE (op0);
3152e4b17023SJohn Marino 	      int elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
3153e4b17023SJohn Marino 	      int n_elts = GET_MODE_SIZE (opmode) / elt_size;
3154e4b17023SJohn Marino 
3155e4b17023SJohn Marino 	      int i = INTVAL (XVECEXP (trueop1, 0, 0));
3156e4b17023SJohn Marino 	      int elem;
3157e4b17023SJohn Marino 
3158e4b17023SJohn Marino 	      rtvec vec;
3159e4b17023SJohn Marino 	      rtx tmp_op, tmp;
3160e4b17023SJohn Marino 
3161e4b17023SJohn Marino 	      gcc_assert (GET_CODE (op1) == PARALLEL);
3162e4b17023SJohn Marino 	      gcc_assert (i < n_elts);
3163e4b17023SJohn Marino 
3164e4b17023SJohn Marino 	      /* Select element, pointed by nested selector.  */
3165e4b17023SJohn Marino 	      elem = INTVAL (XVECEXP (op1, 0, i));
3166e4b17023SJohn Marino 
3167e4b17023SJohn Marino 	      /* Handle the case when nested VEC_SELECT wraps VEC_CONCAT.  */
3168e4b17023SJohn Marino 	      if (GET_CODE (op0) == VEC_CONCAT)
3169e4b17023SJohn Marino 		{
3170e4b17023SJohn Marino 		  rtx op00 = XEXP (op0, 0);
3171e4b17023SJohn Marino 		  rtx op01 = XEXP (op0, 1);
3172e4b17023SJohn Marino 
3173e4b17023SJohn Marino 		  enum machine_mode mode00, mode01;
3174e4b17023SJohn Marino 		  int n_elts00, n_elts01;
3175e4b17023SJohn Marino 
3176e4b17023SJohn Marino 		  mode00 = GET_MODE (op00);
3177e4b17023SJohn Marino 		  mode01 = GET_MODE (op01);
3178e4b17023SJohn Marino 
3179e4b17023SJohn Marino 		  /* Find out number of elements of each operand.  */
3180e4b17023SJohn Marino 		  if (VECTOR_MODE_P (mode00))
3181e4b17023SJohn Marino 		    {
3182e4b17023SJohn Marino 		      elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode00));
3183e4b17023SJohn Marino 		      n_elts00 = GET_MODE_SIZE (mode00) / elt_size;
3184e4b17023SJohn Marino 		    }
3185e4b17023SJohn Marino 		  else
3186e4b17023SJohn Marino 		    n_elts00 = 1;
3187e4b17023SJohn Marino 
3188e4b17023SJohn Marino 		  if (VECTOR_MODE_P (mode01))
3189e4b17023SJohn Marino 		    {
3190e4b17023SJohn Marino 		      elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode01));
3191e4b17023SJohn Marino 		      n_elts01 = GET_MODE_SIZE (mode01) / elt_size;
3192e4b17023SJohn Marino 		    }
3193e4b17023SJohn Marino 		  else
3194e4b17023SJohn Marino 		    n_elts01 = 1;
3195e4b17023SJohn Marino 
3196e4b17023SJohn Marino 		  gcc_assert (n_elts == n_elts00 + n_elts01);
3197e4b17023SJohn Marino 
3198e4b17023SJohn Marino 		  /* Select correct operand of VEC_CONCAT
3199e4b17023SJohn Marino 		     and adjust selector. */
3200e4b17023SJohn Marino 		  if (elem < n_elts01)
3201e4b17023SJohn Marino 		    tmp_op = op00;
3202e4b17023SJohn Marino 		  else
3203e4b17023SJohn Marino 		    {
3204e4b17023SJohn Marino 		      tmp_op = op01;
3205e4b17023SJohn Marino 		      elem -= n_elts00;
3206e4b17023SJohn Marino 		    }
3207e4b17023SJohn Marino 		}
3208e4b17023SJohn Marino 	      else
3209e4b17023SJohn Marino 		tmp_op = op0;
3210e4b17023SJohn Marino 
3211e4b17023SJohn Marino 	      vec = rtvec_alloc (1);
3212e4b17023SJohn Marino 	      RTVEC_ELT (vec, 0) = GEN_INT (elem);
3213e4b17023SJohn Marino 
3214e4b17023SJohn Marino 	      tmp = gen_rtx_fmt_ee (code, mode,
3215e4b17023SJohn Marino 				    tmp_op, gen_rtx_PARALLEL (VOIDmode, vec));
3216e4b17023SJohn Marino 	      return tmp;
3217e4b17023SJohn Marino 	    }
3218e4b17023SJohn Marino 	  if (GET_CODE (trueop0) == VEC_DUPLICATE
3219e4b17023SJohn Marino 	      && GET_MODE (XEXP (trueop0, 0)) == mode)
3220e4b17023SJohn Marino 	    return XEXP (trueop0, 0);
3221e4b17023SJohn Marino 	}
3222e4b17023SJohn Marino       else
3223e4b17023SJohn Marino 	{
3224e4b17023SJohn Marino 	  gcc_assert (VECTOR_MODE_P (GET_MODE (trueop0)));
3225e4b17023SJohn Marino 	  gcc_assert (GET_MODE_INNER (mode)
3226e4b17023SJohn Marino 		      == GET_MODE_INNER (GET_MODE (trueop0)));
3227e4b17023SJohn Marino 	  gcc_assert (GET_CODE (trueop1) == PARALLEL);
3228e4b17023SJohn Marino 
3229e4b17023SJohn Marino 	  if (GET_CODE (trueop0) == CONST_VECTOR)
3230e4b17023SJohn Marino 	    {
3231e4b17023SJohn Marino 	      int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
3232e4b17023SJohn Marino 	      unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
3233e4b17023SJohn Marino 	      rtvec v = rtvec_alloc (n_elts);
3234e4b17023SJohn Marino 	      unsigned int i;
3235e4b17023SJohn Marino 
3236e4b17023SJohn Marino 	      gcc_assert (XVECLEN (trueop1, 0) == (int) n_elts);
3237e4b17023SJohn Marino 	      for (i = 0; i < n_elts; i++)
3238e4b17023SJohn Marino 		{
3239e4b17023SJohn Marino 		  rtx x = XVECEXP (trueop1, 0, i);
3240e4b17023SJohn Marino 
3241e4b17023SJohn Marino 		  gcc_assert (CONST_INT_P (x));
3242e4b17023SJohn Marino 		  RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop0,
3243e4b17023SJohn Marino 						       INTVAL (x));
3244e4b17023SJohn Marino 		}
3245e4b17023SJohn Marino 
3246e4b17023SJohn Marino 	      return gen_rtx_CONST_VECTOR (mode, v);
3247e4b17023SJohn Marino 	    }
3248e4b17023SJohn Marino 	}
3249e4b17023SJohn Marino 
3250e4b17023SJohn Marino       if (XVECLEN (trueop1, 0) == 1
3251e4b17023SJohn Marino 	  && CONST_INT_P (XVECEXP (trueop1, 0, 0))
3252e4b17023SJohn Marino 	  && GET_CODE (trueop0) == VEC_CONCAT)
3253e4b17023SJohn Marino 	{
3254e4b17023SJohn Marino 	  rtx vec = trueop0;
3255e4b17023SJohn Marino 	  int offset = INTVAL (XVECEXP (trueop1, 0, 0)) * GET_MODE_SIZE (mode);
3256e4b17023SJohn Marino 
3257e4b17023SJohn Marino 	  /* Try to find the element in the VEC_CONCAT.  */
3258e4b17023SJohn Marino 	  while (GET_MODE (vec) != mode
3259e4b17023SJohn Marino 		 && GET_CODE (vec) == VEC_CONCAT)
3260e4b17023SJohn Marino 	    {
3261e4b17023SJohn Marino 	      HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
3262e4b17023SJohn Marino 	      if (offset < vec_size)
3263e4b17023SJohn Marino 		vec = XEXP (vec, 0);
3264e4b17023SJohn Marino 	      else
3265e4b17023SJohn Marino 		{
3266e4b17023SJohn Marino 		  offset -= vec_size;
3267e4b17023SJohn Marino 		  vec = XEXP (vec, 1);
3268e4b17023SJohn Marino 		}
3269e4b17023SJohn Marino 	      vec = avoid_constant_pool_reference (vec);
3270e4b17023SJohn Marino 	    }
3271e4b17023SJohn Marino 
3272e4b17023SJohn Marino 	  if (GET_MODE (vec) == mode)
3273e4b17023SJohn Marino 	    return vec;
3274e4b17023SJohn Marino 	}
3275e4b17023SJohn Marino 
3276e4b17023SJohn Marino       return 0;
3277e4b17023SJohn Marino     case VEC_CONCAT:
3278e4b17023SJohn Marino       {
3279e4b17023SJohn Marino 	enum machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
3280e4b17023SJohn Marino 				      ? GET_MODE (trueop0)
3281e4b17023SJohn Marino 				      : GET_MODE_INNER (mode));
3282e4b17023SJohn Marino 	enum machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
3283e4b17023SJohn Marino 				      ? GET_MODE (trueop1)
3284e4b17023SJohn Marino 				      : GET_MODE_INNER (mode));
3285e4b17023SJohn Marino 
3286e4b17023SJohn Marino 	gcc_assert (VECTOR_MODE_P (mode));
3287e4b17023SJohn Marino 	gcc_assert (GET_MODE_SIZE (op0_mode) + GET_MODE_SIZE (op1_mode)
3288e4b17023SJohn Marino 		    == GET_MODE_SIZE (mode));
3289e4b17023SJohn Marino 
3290e4b17023SJohn Marino 	if (VECTOR_MODE_P (op0_mode))
3291e4b17023SJohn Marino 	  gcc_assert (GET_MODE_INNER (mode)
3292e4b17023SJohn Marino 		      == GET_MODE_INNER (op0_mode));
3293e4b17023SJohn Marino 	else
3294e4b17023SJohn Marino 	  gcc_assert (GET_MODE_INNER (mode) == op0_mode);
3295e4b17023SJohn Marino 
3296e4b17023SJohn Marino 	if (VECTOR_MODE_P (op1_mode))
3297e4b17023SJohn Marino 	  gcc_assert (GET_MODE_INNER (mode)
3298e4b17023SJohn Marino 		      == GET_MODE_INNER (op1_mode));
3299e4b17023SJohn Marino 	else
3300e4b17023SJohn Marino 	  gcc_assert (GET_MODE_INNER (mode) == op1_mode);
3301e4b17023SJohn Marino 
3302e4b17023SJohn Marino 	if ((GET_CODE (trueop0) == CONST_VECTOR
3303e4b17023SJohn Marino 	     || CONST_INT_P (trueop0)
3304e4b17023SJohn Marino 	     || GET_CODE (trueop0) == CONST_DOUBLE)
3305e4b17023SJohn Marino 	    && (GET_CODE (trueop1) == CONST_VECTOR
3306e4b17023SJohn Marino 		|| CONST_INT_P (trueop1)
3307e4b17023SJohn Marino 		|| GET_CODE (trueop1) == CONST_DOUBLE))
3308e4b17023SJohn Marino 	  {
3309e4b17023SJohn Marino 	    int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
3310e4b17023SJohn Marino 	    unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
3311e4b17023SJohn Marino 	    rtvec v = rtvec_alloc (n_elts);
3312e4b17023SJohn Marino 	    unsigned int i;
3313e4b17023SJohn Marino 	    unsigned in_n_elts = 1;
3314e4b17023SJohn Marino 
3315e4b17023SJohn Marino 	    if (VECTOR_MODE_P (op0_mode))
3316e4b17023SJohn Marino 	      in_n_elts = (GET_MODE_SIZE (op0_mode) / elt_size);
3317e4b17023SJohn Marino 	    for (i = 0; i < n_elts; i++)
3318e4b17023SJohn Marino 	      {
3319e4b17023SJohn Marino 		if (i < in_n_elts)
3320e4b17023SJohn Marino 		  {
3321e4b17023SJohn Marino 		    if (!VECTOR_MODE_P (op0_mode))
3322e4b17023SJohn Marino 		      RTVEC_ELT (v, i) = trueop0;
3323e4b17023SJohn Marino 		    else
3324e4b17023SJohn Marino 		      RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop0, i);
3325e4b17023SJohn Marino 		  }
3326e4b17023SJohn Marino 		else
3327e4b17023SJohn Marino 		  {
3328e4b17023SJohn Marino 		    if (!VECTOR_MODE_P (op1_mode))
3329e4b17023SJohn Marino 		      RTVEC_ELT (v, i) = trueop1;
3330e4b17023SJohn Marino 		    else
3331e4b17023SJohn Marino 		      RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop1,
3332e4b17023SJohn Marino 							   i - in_n_elts);
3333e4b17023SJohn Marino 		  }
3334e4b17023SJohn Marino 	      }
3335e4b17023SJohn Marino 
3336e4b17023SJohn Marino 	    return gen_rtx_CONST_VECTOR (mode, v);
3337e4b17023SJohn Marino 	  }
3338e4b17023SJohn Marino       }
3339e4b17023SJohn Marino       return 0;
3340e4b17023SJohn Marino 
3341e4b17023SJohn Marino     default:
3342e4b17023SJohn Marino       gcc_unreachable ();
3343e4b17023SJohn Marino     }
3344e4b17023SJohn Marino 
3345e4b17023SJohn Marino   return 0;
3346e4b17023SJohn Marino }
3347e4b17023SJohn Marino 
3348e4b17023SJohn Marino rtx
simplify_const_binary_operation(enum rtx_code code,enum machine_mode mode,rtx op0,rtx op1)3349e4b17023SJohn Marino simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
3350e4b17023SJohn Marino 				 rtx op0, rtx op1)
3351e4b17023SJohn Marino {
3352e4b17023SJohn Marino   HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
3353e4b17023SJohn Marino   HOST_WIDE_INT val;
3354e4b17023SJohn Marino   unsigned int width = GET_MODE_PRECISION (mode);
3355e4b17023SJohn Marino 
3356e4b17023SJohn Marino   if (VECTOR_MODE_P (mode)
3357e4b17023SJohn Marino       && code != VEC_CONCAT
3358e4b17023SJohn Marino       && GET_CODE (op0) == CONST_VECTOR
3359e4b17023SJohn Marino       && GET_CODE (op1) == CONST_VECTOR)
3360e4b17023SJohn Marino     {
3361e4b17023SJohn Marino       unsigned n_elts = GET_MODE_NUNITS (mode);
3362e4b17023SJohn Marino       enum machine_mode op0mode = GET_MODE (op0);
3363e4b17023SJohn Marino       unsigned op0_n_elts = GET_MODE_NUNITS (op0mode);
3364e4b17023SJohn Marino       enum machine_mode op1mode = GET_MODE (op1);
3365e4b17023SJohn Marino       unsigned op1_n_elts = GET_MODE_NUNITS (op1mode);
3366e4b17023SJohn Marino       rtvec v = rtvec_alloc (n_elts);
3367e4b17023SJohn Marino       unsigned int i;
3368e4b17023SJohn Marino 
3369e4b17023SJohn Marino       gcc_assert (op0_n_elts == n_elts);
3370e4b17023SJohn Marino       gcc_assert (op1_n_elts == n_elts);
3371e4b17023SJohn Marino       for (i = 0; i < n_elts; i++)
3372e4b17023SJohn Marino 	{
3373e4b17023SJohn Marino 	  rtx x = simplify_binary_operation (code, GET_MODE_INNER (mode),
3374e4b17023SJohn Marino 					     CONST_VECTOR_ELT (op0, i),
3375e4b17023SJohn Marino 					     CONST_VECTOR_ELT (op1, i));
3376e4b17023SJohn Marino 	  if (!x)
3377e4b17023SJohn Marino 	    return 0;
3378e4b17023SJohn Marino 	  RTVEC_ELT (v, i) = x;
3379e4b17023SJohn Marino 	}
3380e4b17023SJohn Marino 
3381e4b17023SJohn Marino       return gen_rtx_CONST_VECTOR (mode, v);
3382e4b17023SJohn Marino     }
3383e4b17023SJohn Marino 
3384e4b17023SJohn Marino   if (VECTOR_MODE_P (mode)
3385e4b17023SJohn Marino       && code == VEC_CONCAT
3386e4b17023SJohn Marino       && (CONST_INT_P (op0)
3387e4b17023SJohn Marino 	  || GET_CODE (op0) == CONST_DOUBLE
3388e4b17023SJohn Marino 	  || GET_CODE (op0) == CONST_FIXED)
3389e4b17023SJohn Marino       && (CONST_INT_P (op1)
3390e4b17023SJohn Marino 	  || GET_CODE (op1) == CONST_DOUBLE
3391e4b17023SJohn Marino 	  || GET_CODE (op1) == CONST_FIXED))
3392e4b17023SJohn Marino     {
3393e4b17023SJohn Marino       unsigned n_elts = GET_MODE_NUNITS (mode);
3394e4b17023SJohn Marino       rtvec v = rtvec_alloc (n_elts);
3395e4b17023SJohn Marino 
3396e4b17023SJohn Marino       gcc_assert (n_elts >= 2);
3397e4b17023SJohn Marino       if (n_elts == 2)
3398e4b17023SJohn Marino 	{
3399e4b17023SJohn Marino 	  gcc_assert (GET_CODE (op0) != CONST_VECTOR);
3400e4b17023SJohn Marino 	  gcc_assert (GET_CODE (op1) != CONST_VECTOR);
3401e4b17023SJohn Marino 
3402e4b17023SJohn Marino 	  RTVEC_ELT (v, 0) = op0;
3403e4b17023SJohn Marino 	  RTVEC_ELT (v, 1) = op1;
3404e4b17023SJohn Marino 	}
3405e4b17023SJohn Marino       else
3406e4b17023SJohn Marino 	{
3407e4b17023SJohn Marino 	  unsigned op0_n_elts = GET_MODE_NUNITS (GET_MODE (op0));
3408e4b17023SJohn Marino 	  unsigned op1_n_elts = GET_MODE_NUNITS (GET_MODE (op1));
3409e4b17023SJohn Marino 	  unsigned i;
3410e4b17023SJohn Marino 
3411e4b17023SJohn Marino 	  gcc_assert (GET_CODE (op0) == CONST_VECTOR);
3412e4b17023SJohn Marino 	  gcc_assert (GET_CODE (op1) == CONST_VECTOR);
3413e4b17023SJohn Marino 	  gcc_assert (op0_n_elts + op1_n_elts == n_elts);
3414e4b17023SJohn Marino 
3415e4b17023SJohn Marino 	  for (i = 0; i < op0_n_elts; ++i)
3416e4b17023SJohn Marino 	    RTVEC_ELT (v, i) = XVECEXP (op0, 0, i);
3417e4b17023SJohn Marino 	  for (i = 0; i < op1_n_elts; ++i)
3418e4b17023SJohn Marino 	    RTVEC_ELT (v, op0_n_elts+i) = XVECEXP (op1, 0, i);
3419e4b17023SJohn Marino 	}
3420e4b17023SJohn Marino 
3421e4b17023SJohn Marino       return gen_rtx_CONST_VECTOR (mode, v);
3422e4b17023SJohn Marino     }
3423e4b17023SJohn Marino 
3424e4b17023SJohn Marino   if (SCALAR_FLOAT_MODE_P (mode)
3425e4b17023SJohn Marino       && GET_CODE (op0) == CONST_DOUBLE
3426e4b17023SJohn Marino       && GET_CODE (op1) == CONST_DOUBLE
3427e4b17023SJohn Marino       && mode == GET_MODE (op0) && mode == GET_MODE (op1))
3428e4b17023SJohn Marino     {
3429e4b17023SJohn Marino       if (code == AND
3430e4b17023SJohn Marino 	  || code == IOR
3431e4b17023SJohn Marino 	  || code == XOR)
3432e4b17023SJohn Marino 	{
3433e4b17023SJohn Marino 	  long tmp0[4];
3434e4b17023SJohn Marino 	  long tmp1[4];
3435e4b17023SJohn Marino 	  REAL_VALUE_TYPE r;
3436e4b17023SJohn Marino 	  int i;
3437e4b17023SJohn Marino 
3438e4b17023SJohn Marino 	  real_to_target (tmp0, CONST_DOUBLE_REAL_VALUE (op0),
3439e4b17023SJohn Marino 			  GET_MODE (op0));
3440e4b17023SJohn Marino 	  real_to_target (tmp1, CONST_DOUBLE_REAL_VALUE (op1),
3441e4b17023SJohn Marino 			  GET_MODE (op1));
3442e4b17023SJohn Marino 	  for (i = 0; i < 4; i++)
3443e4b17023SJohn Marino 	    {
3444e4b17023SJohn Marino 	      switch (code)
3445e4b17023SJohn Marino 	      {
3446e4b17023SJohn Marino 	      case AND:
3447e4b17023SJohn Marino 		tmp0[i] &= tmp1[i];
3448e4b17023SJohn Marino 		break;
3449e4b17023SJohn Marino 	      case IOR:
3450e4b17023SJohn Marino 		tmp0[i] |= tmp1[i];
3451e4b17023SJohn Marino 		break;
3452e4b17023SJohn Marino 	      case XOR:
3453e4b17023SJohn Marino 		tmp0[i] ^= tmp1[i];
3454e4b17023SJohn Marino 		break;
3455e4b17023SJohn Marino 	      default:
3456e4b17023SJohn Marino 		gcc_unreachable ();
3457e4b17023SJohn Marino 	      }
3458e4b17023SJohn Marino 	    }
3459e4b17023SJohn Marino 	   real_from_target (&r, tmp0, mode);
3460e4b17023SJohn Marino 	   return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
3461e4b17023SJohn Marino 	}
3462e4b17023SJohn Marino       else
3463e4b17023SJohn Marino 	{
3464e4b17023SJohn Marino 	  REAL_VALUE_TYPE f0, f1, value, result;
3465e4b17023SJohn Marino 	  bool inexact;
3466e4b17023SJohn Marino 
3467e4b17023SJohn Marino 	  REAL_VALUE_FROM_CONST_DOUBLE (f0, op0);
3468e4b17023SJohn Marino 	  REAL_VALUE_FROM_CONST_DOUBLE (f1, op1);
3469e4b17023SJohn Marino 	  real_convert (&f0, mode, &f0);
3470e4b17023SJohn Marino 	  real_convert (&f1, mode, &f1);
3471e4b17023SJohn Marino 
3472e4b17023SJohn Marino 	  if (HONOR_SNANS (mode)
3473e4b17023SJohn Marino 	      && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
3474e4b17023SJohn Marino 	    return 0;
3475e4b17023SJohn Marino 
3476e4b17023SJohn Marino 	  if (code == DIV
3477e4b17023SJohn Marino 	      && REAL_VALUES_EQUAL (f1, dconst0)
3478e4b17023SJohn Marino 	      && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
3479e4b17023SJohn Marino 	    return 0;
3480e4b17023SJohn Marino 
3481e4b17023SJohn Marino 	  if (MODE_HAS_INFINITIES (mode) && HONOR_NANS (mode)
3482e4b17023SJohn Marino 	      && flag_trapping_math
3483e4b17023SJohn Marino 	      && REAL_VALUE_ISINF (f0) && REAL_VALUE_ISINF (f1))
3484e4b17023SJohn Marino 	    {
3485e4b17023SJohn Marino 	      int s0 = REAL_VALUE_NEGATIVE (f0);
3486e4b17023SJohn Marino 	      int s1 = REAL_VALUE_NEGATIVE (f1);
3487e4b17023SJohn Marino 
3488e4b17023SJohn Marino 	      switch (code)
3489e4b17023SJohn Marino 		{
3490e4b17023SJohn Marino 		case PLUS:
3491e4b17023SJohn Marino 		  /* Inf + -Inf = NaN plus exception.  */
3492e4b17023SJohn Marino 		  if (s0 != s1)
3493e4b17023SJohn Marino 		    return 0;
3494e4b17023SJohn Marino 		  break;
3495e4b17023SJohn Marino 		case MINUS:
3496e4b17023SJohn Marino 		  /* Inf - Inf = NaN plus exception.  */
3497e4b17023SJohn Marino 		  if (s0 == s1)
3498e4b17023SJohn Marino 		    return 0;
3499e4b17023SJohn Marino 		  break;
3500e4b17023SJohn Marino 		case DIV:
3501e4b17023SJohn Marino 		  /* Inf / Inf = NaN plus exception.  */
3502e4b17023SJohn Marino 		  return 0;
3503e4b17023SJohn Marino 		default:
3504e4b17023SJohn Marino 		  break;
3505e4b17023SJohn Marino 		}
3506e4b17023SJohn Marino 	    }
3507e4b17023SJohn Marino 
3508e4b17023SJohn Marino 	  if (code == MULT && MODE_HAS_INFINITIES (mode) && HONOR_NANS (mode)
3509e4b17023SJohn Marino 	      && flag_trapping_math
3510e4b17023SJohn Marino 	      && ((REAL_VALUE_ISINF (f0) && REAL_VALUES_EQUAL (f1, dconst0))
3511e4b17023SJohn Marino 		  || (REAL_VALUE_ISINF (f1)
3512e4b17023SJohn Marino 		      && REAL_VALUES_EQUAL (f0, dconst0))))
3513e4b17023SJohn Marino 	    /* Inf * 0 = NaN plus exception.  */
3514e4b17023SJohn Marino 	    return 0;
3515e4b17023SJohn Marino 
3516e4b17023SJohn Marino 	  inexact = real_arithmetic (&value, rtx_to_tree_code (code),
3517e4b17023SJohn Marino 				     &f0, &f1);
3518e4b17023SJohn Marino 	  real_convert (&result, mode, &value);
3519e4b17023SJohn Marino 
3520e4b17023SJohn Marino 	  /* Don't constant fold this floating point operation if
3521e4b17023SJohn Marino 	     the result has overflowed and flag_trapping_math.  */
3522e4b17023SJohn Marino 
3523e4b17023SJohn Marino 	  if (flag_trapping_math
3524e4b17023SJohn Marino 	      && MODE_HAS_INFINITIES (mode)
3525e4b17023SJohn Marino 	      && REAL_VALUE_ISINF (result)
3526e4b17023SJohn Marino 	      && !REAL_VALUE_ISINF (f0)
3527e4b17023SJohn Marino 	      && !REAL_VALUE_ISINF (f1))
3528e4b17023SJohn Marino 	    /* Overflow plus exception.  */
3529e4b17023SJohn Marino 	    return 0;
3530e4b17023SJohn Marino 
3531e4b17023SJohn Marino 	  /* Don't constant fold this floating point operation if the
3532e4b17023SJohn Marino 	     result may dependent upon the run-time rounding mode and
3533e4b17023SJohn Marino 	     flag_rounding_math is set, or if GCC's software emulation
3534e4b17023SJohn Marino 	     is unable to accurately represent the result.  */
3535e4b17023SJohn Marino 
3536e4b17023SJohn Marino 	  if ((flag_rounding_math
3537e4b17023SJohn Marino 	       || (MODE_COMPOSITE_P (mode) && !flag_unsafe_math_optimizations))
3538e4b17023SJohn Marino 	      && (inexact || !real_identical (&result, &value)))
3539e4b17023SJohn Marino 	    return NULL_RTX;
3540e4b17023SJohn Marino 
3541e4b17023SJohn Marino 	  return CONST_DOUBLE_FROM_REAL_VALUE (result, mode);
3542e4b17023SJohn Marino 	}
3543e4b17023SJohn Marino     }
3544e4b17023SJohn Marino 
3545e4b17023SJohn Marino   /* We can fold some multi-word operations.  */
3546e4b17023SJohn Marino   if (GET_MODE_CLASS (mode) == MODE_INT
3547e4b17023SJohn Marino       && width == HOST_BITS_PER_DOUBLE_INT
3548e4b17023SJohn Marino       && (CONST_DOUBLE_P (op0) || CONST_INT_P (op0))
3549e4b17023SJohn Marino       && (CONST_DOUBLE_P (op1) || CONST_INT_P (op1)))
3550e4b17023SJohn Marino     {
3551e4b17023SJohn Marino       double_int o0, o1, res, tmp;
3552e4b17023SJohn Marino 
3553e4b17023SJohn Marino       o0 = rtx_to_double_int (op0);
3554e4b17023SJohn Marino       o1 = rtx_to_double_int (op1);
3555e4b17023SJohn Marino 
3556e4b17023SJohn Marino       switch (code)
3557e4b17023SJohn Marino 	{
3558e4b17023SJohn Marino 	case MINUS:
3559e4b17023SJohn Marino 	  /* A - B == A + (-B).  */
3560e4b17023SJohn Marino 	  o1 = double_int_neg (o1);
3561e4b17023SJohn Marino 
3562e4b17023SJohn Marino 	  /* Fall through....  */
3563e4b17023SJohn Marino 
3564e4b17023SJohn Marino 	case PLUS:
3565e4b17023SJohn Marino 	  res = double_int_add (o0, o1);
3566e4b17023SJohn Marino 	  break;
3567e4b17023SJohn Marino 
3568e4b17023SJohn Marino 	case MULT:
3569e4b17023SJohn Marino 	  res = double_int_mul (o0, o1);
3570e4b17023SJohn Marino 	  break;
3571e4b17023SJohn Marino 
3572e4b17023SJohn Marino 	case DIV:
3573e4b17023SJohn Marino 	  if (div_and_round_double (TRUNC_DIV_EXPR, 0,
3574e4b17023SJohn Marino 				    o0.low, o0.high, o1.low, o1.high,
3575e4b17023SJohn Marino 				    &res.low, &res.high,
3576e4b17023SJohn Marino 				    &tmp.low, &tmp.high))
3577e4b17023SJohn Marino 	    return 0;
3578e4b17023SJohn Marino 	  break;
3579e4b17023SJohn Marino 
3580e4b17023SJohn Marino 	case MOD:
3581e4b17023SJohn Marino 	  if (div_and_round_double (TRUNC_DIV_EXPR, 0,
3582e4b17023SJohn Marino 				    o0.low, o0.high, o1.low, o1.high,
3583e4b17023SJohn Marino 				    &tmp.low, &tmp.high,
3584e4b17023SJohn Marino 				    &res.low, &res.high))
3585e4b17023SJohn Marino 	    return 0;
3586e4b17023SJohn Marino 	  break;
3587e4b17023SJohn Marino 
3588e4b17023SJohn Marino 	case UDIV:
3589e4b17023SJohn Marino 	  if (div_and_round_double (TRUNC_DIV_EXPR, 1,
3590e4b17023SJohn Marino 				    o0.low, o0.high, o1.low, o1.high,
3591e4b17023SJohn Marino 				    &res.low, &res.high,
3592e4b17023SJohn Marino 				    &tmp.low, &tmp.high))
3593e4b17023SJohn Marino 	    return 0;
3594e4b17023SJohn Marino 	  break;
3595e4b17023SJohn Marino 
3596e4b17023SJohn Marino 	case UMOD:
3597e4b17023SJohn Marino 	  if (div_and_round_double (TRUNC_DIV_EXPR, 1,
3598e4b17023SJohn Marino 				    o0.low, o0.high, o1.low, o1.high,
3599e4b17023SJohn Marino 				    &tmp.low, &tmp.high,
3600e4b17023SJohn Marino 				    &res.low, &res.high))
3601e4b17023SJohn Marino 	    return 0;
3602e4b17023SJohn Marino 	  break;
3603e4b17023SJohn Marino 
3604e4b17023SJohn Marino 	case AND:
3605e4b17023SJohn Marino 	  res = double_int_and (o0, o1);
3606e4b17023SJohn Marino 	  break;
3607e4b17023SJohn Marino 
3608e4b17023SJohn Marino 	case IOR:
3609e4b17023SJohn Marino 	  res = double_int_ior (o0, o1);
3610e4b17023SJohn Marino 	  break;
3611e4b17023SJohn Marino 
3612e4b17023SJohn Marino 	case XOR:
3613e4b17023SJohn Marino 	  res = double_int_xor (o0, o1);
3614e4b17023SJohn Marino 	  break;
3615e4b17023SJohn Marino 
3616e4b17023SJohn Marino 	case SMIN:
3617e4b17023SJohn Marino 	  res = double_int_smin (o0, o1);
3618e4b17023SJohn Marino 	  break;
3619e4b17023SJohn Marino 
3620e4b17023SJohn Marino 	case SMAX:
3621e4b17023SJohn Marino 	  res = double_int_smax (o0, o1);
3622e4b17023SJohn Marino 	  break;
3623e4b17023SJohn Marino 
3624e4b17023SJohn Marino 	case UMIN:
3625e4b17023SJohn Marino 	  res = double_int_umin (o0, o1);
3626e4b17023SJohn Marino 	  break;
3627e4b17023SJohn Marino 
3628e4b17023SJohn Marino 	case UMAX:
3629e4b17023SJohn Marino 	  res = double_int_umax (o0, o1);
3630e4b17023SJohn Marino 	  break;
3631e4b17023SJohn Marino 
3632e4b17023SJohn Marino 	case LSHIFTRT:   case ASHIFTRT:
3633e4b17023SJohn Marino 	case ASHIFT:
3634e4b17023SJohn Marino 	case ROTATE:     case ROTATERT:
3635e4b17023SJohn Marino 	  {
3636e4b17023SJohn Marino 	    unsigned HOST_WIDE_INT cnt;
3637e4b17023SJohn Marino 
3638e4b17023SJohn Marino 	    if (SHIFT_COUNT_TRUNCATED)
3639e4b17023SJohn Marino 	      o1 = double_int_zext (o1, GET_MODE_PRECISION (mode));
3640e4b17023SJohn Marino 
3641e4b17023SJohn Marino 	    if (!double_int_fits_in_uhwi_p (o1)
3642e4b17023SJohn Marino 	        || double_int_to_uhwi (o1) >= GET_MODE_PRECISION (mode))
3643e4b17023SJohn Marino 	      return 0;
3644e4b17023SJohn Marino 
3645e4b17023SJohn Marino 	    cnt = double_int_to_uhwi (o1);
3646e4b17023SJohn Marino 
3647e4b17023SJohn Marino 	    if (code == LSHIFTRT || code == ASHIFTRT)
3648e4b17023SJohn Marino 	      res = double_int_rshift (o0, cnt, GET_MODE_PRECISION (mode),
3649e4b17023SJohn Marino 				       code == ASHIFTRT);
3650e4b17023SJohn Marino 	    else if (code == ASHIFT)
3651e4b17023SJohn Marino 	      res = double_int_lshift (o0, cnt, GET_MODE_PRECISION (mode),
3652e4b17023SJohn Marino 				       true);
3653e4b17023SJohn Marino 	    else if (code == ROTATE)
3654e4b17023SJohn Marino 	      res = double_int_lrotate (o0, cnt, GET_MODE_PRECISION (mode));
3655e4b17023SJohn Marino 	    else /* code == ROTATERT */
3656e4b17023SJohn Marino 	      res = double_int_rrotate (o0, cnt, GET_MODE_PRECISION (mode));
3657e4b17023SJohn Marino 	  }
3658e4b17023SJohn Marino 	  break;
3659e4b17023SJohn Marino 
3660e4b17023SJohn Marino 	default:
3661e4b17023SJohn Marino 	  return 0;
3662e4b17023SJohn Marino 	}
3663e4b17023SJohn Marino 
3664e4b17023SJohn Marino       return immed_double_int_const (res, mode);
3665e4b17023SJohn Marino     }
3666e4b17023SJohn Marino 
3667e4b17023SJohn Marino   if (CONST_INT_P (op0) && CONST_INT_P (op1)
3668e4b17023SJohn Marino       && width <= HOST_BITS_PER_WIDE_INT && width != 0)
3669e4b17023SJohn Marino     {
3670e4b17023SJohn Marino       /* Get the integer argument values in two forms:
3671e4b17023SJohn Marino          zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
3672e4b17023SJohn Marino 
3673e4b17023SJohn Marino       arg0 = INTVAL (op0);
3674e4b17023SJohn Marino       arg1 = INTVAL (op1);
3675e4b17023SJohn Marino 
3676e4b17023SJohn Marino       if (width < HOST_BITS_PER_WIDE_INT)
3677e4b17023SJohn Marino         {
3678e4b17023SJohn Marino           arg0 &= GET_MODE_MASK (mode);
3679e4b17023SJohn Marino           arg1 &= GET_MODE_MASK (mode);
3680e4b17023SJohn Marino 
3681e4b17023SJohn Marino           arg0s = arg0;
3682e4b17023SJohn Marino 	  if (val_signbit_known_set_p (mode, arg0s))
3683e4b17023SJohn Marino 	    arg0s |= ~GET_MODE_MASK (mode);
3684e4b17023SJohn Marino 
3685e4b17023SJohn Marino           arg1s = arg1;
3686e4b17023SJohn Marino 	  if (val_signbit_known_set_p (mode, arg1s))
3687e4b17023SJohn Marino 	    arg1s |= ~GET_MODE_MASK (mode);
3688e4b17023SJohn Marino 	}
3689e4b17023SJohn Marino       else
3690e4b17023SJohn Marino 	{
3691e4b17023SJohn Marino 	  arg0s = arg0;
3692e4b17023SJohn Marino 	  arg1s = arg1;
3693e4b17023SJohn Marino 	}
3694e4b17023SJohn Marino 
3695e4b17023SJohn Marino       /* Compute the value of the arithmetic.  */
3696e4b17023SJohn Marino 
3697e4b17023SJohn Marino       switch (code)
3698e4b17023SJohn Marino 	{
3699e4b17023SJohn Marino 	case PLUS:
3700e4b17023SJohn Marino 	  val = arg0s + arg1s;
3701e4b17023SJohn Marino 	  break;
3702e4b17023SJohn Marino 
3703e4b17023SJohn Marino 	case MINUS:
3704e4b17023SJohn Marino 	  val = arg0s - arg1s;
3705e4b17023SJohn Marino 	  break;
3706e4b17023SJohn Marino 
3707e4b17023SJohn Marino 	case MULT:
3708e4b17023SJohn Marino 	  val = arg0s * arg1s;
3709e4b17023SJohn Marino 	  break;
3710e4b17023SJohn Marino 
3711e4b17023SJohn Marino 	case DIV:
3712e4b17023SJohn Marino 	  if (arg1s == 0
3713e4b17023SJohn Marino 	      || ((unsigned HOST_WIDE_INT) arg0s
3714e4b17023SJohn Marino 		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3715e4b17023SJohn Marino 		  && arg1s == -1))
3716e4b17023SJohn Marino 	    return 0;
3717e4b17023SJohn Marino 	  val = arg0s / arg1s;
3718e4b17023SJohn Marino 	  break;
3719e4b17023SJohn Marino 
3720e4b17023SJohn Marino 	case MOD:
3721e4b17023SJohn Marino 	  if (arg1s == 0
3722e4b17023SJohn Marino 	      || ((unsigned HOST_WIDE_INT) arg0s
3723e4b17023SJohn Marino 		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3724e4b17023SJohn Marino 		  && arg1s == -1))
3725e4b17023SJohn Marino 	    return 0;
3726e4b17023SJohn Marino 	  val = arg0s % arg1s;
3727e4b17023SJohn Marino 	  break;
3728e4b17023SJohn Marino 
3729e4b17023SJohn Marino 	case UDIV:
3730e4b17023SJohn Marino 	  if (arg1 == 0
3731e4b17023SJohn Marino 	      || ((unsigned HOST_WIDE_INT) arg0s
3732e4b17023SJohn Marino 		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3733e4b17023SJohn Marino 		  && arg1s == -1))
3734e4b17023SJohn Marino 	    return 0;
3735e4b17023SJohn Marino 	  val = (unsigned HOST_WIDE_INT) arg0 / arg1;
3736e4b17023SJohn Marino 	  break;
3737e4b17023SJohn Marino 
3738e4b17023SJohn Marino 	case UMOD:
3739e4b17023SJohn Marino 	  if (arg1 == 0
3740e4b17023SJohn Marino 	      || ((unsigned HOST_WIDE_INT) arg0s
3741e4b17023SJohn Marino 		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
3742e4b17023SJohn Marino 		  && arg1s == -1))
3743e4b17023SJohn Marino 	    return 0;
3744e4b17023SJohn Marino 	  val = (unsigned HOST_WIDE_INT) arg0 % arg1;
3745e4b17023SJohn Marino 	  break;
3746e4b17023SJohn Marino 
3747e4b17023SJohn Marino 	case AND:
3748e4b17023SJohn Marino 	  val = arg0 & arg1;
3749e4b17023SJohn Marino 	  break;
3750e4b17023SJohn Marino 
3751e4b17023SJohn Marino 	case IOR:
3752e4b17023SJohn Marino 	  val = arg0 | arg1;
3753e4b17023SJohn Marino 	  break;
3754e4b17023SJohn Marino 
3755e4b17023SJohn Marino 	case XOR:
3756e4b17023SJohn Marino 	  val = arg0 ^ arg1;
3757e4b17023SJohn Marino 	  break;
3758e4b17023SJohn Marino 
3759e4b17023SJohn Marino 	case LSHIFTRT:
3760e4b17023SJohn Marino 	case ASHIFT:
3761e4b17023SJohn Marino 	case ASHIFTRT:
3762e4b17023SJohn Marino 	  /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
3763e4b17023SJohn Marino 	     the value is in range.  We can't return any old value for
3764e4b17023SJohn Marino 	     out-of-range arguments because either the middle-end (via
3765e4b17023SJohn Marino 	     shift_truncation_mask) or the back-end might be relying on
3766e4b17023SJohn Marino 	     target-specific knowledge.  Nor can we rely on
3767e4b17023SJohn Marino 	     shift_truncation_mask, since the shift might not be part of an
3768e4b17023SJohn Marino 	     ashlM3, lshrM3 or ashrM3 instruction.  */
3769e4b17023SJohn Marino 	  if (SHIFT_COUNT_TRUNCATED)
3770e4b17023SJohn Marino 	    arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
3771e4b17023SJohn Marino 	  else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
3772e4b17023SJohn Marino 	    return 0;
3773e4b17023SJohn Marino 
3774e4b17023SJohn Marino 	  val = (code == ASHIFT
3775e4b17023SJohn Marino 		 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
3776e4b17023SJohn Marino 		 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
3777e4b17023SJohn Marino 
3778e4b17023SJohn Marino 	  /* Sign-extend the result for arithmetic right shifts.  */
3779e4b17023SJohn Marino 	  if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
3780e4b17023SJohn Marino 	    val |= ((unsigned HOST_WIDE_INT) (-1)) << (width - arg1);
3781e4b17023SJohn Marino 	  break;
3782e4b17023SJohn Marino 
3783e4b17023SJohn Marino 	case ROTATERT:
3784e4b17023SJohn Marino 	  if (arg1 < 0)
3785e4b17023SJohn Marino 	    return 0;
3786e4b17023SJohn Marino 
3787e4b17023SJohn Marino 	  arg1 %= width;
3788e4b17023SJohn Marino 	  val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
3789e4b17023SJohn Marino 		 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
3790e4b17023SJohn Marino 	  break;
3791e4b17023SJohn Marino 
3792e4b17023SJohn Marino 	case ROTATE:
3793e4b17023SJohn Marino 	  if (arg1 < 0)
3794e4b17023SJohn Marino 	    return 0;
3795e4b17023SJohn Marino 
3796e4b17023SJohn Marino 	  arg1 %= width;
3797e4b17023SJohn Marino 	  val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
3798e4b17023SJohn Marino 		 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
3799e4b17023SJohn Marino 	  break;
3800e4b17023SJohn Marino 
3801e4b17023SJohn Marino 	case COMPARE:
3802e4b17023SJohn Marino 	  /* Do nothing here.  */
3803e4b17023SJohn Marino 	  return 0;
3804e4b17023SJohn Marino 
3805e4b17023SJohn Marino 	case SMIN:
3806e4b17023SJohn Marino 	  val = arg0s <= arg1s ? arg0s : arg1s;
3807e4b17023SJohn Marino 	  break;
3808e4b17023SJohn Marino 
3809e4b17023SJohn Marino 	case UMIN:
3810e4b17023SJohn Marino 	  val = ((unsigned HOST_WIDE_INT) arg0
3811e4b17023SJohn Marino 		 <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
3812e4b17023SJohn Marino 	  break;
3813e4b17023SJohn Marino 
3814e4b17023SJohn Marino 	case SMAX:
3815e4b17023SJohn Marino 	  val = arg0s > arg1s ? arg0s : arg1s;
3816e4b17023SJohn Marino 	  break;
3817e4b17023SJohn Marino 
3818e4b17023SJohn Marino 	case UMAX:
3819e4b17023SJohn Marino 	  val = ((unsigned HOST_WIDE_INT) arg0
3820e4b17023SJohn Marino 		 > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
3821e4b17023SJohn Marino 	  break;
3822e4b17023SJohn Marino 
3823e4b17023SJohn Marino 	case SS_PLUS:
3824e4b17023SJohn Marino 	case US_PLUS:
3825e4b17023SJohn Marino 	case SS_MINUS:
3826e4b17023SJohn Marino 	case US_MINUS:
3827e4b17023SJohn Marino 	case SS_MULT:
3828e4b17023SJohn Marino 	case US_MULT:
3829e4b17023SJohn Marino 	case SS_DIV:
3830e4b17023SJohn Marino 	case US_DIV:
3831e4b17023SJohn Marino 	case SS_ASHIFT:
3832e4b17023SJohn Marino 	case US_ASHIFT:
3833e4b17023SJohn Marino 	  /* ??? There are simplifications that can be done.  */
3834e4b17023SJohn Marino 	  return 0;
3835e4b17023SJohn Marino 
3836e4b17023SJohn Marino 	default:
3837e4b17023SJohn Marino 	  gcc_unreachable ();
3838e4b17023SJohn Marino 	}
3839e4b17023SJohn Marino 
3840e4b17023SJohn Marino       return gen_int_mode (val, mode);
3841e4b17023SJohn Marino     }
3842e4b17023SJohn Marino 
3843e4b17023SJohn Marino   return NULL_RTX;
3844e4b17023SJohn Marino }
3845e4b17023SJohn Marino 
3846e4b17023SJohn Marino 
3847e4b17023SJohn Marino 
3848e4b17023SJohn Marino /* Simplify a PLUS or MINUS, at least one of whose operands may be another
3849e4b17023SJohn Marino    PLUS or MINUS.
3850e4b17023SJohn Marino 
3851e4b17023SJohn Marino    Rather than test for specific case, we do this by a brute-force method
3852e4b17023SJohn Marino    and do all possible simplifications until no more changes occur.  Then
3853e4b17023SJohn Marino    we rebuild the operation.  */
3854e4b17023SJohn Marino 
3855e4b17023SJohn Marino struct simplify_plus_minus_op_data
3856e4b17023SJohn Marino {
3857e4b17023SJohn Marino   rtx op;
3858e4b17023SJohn Marino   short neg;
3859e4b17023SJohn Marino };
3860e4b17023SJohn Marino 
3861e4b17023SJohn Marino static bool
simplify_plus_minus_op_data_cmp(rtx x,rtx y)3862e4b17023SJohn Marino simplify_plus_minus_op_data_cmp (rtx x, rtx y)
3863e4b17023SJohn Marino {
3864e4b17023SJohn Marino   int result;
3865e4b17023SJohn Marino 
3866e4b17023SJohn Marino   result = (commutative_operand_precedence (y)
3867e4b17023SJohn Marino 	    - commutative_operand_precedence (x));
3868e4b17023SJohn Marino   if (result)
3869e4b17023SJohn Marino     return result > 0;
3870e4b17023SJohn Marino 
3871e4b17023SJohn Marino   /* Group together equal REGs to do more simplification.  */
3872e4b17023SJohn Marino   if (REG_P (x) && REG_P (y))
3873e4b17023SJohn Marino     return REGNO (x) > REGNO (y);
3874e4b17023SJohn Marino   else
3875e4b17023SJohn Marino     return false;
3876e4b17023SJohn Marino }
3877e4b17023SJohn Marino 
3878e4b17023SJohn Marino static rtx
simplify_plus_minus(enum rtx_code code,enum machine_mode mode,rtx op0,rtx op1)3879e4b17023SJohn Marino simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
3880e4b17023SJohn Marino 		     rtx op1)
3881e4b17023SJohn Marino {
3882e4b17023SJohn Marino   struct simplify_plus_minus_op_data ops[8];
3883e4b17023SJohn Marino   rtx result, tem;
3884e4b17023SJohn Marino   int n_ops = 2, input_ops = 2;
3885e4b17023SJohn Marino   int changed, n_constants = 0, canonicalized = 0;
3886e4b17023SJohn Marino   int i, j;
3887e4b17023SJohn Marino 
3888e4b17023SJohn Marino   memset (ops, 0, sizeof ops);
3889e4b17023SJohn Marino 
3890e4b17023SJohn Marino   /* Set up the two operands and then expand them until nothing has been
3891e4b17023SJohn Marino      changed.  If we run out of room in our array, give up; this should
3892e4b17023SJohn Marino      almost never happen.  */
3893e4b17023SJohn Marino 
3894e4b17023SJohn Marino   ops[0].op = op0;
3895e4b17023SJohn Marino   ops[0].neg = 0;
3896e4b17023SJohn Marino   ops[1].op = op1;
3897e4b17023SJohn Marino   ops[1].neg = (code == MINUS);
3898e4b17023SJohn Marino 
3899e4b17023SJohn Marino   do
3900e4b17023SJohn Marino     {
3901e4b17023SJohn Marino       changed = 0;
3902e4b17023SJohn Marino 
3903e4b17023SJohn Marino       for (i = 0; i < n_ops; i++)
3904e4b17023SJohn Marino 	{
3905e4b17023SJohn Marino 	  rtx this_op = ops[i].op;
3906e4b17023SJohn Marino 	  int this_neg = ops[i].neg;
3907e4b17023SJohn Marino 	  enum rtx_code this_code = GET_CODE (this_op);
3908e4b17023SJohn Marino 
3909e4b17023SJohn Marino 	  switch (this_code)
3910e4b17023SJohn Marino 	    {
3911e4b17023SJohn Marino 	    case PLUS:
3912e4b17023SJohn Marino 	    case MINUS:
3913e4b17023SJohn Marino 	      if (n_ops == 7)
3914e4b17023SJohn Marino 		return NULL_RTX;
3915e4b17023SJohn Marino 
3916e4b17023SJohn Marino 	      ops[n_ops].op = XEXP (this_op, 1);
3917e4b17023SJohn Marino 	      ops[n_ops].neg = (this_code == MINUS) ^ this_neg;
3918e4b17023SJohn Marino 	      n_ops++;
3919e4b17023SJohn Marino 
3920e4b17023SJohn Marino 	      ops[i].op = XEXP (this_op, 0);
3921e4b17023SJohn Marino 	      input_ops++;
3922e4b17023SJohn Marino 	      changed = 1;
3923e4b17023SJohn Marino 	      canonicalized |= this_neg;
3924e4b17023SJohn Marino 	      break;
3925e4b17023SJohn Marino 
3926e4b17023SJohn Marino 	    case NEG:
3927e4b17023SJohn Marino 	      ops[i].op = XEXP (this_op, 0);
3928e4b17023SJohn Marino 	      ops[i].neg = ! this_neg;
3929e4b17023SJohn Marino 	      changed = 1;
3930e4b17023SJohn Marino 	      canonicalized = 1;
3931e4b17023SJohn Marino 	      break;
3932e4b17023SJohn Marino 
3933e4b17023SJohn Marino 	    case CONST:
3934e4b17023SJohn Marino 	      if (n_ops < 7
3935e4b17023SJohn Marino 		  && GET_CODE (XEXP (this_op, 0)) == PLUS
3936e4b17023SJohn Marino 		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 0))
3937e4b17023SJohn Marino 		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 1)))
3938e4b17023SJohn Marino 		{
3939e4b17023SJohn Marino 		  ops[i].op = XEXP (XEXP (this_op, 0), 0);
3940e4b17023SJohn Marino 		  ops[n_ops].op = XEXP (XEXP (this_op, 0), 1);
3941e4b17023SJohn Marino 		  ops[n_ops].neg = this_neg;
3942e4b17023SJohn Marino 		  n_ops++;
3943e4b17023SJohn Marino 		  changed = 1;
3944e4b17023SJohn Marino 	          canonicalized = 1;
3945e4b17023SJohn Marino 		}
3946e4b17023SJohn Marino 	      break;
3947e4b17023SJohn Marino 
3948e4b17023SJohn Marino 	    case NOT:
3949e4b17023SJohn Marino 	      /* ~a -> (-a - 1) */
3950e4b17023SJohn Marino 	      if (n_ops != 7)
3951e4b17023SJohn Marino 		{
3952e4b17023SJohn Marino 		  ops[n_ops].op = CONSTM1_RTX (mode);
3953e4b17023SJohn Marino 		  ops[n_ops++].neg = this_neg;
3954e4b17023SJohn Marino 		  ops[i].op = XEXP (this_op, 0);
3955e4b17023SJohn Marino 		  ops[i].neg = !this_neg;
3956e4b17023SJohn Marino 		  changed = 1;
3957e4b17023SJohn Marino 	          canonicalized = 1;
3958e4b17023SJohn Marino 		}
3959e4b17023SJohn Marino 	      break;
3960e4b17023SJohn Marino 
3961e4b17023SJohn Marino 	    case CONST_INT:
3962e4b17023SJohn Marino 	      n_constants++;
3963e4b17023SJohn Marino 	      if (this_neg)
3964e4b17023SJohn Marino 		{
3965e4b17023SJohn Marino 		  ops[i].op = neg_const_int (mode, this_op);
3966e4b17023SJohn Marino 		  ops[i].neg = 0;
3967e4b17023SJohn Marino 		  changed = 1;
3968e4b17023SJohn Marino 	          canonicalized = 1;
3969e4b17023SJohn Marino 		}
3970e4b17023SJohn Marino 	      break;
3971e4b17023SJohn Marino 
3972e4b17023SJohn Marino 	    default:
3973e4b17023SJohn Marino 	      break;
3974e4b17023SJohn Marino 	    }
3975e4b17023SJohn Marino 	}
3976e4b17023SJohn Marino     }
3977e4b17023SJohn Marino   while (changed);
3978e4b17023SJohn Marino 
3979e4b17023SJohn Marino   if (n_constants > 1)
3980e4b17023SJohn Marino     canonicalized = 1;
3981e4b17023SJohn Marino 
3982e4b17023SJohn Marino   gcc_assert (n_ops >= 2);
3983e4b17023SJohn Marino 
3984e4b17023SJohn Marino   /* If we only have two operands, we can avoid the loops.  */
3985e4b17023SJohn Marino   if (n_ops == 2)
3986e4b17023SJohn Marino     {
3987e4b17023SJohn Marino       enum rtx_code code = ops[0].neg || ops[1].neg ? MINUS : PLUS;
3988e4b17023SJohn Marino       rtx lhs, rhs;
3989e4b17023SJohn Marino 
3990e4b17023SJohn Marino       /* Get the two operands.  Be careful with the order, especially for
3991e4b17023SJohn Marino 	 the cases where code == MINUS.  */
3992e4b17023SJohn Marino       if (ops[0].neg && ops[1].neg)
3993e4b17023SJohn Marino 	{
3994e4b17023SJohn Marino 	  lhs = gen_rtx_NEG (mode, ops[0].op);
3995e4b17023SJohn Marino 	  rhs = ops[1].op;
3996e4b17023SJohn Marino 	}
3997e4b17023SJohn Marino       else if (ops[0].neg)
3998e4b17023SJohn Marino 	{
3999e4b17023SJohn Marino 	  lhs = ops[1].op;
4000e4b17023SJohn Marino 	  rhs = ops[0].op;
4001e4b17023SJohn Marino 	}
4002e4b17023SJohn Marino       else
4003e4b17023SJohn Marino 	{
4004e4b17023SJohn Marino 	  lhs = ops[0].op;
4005e4b17023SJohn Marino 	  rhs = ops[1].op;
4006e4b17023SJohn Marino 	}
4007e4b17023SJohn Marino 
4008e4b17023SJohn Marino       return simplify_const_binary_operation (code, mode, lhs, rhs);
4009e4b17023SJohn Marino     }
4010e4b17023SJohn Marino 
4011e4b17023SJohn Marino   /* Now simplify each pair of operands until nothing changes.  */
4012e4b17023SJohn Marino   do
4013e4b17023SJohn Marino     {
4014e4b17023SJohn Marino       /* Insertion sort is good enough for an eight-element array.  */
4015e4b17023SJohn Marino       for (i = 1; i < n_ops; i++)
4016e4b17023SJohn Marino         {
4017e4b17023SJohn Marino           struct simplify_plus_minus_op_data save;
4018e4b17023SJohn Marino           j = i - 1;
4019e4b17023SJohn Marino           if (!simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op))
4020e4b17023SJohn Marino 	    continue;
4021e4b17023SJohn Marino 
4022e4b17023SJohn Marino           canonicalized = 1;
4023e4b17023SJohn Marino           save = ops[i];
4024e4b17023SJohn Marino           do
4025e4b17023SJohn Marino 	    ops[j + 1] = ops[j];
4026e4b17023SJohn Marino           while (j-- && simplify_plus_minus_op_data_cmp (ops[j].op, save.op));
4027e4b17023SJohn Marino           ops[j + 1] = save;
4028e4b17023SJohn Marino         }
4029e4b17023SJohn Marino 
4030e4b17023SJohn Marino       changed = 0;
4031e4b17023SJohn Marino       for (i = n_ops - 1; i > 0; i--)
4032e4b17023SJohn Marino 	for (j = i - 1; j >= 0; j--)
4033e4b17023SJohn Marino 	  {
4034e4b17023SJohn Marino 	    rtx lhs = ops[j].op, rhs = ops[i].op;
4035e4b17023SJohn Marino 	    int lneg = ops[j].neg, rneg = ops[i].neg;
4036e4b17023SJohn Marino 
4037e4b17023SJohn Marino 	    if (lhs != 0 && rhs != 0)
4038e4b17023SJohn Marino 	      {
4039e4b17023SJohn Marino 		enum rtx_code ncode = PLUS;
4040e4b17023SJohn Marino 
4041e4b17023SJohn Marino 		if (lneg != rneg)
4042e4b17023SJohn Marino 		  {
4043e4b17023SJohn Marino 		    ncode = MINUS;
4044e4b17023SJohn Marino 		    if (lneg)
4045e4b17023SJohn Marino 		      tem = lhs, lhs = rhs, rhs = tem;
4046e4b17023SJohn Marino 		  }
4047e4b17023SJohn Marino 		else if (swap_commutative_operands_p (lhs, rhs))
4048e4b17023SJohn Marino 		  tem = lhs, lhs = rhs, rhs = tem;
4049e4b17023SJohn Marino 
4050e4b17023SJohn Marino 		if ((GET_CODE (lhs) == CONST || CONST_INT_P (lhs))
4051e4b17023SJohn Marino 		    && (GET_CODE (rhs) == CONST || CONST_INT_P (rhs)))
4052e4b17023SJohn Marino 		  {
4053e4b17023SJohn Marino 		    rtx tem_lhs, tem_rhs;
4054e4b17023SJohn Marino 
4055e4b17023SJohn Marino 		    tem_lhs = GET_CODE (lhs) == CONST ? XEXP (lhs, 0) : lhs;
4056e4b17023SJohn Marino 		    tem_rhs = GET_CODE (rhs) == CONST ? XEXP (rhs, 0) : rhs;
4057e4b17023SJohn Marino 		    tem = simplify_binary_operation (ncode, mode, tem_lhs, tem_rhs);
4058e4b17023SJohn Marino 
4059e4b17023SJohn Marino 		    if (tem && !CONSTANT_P (tem))
4060e4b17023SJohn Marino 		      tem = gen_rtx_CONST (GET_MODE (tem), tem);
4061e4b17023SJohn Marino 		  }
4062e4b17023SJohn Marino 		else
4063e4b17023SJohn Marino 		  tem = simplify_binary_operation (ncode, mode, lhs, rhs);
4064e4b17023SJohn Marino 
4065e4b17023SJohn Marino 		/* Reject "simplifications" that just wrap the two
4066e4b17023SJohn Marino 		   arguments in a CONST.  Failure to do so can result
4067e4b17023SJohn Marino 		   in infinite recursion with simplify_binary_operation
4068e4b17023SJohn Marino 		   when it calls us to simplify CONST operations.  */
4069e4b17023SJohn Marino 		if (tem
4070e4b17023SJohn Marino 		    && ! (GET_CODE (tem) == CONST
4071e4b17023SJohn Marino 			  && GET_CODE (XEXP (tem, 0)) == ncode
4072e4b17023SJohn Marino 			  && XEXP (XEXP (tem, 0), 0) == lhs
4073e4b17023SJohn Marino 			  && XEXP (XEXP (tem, 0), 1) == rhs))
4074e4b17023SJohn Marino 		  {
4075e4b17023SJohn Marino 		    lneg &= rneg;
4076e4b17023SJohn Marino 		    if (GET_CODE (tem) == NEG)
4077e4b17023SJohn Marino 		      tem = XEXP (tem, 0), lneg = !lneg;
4078e4b17023SJohn Marino 		    if (CONST_INT_P (tem) && lneg)
4079e4b17023SJohn Marino 		      tem = neg_const_int (mode, tem), lneg = 0;
4080e4b17023SJohn Marino 
4081e4b17023SJohn Marino 		    ops[i].op = tem;
4082e4b17023SJohn Marino 		    ops[i].neg = lneg;
4083e4b17023SJohn Marino 		    ops[j].op = NULL_RTX;
4084e4b17023SJohn Marino 		    changed = 1;
4085e4b17023SJohn Marino 		    canonicalized = 1;
4086e4b17023SJohn Marino 		  }
4087e4b17023SJohn Marino 	      }
4088e4b17023SJohn Marino 	  }
4089e4b17023SJohn Marino 
4090e4b17023SJohn Marino       /* If nothing changed, fail.  */
4091e4b17023SJohn Marino       if (!canonicalized)
4092e4b17023SJohn Marino         return NULL_RTX;
4093e4b17023SJohn Marino 
4094e4b17023SJohn Marino       /* Pack all the operands to the lower-numbered entries.  */
4095e4b17023SJohn Marino       for (i = 0, j = 0; j < n_ops; j++)
4096e4b17023SJohn Marino         if (ops[j].op)
4097e4b17023SJohn Marino           {
4098e4b17023SJohn Marino 	    ops[i] = ops[j];
4099e4b17023SJohn Marino 	    i++;
4100e4b17023SJohn Marino           }
4101e4b17023SJohn Marino       n_ops = i;
4102e4b17023SJohn Marino     }
4103e4b17023SJohn Marino   while (changed);
4104e4b17023SJohn Marino 
4105e4b17023SJohn Marino   /* Create (minus -C X) instead of (neg (const (plus X C))).  */
4106e4b17023SJohn Marino   if (n_ops == 2
4107e4b17023SJohn Marino       && CONST_INT_P (ops[1].op)
4108e4b17023SJohn Marino       && CONSTANT_P (ops[0].op)
4109e4b17023SJohn Marino       && ops[0].neg)
4110e4b17023SJohn Marino     return gen_rtx_fmt_ee (MINUS, mode, ops[1].op, ops[0].op);
4111e4b17023SJohn Marino 
4112e4b17023SJohn Marino   /* We suppressed creation of trivial CONST expressions in the
4113e4b17023SJohn Marino      combination loop to avoid recursion.  Create one manually now.
4114e4b17023SJohn Marino      The combination loop should have ensured that there is exactly
4115e4b17023SJohn Marino      one CONST_INT, and the sort will have ensured that it is last
4116e4b17023SJohn Marino      in the array and that any other constant will be next-to-last.  */
4117e4b17023SJohn Marino 
4118e4b17023SJohn Marino   if (n_ops > 1
4119e4b17023SJohn Marino       && CONST_INT_P (ops[n_ops - 1].op)
4120e4b17023SJohn Marino       && CONSTANT_P (ops[n_ops - 2].op))
4121e4b17023SJohn Marino     {
4122e4b17023SJohn Marino       rtx value = ops[n_ops - 1].op;
4123e4b17023SJohn Marino       if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg)
4124e4b17023SJohn Marino 	value = neg_const_int (mode, value);
4125e4b17023SJohn Marino       ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value));
4126e4b17023SJohn Marino       n_ops--;
4127e4b17023SJohn Marino     }
4128e4b17023SJohn Marino 
4129e4b17023SJohn Marino   /* Put a non-negated operand first, if possible.  */
4130e4b17023SJohn Marino 
4131e4b17023SJohn Marino   for (i = 0; i < n_ops && ops[i].neg; i++)
4132e4b17023SJohn Marino     continue;
4133e4b17023SJohn Marino   if (i == n_ops)
4134e4b17023SJohn Marino     ops[0].op = gen_rtx_NEG (mode, ops[0].op);
4135e4b17023SJohn Marino   else if (i != 0)
4136e4b17023SJohn Marino     {
4137e4b17023SJohn Marino       tem = ops[0].op;
4138e4b17023SJohn Marino       ops[0] = ops[i];
4139e4b17023SJohn Marino       ops[i].op = tem;
4140e4b17023SJohn Marino       ops[i].neg = 1;
4141e4b17023SJohn Marino     }
4142e4b17023SJohn Marino 
4143e4b17023SJohn Marino   /* Now make the result by performing the requested operations.  */
4144e4b17023SJohn Marino   result = ops[0].op;
4145e4b17023SJohn Marino   for (i = 1; i < n_ops; i++)
4146e4b17023SJohn Marino     result = gen_rtx_fmt_ee (ops[i].neg ? MINUS : PLUS,
4147e4b17023SJohn Marino 			     mode, result, ops[i].op);
4148e4b17023SJohn Marino 
4149e4b17023SJohn Marino   return result;
4150e4b17023SJohn Marino }
4151e4b17023SJohn Marino 
4152e4b17023SJohn Marino /* Check whether an operand is suitable for calling simplify_plus_minus.  */
4153e4b17023SJohn Marino static bool
plus_minus_operand_p(const_rtx x)4154e4b17023SJohn Marino plus_minus_operand_p (const_rtx x)
4155e4b17023SJohn Marino {
4156e4b17023SJohn Marino   return GET_CODE (x) == PLUS
4157e4b17023SJohn Marino          || GET_CODE (x) == MINUS
4158e4b17023SJohn Marino 	 || (GET_CODE (x) == CONST
4159e4b17023SJohn Marino 	     && GET_CODE (XEXP (x, 0)) == PLUS
4160e4b17023SJohn Marino 	     && CONSTANT_P (XEXP (XEXP (x, 0), 0))
4161e4b17023SJohn Marino 	     && CONSTANT_P (XEXP (XEXP (x, 0), 1)));
4162e4b17023SJohn Marino }
4163e4b17023SJohn Marino 
4164e4b17023SJohn Marino /* Like simplify_binary_operation except used for relational operators.
4165e4b17023SJohn Marino    MODE is the mode of the result. If MODE is VOIDmode, both operands must
4166e4b17023SJohn Marino    not also be VOIDmode.
4167e4b17023SJohn Marino 
4168e4b17023SJohn Marino    CMP_MODE specifies in which mode the comparison is done in, so it is
4169e4b17023SJohn Marino    the mode of the operands.  If CMP_MODE is VOIDmode, it is taken from
4170e4b17023SJohn Marino    the operands or, if both are VOIDmode, the operands are compared in
4171e4b17023SJohn Marino    "infinite precision".  */
4172e4b17023SJohn Marino rtx
simplify_relational_operation(enum rtx_code code,enum machine_mode mode,enum machine_mode cmp_mode,rtx op0,rtx op1)4173e4b17023SJohn Marino simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
4174e4b17023SJohn Marino 			       enum machine_mode cmp_mode, rtx op0, rtx op1)
4175e4b17023SJohn Marino {
4176e4b17023SJohn Marino   rtx tem, trueop0, trueop1;
4177e4b17023SJohn Marino 
4178e4b17023SJohn Marino   if (cmp_mode == VOIDmode)
4179e4b17023SJohn Marino     cmp_mode = GET_MODE (op0);
4180e4b17023SJohn Marino   if (cmp_mode == VOIDmode)
4181e4b17023SJohn Marino     cmp_mode = GET_MODE (op1);
4182e4b17023SJohn Marino 
4183e4b17023SJohn Marino   tem = simplify_const_relational_operation (code, cmp_mode, op0, op1);
4184e4b17023SJohn Marino   if (tem)
4185e4b17023SJohn Marino     {
4186e4b17023SJohn Marino       if (SCALAR_FLOAT_MODE_P (mode))
4187e4b17023SJohn Marino 	{
4188e4b17023SJohn Marino           if (tem == const0_rtx)
4189e4b17023SJohn Marino             return CONST0_RTX (mode);
4190e4b17023SJohn Marino #ifdef FLOAT_STORE_FLAG_VALUE
4191e4b17023SJohn Marino 	  {
4192e4b17023SJohn Marino 	    REAL_VALUE_TYPE val;
4193e4b17023SJohn Marino 	    val = FLOAT_STORE_FLAG_VALUE (mode);
4194e4b17023SJohn Marino 	    return CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
4195e4b17023SJohn Marino 	  }
4196e4b17023SJohn Marino #else
4197e4b17023SJohn Marino 	  return NULL_RTX;
4198e4b17023SJohn Marino #endif
4199e4b17023SJohn Marino 	}
4200e4b17023SJohn Marino       if (VECTOR_MODE_P (mode))
4201e4b17023SJohn Marino 	{
4202e4b17023SJohn Marino 	  if (tem == const0_rtx)
4203e4b17023SJohn Marino 	    return CONST0_RTX (mode);
4204e4b17023SJohn Marino #ifdef VECTOR_STORE_FLAG_VALUE
4205e4b17023SJohn Marino 	  {
4206e4b17023SJohn Marino 	    int i, units;
4207e4b17023SJohn Marino 	    rtvec v;
4208e4b17023SJohn Marino 
4209e4b17023SJohn Marino 	    rtx val = VECTOR_STORE_FLAG_VALUE (mode);
4210e4b17023SJohn Marino 	    if (val == NULL_RTX)
4211e4b17023SJohn Marino 	      return NULL_RTX;
4212e4b17023SJohn Marino 	    if (val == const1_rtx)
4213e4b17023SJohn Marino 	      return CONST1_RTX (mode);
4214e4b17023SJohn Marino 
4215e4b17023SJohn Marino 	    units = GET_MODE_NUNITS (mode);
4216e4b17023SJohn Marino 	    v = rtvec_alloc (units);
4217e4b17023SJohn Marino 	    for (i = 0; i < units; i++)
4218e4b17023SJohn Marino 	      RTVEC_ELT (v, i) = val;
4219e4b17023SJohn Marino 	    return gen_rtx_raw_CONST_VECTOR (mode, v);
4220e4b17023SJohn Marino 	  }
4221e4b17023SJohn Marino #else
4222e4b17023SJohn Marino 	  return NULL_RTX;
4223e4b17023SJohn Marino #endif
4224e4b17023SJohn Marino 	}
4225e4b17023SJohn Marino 
4226e4b17023SJohn Marino       return tem;
4227e4b17023SJohn Marino     }
4228e4b17023SJohn Marino 
4229e4b17023SJohn Marino   /* For the following tests, ensure const0_rtx is op1.  */
4230e4b17023SJohn Marino   if (swap_commutative_operands_p (op0, op1)
4231e4b17023SJohn Marino       || (op0 == const0_rtx && op1 != const0_rtx))
4232e4b17023SJohn Marino     tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
4233e4b17023SJohn Marino 
4234e4b17023SJohn Marino   /* If op0 is a compare, extract the comparison arguments from it.  */
4235e4b17023SJohn Marino   if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
4236e4b17023SJohn Marino     return simplify_gen_relational (code, mode, VOIDmode,
4237e4b17023SJohn Marino 				    XEXP (op0, 0), XEXP (op0, 1));
4238e4b17023SJohn Marino 
4239e4b17023SJohn Marino   if (GET_MODE_CLASS (cmp_mode) == MODE_CC
4240e4b17023SJohn Marino       || CC0_P (op0))
4241e4b17023SJohn Marino     return NULL_RTX;
4242e4b17023SJohn Marino 
4243e4b17023SJohn Marino   trueop0 = avoid_constant_pool_reference (op0);
4244e4b17023SJohn Marino   trueop1 = avoid_constant_pool_reference (op1);
4245e4b17023SJohn Marino   return simplify_relational_operation_1 (code, mode, cmp_mode,
4246e4b17023SJohn Marino 		  			  trueop0, trueop1);
4247e4b17023SJohn Marino }
4248e4b17023SJohn Marino 
4249e4b17023SJohn Marino /* This part of simplify_relational_operation is only used when CMP_MODE
4250e4b17023SJohn Marino    is not in class MODE_CC (i.e. it is a real comparison).
4251e4b17023SJohn Marino 
4252e4b17023SJohn Marino    MODE is the mode of the result, while CMP_MODE specifies in which
4253e4b17023SJohn Marino    mode the comparison is done in, so it is the mode of the operands.  */
4254e4b17023SJohn Marino 
4255e4b17023SJohn Marino static rtx
simplify_relational_operation_1(enum rtx_code code,enum machine_mode mode,enum machine_mode cmp_mode,rtx op0,rtx op1)4256e4b17023SJohn Marino simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
4257e4b17023SJohn Marino 				 enum machine_mode cmp_mode, rtx op0, rtx op1)
4258e4b17023SJohn Marino {
4259e4b17023SJohn Marino   enum rtx_code op0code = GET_CODE (op0);
4260e4b17023SJohn Marino 
4261e4b17023SJohn Marino   if (op1 == const0_rtx && COMPARISON_P (op0))
4262e4b17023SJohn Marino     {
4263e4b17023SJohn Marino       /* If op0 is a comparison, extract the comparison arguments
4264e4b17023SJohn Marino          from it.  */
4265e4b17023SJohn Marino       if (code == NE)
4266e4b17023SJohn Marino 	{
4267e4b17023SJohn Marino 	  if (GET_MODE (op0) == mode)
4268e4b17023SJohn Marino 	    return simplify_rtx (op0);
4269e4b17023SJohn Marino 	  else
4270e4b17023SJohn Marino 	    return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
4271e4b17023SJohn Marino 					    XEXP (op0, 0), XEXP (op0, 1));
4272e4b17023SJohn Marino 	}
4273e4b17023SJohn Marino       else if (code == EQ)
4274e4b17023SJohn Marino 	{
4275e4b17023SJohn Marino 	  enum rtx_code new_code = reversed_comparison_code (op0, NULL_RTX);
4276e4b17023SJohn Marino 	  if (new_code != UNKNOWN)
4277e4b17023SJohn Marino 	    return simplify_gen_relational (new_code, mode, VOIDmode,
4278e4b17023SJohn Marino 					    XEXP (op0, 0), XEXP (op0, 1));
4279e4b17023SJohn Marino 	}
4280e4b17023SJohn Marino     }
4281e4b17023SJohn Marino 
4282e4b17023SJohn Marino   /* (LTU/GEU (PLUS a C) C), where C is constant, can be simplified to
4283e4b17023SJohn Marino      (GEU/LTU a -C).  Likewise for (LTU/GEU (PLUS a C) a).  */
4284e4b17023SJohn Marino   if ((code == LTU || code == GEU)
4285e4b17023SJohn Marino       && GET_CODE (op0) == PLUS
4286e4b17023SJohn Marino       && CONST_INT_P (XEXP (op0, 1))
4287e4b17023SJohn Marino       && (rtx_equal_p (op1, XEXP (op0, 0))
4288e4b17023SJohn Marino 	  || rtx_equal_p (op1, XEXP (op0, 1))))
4289e4b17023SJohn Marino     {
4290e4b17023SJohn Marino       rtx new_cmp
4291e4b17023SJohn Marino 	= simplify_gen_unary (NEG, cmp_mode, XEXP (op0, 1), cmp_mode);
4292e4b17023SJohn Marino       return simplify_gen_relational ((code == LTU ? GEU : LTU), mode,
4293e4b17023SJohn Marino 				      cmp_mode, XEXP (op0, 0), new_cmp);
4294e4b17023SJohn Marino     }
4295e4b17023SJohn Marino 
4296e4b17023SJohn Marino   /* Canonicalize (LTU/GEU (PLUS a b) b) as (LTU/GEU (PLUS a b) a).  */
4297e4b17023SJohn Marino   if ((code == LTU || code == GEU)
4298e4b17023SJohn Marino       && GET_CODE (op0) == PLUS
4299e4b17023SJohn Marino       && rtx_equal_p (op1, XEXP (op0, 1))
4300e4b17023SJohn Marino       /* Don't recurse "infinitely" for (LTU/GEU (PLUS b b) b).  */
4301e4b17023SJohn Marino       && !rtx_equal_p (op1, XEXP (op0, 0)))
4302e4b17023SJohn Marino     return simplify_gen_relational (code, mode, cmp_mode, op0,
4303e4b17023SJohn Marino 				    copy_rtx (XEXP (op0, 0)));
4304e4b17023SJohn Marino 
4305e4b17023SJohn Marino   if (op1 == const0_rtx)
4306e4b17023SJohn Marino     {
4307e4b17023SJohn Marino       /* Canonicalize (GTU x 0) as (NE x 0).  */
4308e4b17023SJohn Marino       if (code == GTU)
4309e4b17023SJohn Marino         return simplify_gen_relational (NE, mode, cmp_mode, op0, op1);
4310e4b17023SJohn Marino       /* Canonicalize (LEU x 0) as (EQ x 0).  */
4311e4b17023SJohn Marino       if (code == LEU)
4312e4b17023SJohn Marino         return simplify_gen_relational (EQ, mode, cmp_mode, op0, op1);
4313e4b17023SJohn Marino     }
4314e4b17023SJohn Marino   else if (op1 == const1_rtx)
4315e4b17023SJohn Marino     {
4316e4b17023SJohn Marino       switch (code)
4317e4b17023SJohn Marino         {
4318e4b17023SJohn Marino         case GE:
4319e4b17023SJohn Marino 	  /* Canonicalize (GE x 1) as (GT x 0).  */
4320e4b17023SJohn Marino 	  return simplify_gen_relational (GT, mode, cmp_mode,
4321e4b17023SJohn Marino 					  op0, const0_rtx);
4322e4b17023SJohn Marino 	case GEU:
4323e4b17023SJohn Marino 	  /* Canonicalize (GEU x 1) as (NE x 0).  */
4324e4b17023SJohn Marino 	  return simplify_gen_relational (NE, mode, cmp_mode,
4325e4b17023SJohn Marino 					  op0, const0_rtx);
4326e4b17023SJohn Marino 	case LT:
4327e4b17023SJohn Marino 	  /* Canonicalize (LT x 1) as (LE x 0).  */
4328e4b17023SJohn Marino 	  return simplify_gen_relational (LE, mode, cmp_mode,
4329e4b17023SJohn Marino 					  op0, const0_rtx);
4330e4b17023SJohn Marino 	case LTU:
4331e4b17023SJohn Marino 	  /* Canonicalize (LTU x 1) as (EQ x 0).  */
4332e4b17023SJohn Marino 	  return simplify_gen_relational (EQ, mode, cmp_mode,
4333e4b17023SJohn Marino 					  op0, const0_rtx);
4334e4b17023SJohn Marino 	default:
4335e4b17023SJohn Marino 	  break;
4336e4b17023SJohn Marino 	}
4337e4b17023SJohn Marino     }
4338e4b17023SJohn Marino   else if (op1 == constm1_rtx)
4339e4b17023SJohn Marino     {
4340e4b17023SJohn Marino       /* Canonicalize (LE x -1) as (LT x 0).  */
4341e4b17023SJohn Marino       if (code == LE)
4342e4b17023SJohn Marino         return simplify_gen_relational (LT, mode, cmp_mode, op0, const0_rtx);
4343e4b17023SJohn Marino       /* Canonicalize (GT x -1) as (GE x 0).  */
4344e4b17023SJohn Marino       if (code == GT)
4345e4b17023SJohn Marino         return simplify_gen_relational (GE, mode, cmp_mode, op0, const0_rtx);
4346e4b17023SJohn Marino     }
4347e4b17023SJohn Marino 
4348e4b17023SJohn Marino   /* (eq/ne (plus x cst1) cst2) simplifies to (eq/ne x (cst2 - cst1))  */
4349e4b17023SJohn Marino   if ((code == EQ || code == NE)
4350e4b17023SJohn Marino       && (op0code == PLUS || op0code == MINUS)
4351e4b17023SJohn Marino       && CONSTANT_P (op1)
4352e4b17023SJohn Marino       && CONSTANT_P (XEXP (op0, 1))
4353e4b17023SJohn Marino       && (INTEGRAL_MODE_P (cmp_mode) || flag_unsafe_math_optimizations))
4354e4b17023SJohn Marino     {
4355e4b17023SJohn Marino       rtx x = XEXP (op0, 0);
4356e4b17023SJohn Marino       rtx c = XEXP (op0, 1);
4357e4b17023SJohn Marino       enum rtx_code invcode = op0code == PLUS ? MINUS : PLUS;
4358e4b17023SJohn Marino       rtx tem = simplify_gen_binary (invcode, cmp_mode, op1, c);
4359e4b17023SJohn Marino 
4360e4b17023SJohn Marino       /* Detect an infinite recursive condition, where we oscillate at this
4361e4b17023SJohn Marino 	 simplification case between:
4362e4b17023SJohn Marino 	    A + B == C  <--->  C - B == A,
4363e4b17023SJohn Marino 	 where A, B, and C are all constants with non-simplifiable expressions,
4364e4b17023SJohn Marino 	 usually SYMBOL_REFs.  */
4365e4b17023SJohn Marino       if (GET_CODE (tem) == invcode
4366e4b17023SJohn Marino 	  && CONSTANT_P (x)
4367e4b17023SJohn Marino 	  && rtx_equal_p (c, XEXP (tem, 1)))
4368e4b17023SJohn Marino 	return NULL_RTX;
4369e4b17023SJohn Marino 
4370e4b17023SJohn Marino       return simplify_gen_relational (code, mode, cmp_mode, x, tem);
4371e4b17023SJohn Marino     }
4372e4b17023SJohn Marino 
4373e4b17023SJohn Marino   /* (ne:SI (zero_extract:SI FOO (const_int 1) BAR) (const_int 0))) is
4374e4b17023SJohn Marino      the same as (zero_extract:SI FOO (const_int 1) BAR).  */
4375e4b17023SJohn Marino   if (code == NE
4376e4b17023SJohn Marino       && op1 == const0_rtx
4377e4b17023SJohn Marino       && GET_MODE_CLASS (mode) == MODE_INT
4378e4b17023SJohn Marino       && cmp_mode != VOIDmode
4379e4b17023SJohn Marino       /* ??? Work-around BImode bugs in the ia64 backend.  */
4380e4b17023SJohn Marino       && mode != BImode
4381e4b17023SJohn Marino       && cmp_mode != BImode
4382e4b17023SJohn Marino       && nonzero_bits (op0, cmp_mode) == 1
4383e4b17023SJohn Marino       && STORE_FLAG_VALUE == 1)
4384e4b17023SJohn Marino     return GET_MODE_SIZE (mode) > GET_MODE_SIZE (cmp_mode)
4385e4b17023SJohn Marino 	   ? simplify_gen_unary (ZERO_EXTEND, mode, op0, cmp_mode)
4386e4b17023SJohn Marino 	   : lowpart_subreg (mode, op0, cmp_mode);
4387e4b17023SJohn Marino 
4388e4b17023SJohn Marino   /* (eq/ne (xor x y) 0) simplifies to (eq/ne x y).  */
4389e4b17023SJohn Marino   if ((code == EQ || code == NE)
4390e4b17023SJohn Marino       && op1 == const0_rtx
4391e4b17023SJohn Marino       && op0code == XOR)
4392e4b17023SJohn Marino     return simplify_gen_relational (code, mode, cmp_mode,
4393e4b17023SJohn Marino 				    XEXP (op0, 0), XEXP (op0, 1));
4394e4b17023SJohn Marino 
4395e4b17023SJohn Marino   /* (eq/ne (xor x y) x) simplifies to (eq/ne y 0).  */
4396e4b17023SJohn Marino   if ((code == EQ || code == NE)
4397e4b17023SJohn Marino       && op0code == XOR
4398e4b17023SJohn Marino       && rtx_equal_p (XEXP (op0, 0), op1)
4399e4b17023SJohn Marino       && !side_effects_p (XEXP (op0, 0)))
4400e4b17023SJohn Marino     return simplify_gen_relational (code, mode, cmp_mode,
4401e4b17023SJohn Marino 				    XEXP (op0, 1), const0_rtx);
4402e4b17023SJohn Marino 
4403e4b17023SJohn Marino   /* Likewise (eq/ne (xor x y) y) simplifies to (eq/ne x 0).  */
4404e4b17023SJohn Marino   if ((code == EQ || code == NE)
4405e4b17023SJohn Marino       && op0code == XOR
4406e4b17023SJohn Marino       && rtx_equal_p (XEXP (op0, 1), op1)
4407e4b17023SJohn Marino       && !side_effects_p (XEXP (op0, 1)))
4408e4b17023SJohn Marino     return simplify_gen_relational (code, mode, cmp_mode,
4409e4b17023SJohn Marino 				    XEXP (op0, 0), const0_rtx);
4410e4b17023SJohn Marino 
4411e4b17023SJohn Marino   /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
4412e4b17023SJohn Marino   if ((code == EQ || code == NE)
4413e4b17023SJohn Marino       && op0code == XOR
4414e4b17023SJohn Marino       && (CONST_INT_P (op1)
4415e4b17023SJohn Marino 	  || GET_CODE (op1) == CONST_DOUBLE)
4416e4b17023SJohn Marino       && (CONST_INT_P (XEXP (op0, 1))
4417e4b17023SJohn Marino 	  || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE))
4418e4b17023SJohn Marino     return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
4419e4b17023SJohn Marino 				    simplify_gen_binary (XOR, cmp_mode,
4420e4b17023SJohn Marino 							 XEXP (op0, 1), op1));
4421e4b17023SJohn Marino 
4422e4b17023SJohn Marino   if (op0code == POPCOUNT && op1 == const0_rtx)
4423e4b17023SJohn Marino     switch (code)
4424e4b17023SJohn Marino       {
4425e4b17023SJohn Marino       case EQ:
4426e4b17023SJohn Marino       case LE:
4427e4b17023SJohn Marino       case LEU:
4428e4b17023SJohn Marino 	/* (eq (popcount x) (const_int 0)) -> (eq x (const_int 0)).  */
4429e4b17023SJohn Marino 	return simplify_gen_relational (EQ, mode, GET_MODE (XEXP (op0, 0)),
4430e4b17023SJohn Marino 					XEXP (op0, 0), const0_rtx);
4431e4b17023SJohn Marino 
4432e4b17023SJohn Marino       case NE:
4433e4b17023SJohn Marino       case GT:
4434e4b17023SJohn Marino       case GTU:
4435e4b17023SJohn Marino 	/* (ne (popcount x) (const_int 0)) -> (ne x (const_int 0)).  */
4436e4b17023SJohn Marino 	return simplify_gen_relational (NE, mode, GET_MODE (XEXP (op0, 0)),
4437e4b17023SJohn Marino 					XEXP (op0, 0), const0_rtx);
4438e4b17023SJohn Marino 
4439e4b17023SJohn Marino       default:
4440e4b17023SJohn Marino 	break;
4441e4b17023SJohn Marino       }
4442e4b17023SJohn Marino 
4443e4b17023SJohn Marino   return NULL_RTX;
4444e4b17023SJohn Marino }
4445e4b17023SJohn Marino 
4446e4b17023SJohn Marino enum
4447e4b17023SJohn Marino {
4448e4b17023SJohn Marino   CMP_EQ = 1,
4449e4b17023SJohn Marino   CMP_LT = 2,
4450e4b17023SJohn Marino   CMP_GT = 4,
4451e4b17023SJohn Marino   CMP_LTU = 8,
4452e4b17023SJohn Marino   CMP_GTU = 16
4453e4b17023SJohn Marino };
4454e4b17023SJohn Marino 
4455e4b17023SJohn Marino 
4456e4b17023SJohn Marino /* Convert the known results for EQ, LT, GT, LTU, GTU contained in
4457e4b17023SJohn Marino    KNOWN_RESULT to a CONST_INT, based on the requested comparison CODE
4458e4b17023SJohn Marino    For KNOWN_RESULT to make sense it should be either CMP_EQ, or the
4459e4b17023SJohn Marino    logical OR of one of (CMP_LT, CMP_GT) and one of (CMP_LTU, CMP_GTU).
4460e4b17023SJohn Marino    For floating-point comparisons, assume that the operands were ordered.  */
4461e4b17023SJohn Marino 
4462e4b17023SJohn Marino static rtx
comparison_result(enum rtx_code code,int known_results)4463e4b17023SJohn Marino comparison_result (enum rtx_code code, int known_results)
4464e4b17023SJohn Marino {
4465e4b17023SJohn Marino   switch (code)
4466e4b17023SJohn Marino     {
4467e4b17023SJohn Marino     case EQ:
4468e4b17023SJohn Marino     case UNEQ:
4469e4b17023SJohn Marino       return (known_results & CMP_EQ) ? const_true_rtx : const0_rtx;
4470e4b17023SJohn Marino     case NE:
4471e4b17023SJohn Marino     case LTGT:
4472e4b17023SJohn Marino       return (known_results & CMP_EQ) ? const0_rtx : const_true_rtx;
4473e4b17023SJohn Marino 
4474e4b17023SJohn Marino     case LT:
4475e4b17023SJohn Marino     case UNLT:
4476e4b17023SJohn Marino       return (known_results & CMP_LT) ? const_true_rtx : const0_rtx;
4477e4b17023SJohn Marino     case GE:
4478e4b17023SJohn Marino     case UNGE:
4479e4b17023SJohn Marino       return (known_results & CMP_LT) ? const0_rtx : const_true_rtx;
4480e4b17023SJohn Marino 
4481e4b17023SJohn Marino     case GT:
4482e4b17023SJohn Marino     case UNGT:
4483e4b17023SJohn Marino       return (known_results & CMP_GT) ? const_true_rtx : const0_rtx;
4484e4b17023SJohn Marino     case LE:
4485e4b17023SJohn Marino     case UNLE:
4486e4b17023SJohn Marino       return (known_results & CMP_GT) ? const0_rtx : const_true_rtx;
4487e4b17023SJohn Marino 
4488e4b17023SJohn Marino     case LTU:
4489e4b17023SJohn Marino       return (known_results & CMP_LTU) ? const_true_rtx : const0_rtx;
4490e4b17023SJohn Marino     case GEU:
4491e4b17023SJohn Marino       return (known_results & CMP_LTU) ? const0_rtx : const_true_rtx;
4492e4b17023SJohn Marino 
4493e4b17023SJohn Marino     case GTU:
4494e4b17023SJohn Marino       return (known_results & CMP_GTU) ? const_true_rtx : const0_rtx;
4495e4b17023SJohn Marino     case LEU:
4496e4b17023SJohn Marino       return (known_results & CMP_GTU) ? const0_rtx : const_true_rtx;
4497e4b17023SJohn Marino 
4498e4b17023SJohn Marino     case ORDERED:
4499e4b17023SJohn Marino       return const_true_rtx;
4500e4b17023SJohn Marino     case UNORDERED:
4501e4b17023SJohn Marino       return const0_rtx;
4502e4b17023SJohn Marino     default:
4503e4b17023SJohn Marino       gcc_unreachable ();
4504e4b17023SJohn Marino     }
4505e4b17023SJohn Marino }
4506e4b17023SJohn Marino 
4507e4b17023SJohn Marino /* Check if the given comparison (done in the given MODE) is actually a
4508e4b17023SJohn Marino    tautology or a contradiction.
4509e4b17023SJohn Marino    If no simplification is possible, this function returns zero.
4510e4b17023SJohn Marino    Otherwise, it returns either const_true_rtx or const0_rtx.  */
4511e4b17023SJohn Marino 
4512e4b17023SJohn Marino rtx
simplify_const_relational_operation(enum rtx_code code,enum machine_mode mode,rtx op0,rtx op1)4513e4b17023SJohn Marino simplify_const_relational_operation (enum rtx_code code,
4514e4b17023SJohn Marino 				     enum machine_mode mode,
4515e4b17023SJohn Marino 				     rtx op0, rtx op1)
4516e4b17023SJohn Marino {
4517e4b17023SJohn Marino   rtx tem;
4518e4b17023SJohn Marino   rtx trueop0;
4519e4b17023SJohn Marino   rtx trueop1;
4520e4b17023SJohn Marino 
4521e4b17023SJohn Marino   gcc_assert (mode != VOIDmode
4522e4b17023SJohn Marino 	      || (GET_MODE (op0) == VOIDmode
4523e4b17023SJohn Marino 		  && GET_MODE (op1) == VOIDmode));
4524e4b17023SJohn Marino 
4525e4b17023SJohn Marino   /* If op0 is a compare, extract the comparison arguments from it.  */
4526e4b17023SJohn Marino   if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
4527e4b17023SJohn Marino     {
4528e4b17023SJohn Marino       op1 = XEXP (op0, 1);
4529e4b17023SJohn Marino       op0 = XEXP (op0, 0);
4530e4b17023SJohn Marino 
4531e4b17023SJohn Marino       if (GET_MODE (op0) != VOIDmode)
4532e4b17023SJohn Marino 	mode = GET_MODE (op0);
4533e4b17023SJohn Marino       else if (GET_MODE (op1) != VOIDmode)
4534e4b17023SJohn Marino 	mode = GET_MODE (op1);
4535e4b17023SJohn Marino       else
4536e4b17023SJohn Marino 	return 0;
4537e4b17023SJohn Marino     }
4538e4b17023SJohn Marino 
4539e4b17023SJohn Marino   /* We can't simplify MODE_CC values since we don't know what the
4540e4b17023SJohn Marino      actual comparison is.  */
4541e4b17023SJohn Marino   if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC || CC0_P (op0))
4542e4b17023SJohn Marino     return 0;
4543e4b17023SJohn Marino 
4544e4b17023SJohn Marino   /* Make sure the constant is second.  */
4545e4b17023SJohn Marino   if (swap_commutative_operands_p (op0, op1))
4546e4b17023SJohn Marino     {
4547e4b17023SJohn Marino       tem = op0, op0 = op1, op1 = tem;
4548e4b17023SJohn Marino       code = swap_condition (code);
4549e4b17023SJohn Marino     }
4550e4b17023SJohn Marino 
4551e4b17023SJohn Marino   trueop0 = avoid_constant_pool_reference (op0);
4552e4b17023SJohn Marino   trueop1 = avoid_constant_pool_reference (op1);
4553e4b17023SJohn Marino 
4554e4b17023SJohn Marino   /* For integer comparisons of A and B maybe we can simplify A - B and can
4555e4b17023SJohn Marino      then simplify a comparison of that with zero.  If A and B are both either
4556e4b17023SJohn Marino      a register or a CONST_INT, this can't help; testing for these cases will
4557e4b17023SJohn Marino      prevent infinite recursion here and speed things up.
4558e4b17023SJohn Marino 
4559e4b17023SJohn Marino      We can only do this for EQ and NE comparisons as otherwise we may
4560e4b17023SJohn Marino      lose or introduce overflow which we cannot disregard as undefined as
4561e4b17023SJohn Marino      we do not know the signedness of the operation on either the left or
4562e4b17023SJohn Marino      the right hand side of the comparison.  */
4563e4b17023SJohn Marino 
4564e4b17023SJohn Marino   if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
4565e4b17023SJohn Marino       && (code == EQ || code == NE)
4566e4b17023SJohn Marino       && ! ((REG_P (op0) || CONST_INT_P (trueop0))
4567e4b17023SJohn Marino 	    && (REG_P (op1) || CONST_INT_P (trueop1)))
4568e4b17023SJohn Marino       && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
4569e4b17023SJohn Marino       /* We cannot do this if tem is a nonzero address.  */
4570e4b17023SJohn Marino       && ! nonzero_address_p (tem))
4571e4b17023SJohn Marino     return simplify_const_relational_operation (signed_condition (code),
4572e4b17023SJohn Marino 						mode, tem, const0_rtx);
4573e4b17023SJohn Marino 
4574e4b17023SJohn Marino   if (! HONOR_NANS (mode) && code == ORDERED)
4575e4b17023SJohn Marino     return const_true_rtx;
4576e4b17023SJohn Marino 
4577e4b17023SJohn Marino   if (! HONOR_NANS (mode) && code == UNORDERED)
4578e4b17023SJohn Marino     return const0_rtx;
4579e4b17023SJohn Marino 
4580e4b17023SJohn Marino   /* For modes without NaNs, if the two operands are equal, we know the
4581e4b17023SJohn Marino      result except if they have side-effects.  Even with NaNs we know
4582e4b17023SJohn Marino      the result of unordered comparisons and, if signaling NaNs are
4583e4b17023SJohn Marino      irrelevant, also the result of LT/GT/LTGT.  */
4584e4b17023SJohn Marino   if ((! HONOR_NANS (GET_MODE (trueop0))
4585e4b17023SJohn Marino        || code == UNEQ || code == UNLE || code == UNGE
4586e4b17023SJohn Marino        || ((code == LT || code == GT || code == LTGT)
4587e4b17023SJohn Marino 	   && ! HONOR_SNANS (GET_MODE (trueop0))))
4588e4b17023SJohn Marino       && rtx_equal_p (trueop0, trueop1)
4589e4b17023SJohn Marino       && ! side_effects_p (trueop0))
4590e4b17023SJohn Marino     return comparison_result (code, CMP_EQ);
4591e4b17023SJohn Marino 
4592e4b17023SJohn Marino   /* If the operands are floating-point constants, see if we can fold
4593e4b17023SJohn Marino      the result.  */
4594e4b17023SJohn Marino   if (GET_CODE (trueop0) == CONST_DOUBLE
4595e4b17023SJohn Marino       && GET_CODE (trueop1) == CONST_DOUBLE
4596e4b17023SJohn Marino       && SCALAR_FLOAT_MODE_P (GET_MODE (trueop0)))
4597e4b17023SJohn Marino     {
4598e4b17023SJohn Marino       REAL_VALUE_TYPE d0, d1;
4599e4b17023SJohn Marino 
4600e4b17023SJohn Marino       REAL_VALUE_FROM_CONST_DOUBLE (d0, trueop0);
4601e4b17023SJohn Marino       REAL_VALUE_FROM_CONST_DOUBLE (d1, trueop1);
4602e4b17023SJohn Marino 
4603e4b17023SJohn Marino       /* Comparisons are unordered iff at least one of the values is NaN.  */
4604e4b17023SJohn Marino       if (REAL_VALUE_ISNAN (d0) || REAL_VALUE_ISNAN (d1))
4605e4b17023SJohn Marino 	switch (code)
4606e4b17023SJohn Marino 	  {
4607e4b17023SJohn Marino 	  case UNEQ:
4608e4b17023SJohn Marino 	  case UNLT:
4609e4b17023SJohn Marino 	  case UNGT:
4610e4b17023SJohn Marino 	  case UNLE:
4611e4b17023SJohn Marino 	  case UNGE:
4612e4b17023SJohn Marino 	  case NE:
4613e4b17023SJohn Marino 	  case UNORDERED:
4614e4b17023SJohn Marino 	    return const_true_rtx;
4615e4b17023SJohn Marino 	  case EQ:
4616e4b17023SJohn Marino 	  case LT:
4617e4b17023SJohn Marino 	  case GT:
4618e4b17023SJohn Marino 	  case LE:
4619e4b17023SJohn Marino 	  case GE:
4620e4b17023SJohn Marino 	  case LTGT:
4621e4b17023SJohn Marino 	  case ORDERED:
4622e4b17023SJohn Marino 	    return const0_rtx;
4623e4b17023SJohn Marino 	  default:
4624e4b17023SJohn Marino 	    return 0;
4625e4b17023SJohn Marino 	  }
4626e4b17023SJohn Marino 
4627e4b17023SJohn Marino       return comparison_result (code,
4628e4b17023SJohn Marino 				(REAL_VALUES_EQUAL (d0, d1) ? CMP_EQ :
4629e4b17023SJohn Marino 				 REAL_VALUES_LESS (d0, d1) ? CMP_LT : CMP_GT));
4630e4b17023SJohn Marino     }
4631e4b17023SJohn Marino 
4632e4b17023SJohn Marino   /* Otherwise, see if the operands are both integers.  */
4633e4b17023SJohn Marino   if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
4634e4b17023SJohn Marino        && (GET_CODE (trueop0) == CONST_DOUBLE
4635e4b17023SJohn Marino 	   || CONST_INT_P (trueop0))
4636e4b17023SJohn Marino        && (GET_CODE (trueop1) == CONST_DOUBLE
4637e4b17023SJohn Marino 	   || CONST_INT_P (trueop1)))
4638e4b17023SJohn Marino     {
4639e4b17023SJohn Marino       int width = GET_MODE_PRECISION (mode);
4640e4b17023SJohn Marino       HOST_WIDE_INT l0s, h0s, l1s, h1s;
4641e4b17023SJohn Marino       unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
4642e4b17023SJohn Marino 
4643e4b17023SJohn Marino       /* Get the two words comprising each integer constant.  */
4644e4b17023SJohn Marino       if (GET_CODE (trueop0) == CONST_DOUBLE)
4645e4b17023SJohn Marino 	{
4646e4b17023SJohn Marino 	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
4647e4b17023SJohn Marino 	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
4648e4b17023SJohn Marino 	}
4649e4b17023SJohn Marino       else
4650e4b17023SJohn Marino 	{
4651e4b17023SJohn Marino 	  l0u = l0s = INTVAL (trueop0);
4652e4b17023SJohn Marino 	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
4653e4b17023SJohn Marino 	}
4654e4b17023SJohn Marino 
4655e4b17023SJohn Marino       if (GET_CODE (trueop1) == CONST_DOUBLE)
4656e4b17023SJohn Marino 	{
4657e4b17023SJohn Marino 	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
4658e4b17023SJohn Marino 	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
4659e4b17023SJohn Marino 	}
4660e4b17023SJohn Marino       else
4661e4b17023SJohn Marino 	{
4662e4b17023SJohn Marino 	  l1u = l1s = INTVAL (trueop1);
4663e4b17023SJohn Marino 	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
4664e4b17023SJohn Marino 	}
4665e4b17023SJohn Marino 
4666e4b17023SJohn Marino       /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
4667e4b17023SJohn Marino 	 we have to sign or zero-extend the values.  */
4668e4b17023SJohn Marino       if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
4669e4b17023SJohn Marino 	{
4670e4b17023SJohn Marino 	  l0u &= GET_MODE_MASK (mode);
4671e4b17023SJohn Marino 	  l1u &= GET_MODE_MASK (mode);
4672e4b17023SJohn Marino 
4673e4b17023SJohn Marino 	  if (val_signbit_known_set_p (mode, l0s))
4674e4b17023SJohn Marino 	    l0s |= ~GET_MODE_MASK (mode);
4675e4b17023SJohn Marino 
4676e4b17023SJohn Marino 	  if (val_signbit_known_set_p (mode, l1s))
4677e4b17023SJohn Marino 	    l1s |= ~GET_MODE_MASK (mode);
4678e4b17023SJohn Marino 	}
4679e4b17023SJohn Marino       if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
4680e4b17023SJohn Marino 	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
4681e4b17023SJohn Marino 
4682e4b17023SJohn Marino       if (h0u == h1u && l0u == l1u)
4683e4b17023SJohn Marino 	return comparison_result (code, CMP_EQ);
4684e4b17023SJohn Marino       else
4685e4b17023SJohn Marino 	{
4686e4b17023SJohn Marino 	  int cr;
4687e4b17023SJohn Marino 	  cr = (h0s < h1s || (h0s == h1s && l0u < l1u)) ? CMP_LT : CMP_GT;
4688e4b17023SJohn Marino 	  cr |= (h0u < h1u || (h0u == h1u && l0u < l1u)) ? CMP_LTU : CMP_GTU;
4689e4b17023SJohn Marino 	  return comparison_result (code, cr);
4690e4b17023SJohn Marino 	}
4691e4b17023SJohn Marino     }
4692e4b17023SJohn Marino 
4693e4b17023SJohn Marino   /* Optimize comparisons with upper and lower bounds.  */
4694e4b17023SJohn Marino   if (HWI_COMPUTABLE_MODE_P (mode)
4695e4b17023SJohn Marino       && CONST_INT_P (trueop1))
4696e4b17023SJohn Marino     {
4697e4b17023SJohn Marino       int sign;
4698e4b17023SJohn Marino       unsigned HOST_WIDE_INT nonzero = nonzero_bits (trueop0, mode);
4699e4b17023SJohn Marino       HOST_WIDE_INT val = INTVAL (trueop1);
4700e4b17023SJohn Marino       HOST_WIDE_INT mmin, mmax;
4701e4b17023SJohn Marino 
4702e4b17023SJohn Marino       if (code == GEU
4703e4b17023SJohn Marino 	  || code == LEU
4704e4b17023SJohn Marino 	  || code == GTU
4705e4b17023SJohn Marino 	  || code == LTU)
4706e4b17023SJohn Marino 	sign = 0;
4707e4b17023SJohn Marino       else
4708e4b17023SJohn Marino 	sign = 1;
4709e4b17023SJohn Marino 
4710e4b17023SJohn Marino       /* Get a reduced range if the sign bit is zero.  */
4711e4b17023SJohn Marino       if (nonzero <= (GET_MODE_MASK (mode) >> 1))
4712e4b17023SJohn Marino 	{
4713e4b17023SJohn Marino 	  mmin = 0;
4714e4b17023SJohn Marino 	  mmax = nonzero;
4715e4b17023SJohn Marino 	}
4716e4b17023SJohn Marino       else
4717e4b17023SJohn Marino 	{
4718e4b17023SJohn Marino 	  rtx mmin_rtx, mmax_rtx;
4719e4b17023SJohn Marino 	  get_mode_bounds (mode, sign, mode, &mmin_rtx, &mmax_rtx);
4720e4b17023SJohn Marino 
4721e4b17023SJohn Marino 	  mmin = INTVAL (mmin_rtx);
4722e4b17023SJohn Marino 	  mmax = INTVAL (mmax_rtx);
4723e4b17023SJohn Marino 	  if (sign)
4724e4b17023SJohn Marino 	    {
4725e4b17023SJohn Marino 	      unsigned int sign_copies = num_sign_bit_copies (trueop0, mode);
4726e4b17023SJohn Marino 
4727e4b17023SJohn Marino 	      mmin >>= (sign_copies - 1);
4728e4b17023SJohn Marino 	      mmax >>= (sign_copies - 1);
4729e4b17023SJohn Marino 	    }
4730e4b17023SJohn Marino 	}
4731e4b17023SJohn Marino 
4732e4b17023SJohn Marino       switch (code)
4733e4b17023SJohn Marino 	{
4734e4b17023SJohn Marino 	/* x >= y is always true for y <= mmin, always false for y > mmax.  */
4735e4b17023SJohn Marino 	case GEU:
4736e4b17023SJohn Marino 	  if ((unsigned HOST_WIDE_INT) val <= (unsigned HOST_WIDE_INT) mmin)
4737e4b17023SJohn Marino 	    return const_true_rtx;
4738e4b17023SJohn Marino 	  if ((unsigned HOST_WIDE_INT) val > (unsigned HOST_WIDE_INT) mmax)
4739e4b17023SJohn Marino 	    return const0_rtx;
4740e4b17023SJohn Marino 	  break;
4741e4b17023SJohn Marino 	case GE:
4742e4b17023SJohn Marino 	  if (val <= mmin)
4743e4b17023SJohn Marino 	    return const_true_rtx;
4744e4b17023SJohn Marino 	  if (val > mmax)
4745e4b17023SJohn Marino 	    return const0_rtx;
4746e4b17023SJohn Marino 	  break;
4747e4b17023SJohn Marino 
4748e4b17023SJohn Marino 	/* x <= y is always true for y >= mmax, always false for y < mmin.  */
4749e4b17023SJohn Marino 	case LEU:
4750e4b17023SJohn Marino 	  if ((unsigned HOST_WIDE_INT) val >= (unsigned HOST_WIDE_INT) mmax)
4751e4b17023SJohn Marino 	    return const_true_rtx;
4752e4b17023SJohn Marino 	  if ((unsigned HOST_WIDE_INT) val < (unsigned HOST_WIDE_INT) mmin)
4753e4b17023SJohn Marino 	    return const0_rtx;
4754e4b17023SJohn Marino 	  break;
4755e4b17023SJohn Marino 	case LE:
4756e4b17023SJohn Marino 	  if (val >= mmax)
4757e4b17023SJohn Marino 	    return const_true_rtx;
4758e4b17023SJohn Marino 	  if (val < mmin)
4759e4b17023SJohn Marino 	    return const0_rtx;
4760e4b17023SJohn Marino 	  break;
4761e4b17023SJohn Marino 
4762e4b17023SJohn Marino 	case EQ:
4763e4b17023SJohn Marino 	  /* x == y is always false for y out of range.  */
4764e4b17023SJohn Marino 	  if (val < mmin || val > mmax)
4765e4b17023SJohn Marino 	    return const0_rtx;
4766e4b17023SJohn Marino 	  break;
4767e4b17023SJohn Marino 
4768e4b17023SJohn Marino 	/* x > y is always false for y >= mmax, always true for y < mmin.  */
4769e4b17023SJohn Marino 	case GTU:
4770e4b17023SJohn Marino 	  if ((unsigned HOST_WIDE_INT) val >= (unsigned HOST_WIDE_INT) mmax)
4771e4b17023SJohn Marino 	    return const0_rtx;
4772e4b17023SJohn Marino 	  if ((unsigned HOST_WIDE_INT) val < (unsigned HOST_WIDE_INT) mmin)
4773e4b17023SJohn Marino 	    return const_true_rtx;
4774e4b17023SJohn Marino 	  break;
4775e4b17023SJohn Marino 	case GT:
4776e4b17023SJohn Marino 	  if (val >= mmax)
4777e4b17023SJohn Marino 	    return const0_rtx;
4778e4b17023SJohn Marino 	  if (val < mmin)
4779e4b17023SJohn Marino 	    return const_true_rtx;
4780e4b17023SJohn Marino 	  break;
4781e4b17023SJohn Marino 
4782e4b17023SJohn Marino 	/* x < y is always false for y <= mmin, always true for y > mmax.  */
4783e4b17023SJohn Marino 	case LTU:
4784e4b17023SJohn Marino 	  if ((unsigned HOST_WIDE_INT) val <= (unsigned HOST_WIDE_INT) mmin)
4785e4b17023SJohn Marino 	    return const0_rtx;
4786e4b17023SJohn Marino 	  if ((unsigned HOST_WIDE_INT) val > (unsigned HOST_WIDE_INT) mmax)
4787e4b17023SJohn Marino 	    return const_true_rtx;
4788e4b17023SJohn Marino 	  break;
4789e4b17023SJohn Marino 	case LT:
4790e4b17023SJohn Marino 	  if (val <= mmin)
4791e4b17023SJohn Marino 	    return const0_rtx;
4792e4b17023SJohn Marino 	  if (val > mmax)
4793e4b17023SJohn Marino 	    return const_true_rtx;
4794e4b17023SJohn Marino 	  break;
4795e4b17023SJohn Marino 
4796e4b17023SJohn Marino 	case NE:
4797e4b17023SJohn Marino 	  /* x != y is always true for y out of range.  */
4798e4b17023SJohn Marino 	  if (val < mmin || val > mmax)
4799e4b17023SJohn Marino 	    return const_true_rtx;
4800e4b17023SJohn Marino 	  break;
4801e4b17023SJohn Marino 
4802e4b17023SJohn Marino 	default:
4803e4b17023SJohn Marino 	  break;
4804e4b17023SJohn Marino 	}
4805e4b17023SJohn Marino     }
4806e4b17023SJohn Marino 
4807e4b17023SJohn Marino   /* Optimize integer comparisons with zero.  */
4808e4b17023SJohn Marino   if (trueop1 == const0_rtx)
4809e4b17023SJohn Marino     {
4810e4b17023SJohn Marino       /* Some addresses are known to be nonzero.  We don't know
4811e4b17023SJohn Marino 	 their sign, but equality comparisons are known.  */
4812e4b17023SJohn Marino       if (nonzero_address_p (trueop0))
4813e4b17023SJohn Marino 	{
4814e4b17023SJohn Marino 	  if (code == EQ || code == LEU)
4815e4b17023SJohn Marino 	    return const0_rtx;
4816e4b17023SJohn Marino 	  if (code == NE || code == GTU)
4817e4b17023SJohn Marino 	    return const_true_rtx;
4818e4b17023SJohn Marino 	}
4819e4b17023SJohn Marino 
4820e4b17023SJohn Marino       /* See if the first operand is an IOR with a constant.  If so, we
4821e4b17023SJohn Marino 	 may be able to determine the result of this comparison.  */
4822e4b17023SJohn Marino       if (GET_CODE (op0) == IOR)
4823e4b17023SJohn Marino 	{
4824e4b17023SJohn Marino 	  rtx inner_const = avoid_constant_pool_reference (XEXP (op0, 1));
4825e4b17023SJohn Marino 	  if (CONST_INT_P (inner_const) && inner_const != const0_rtx)
4826e4b17023SJohn Marino 	    {
4827e4b17023SJohn Marino 	      int sign_bitnum = GET_MODE_PRECISION (mode) - 1;
4828e4b17023SJohn Marino 	      int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
4829e4b17023SJohn Marino 			      && (UINTVAL (inner_const)
4830e4b17023SJohn Marino 				  & ((unsigned HOST_WIDE_INT) 1
4831e4b17023SJohn Marino 				     << sign_bitnum)));
4832e4b17023SJohn Marino 
4833e4b17023SJohn Marino 	      switch (code)
4834e4b17023SJohn Marino 		{
4835e4b17023SJohn Marino 		case EQ:
4836e4b17023SJohn Marino 		case LEU:
4837e4b17023SJohn Marino 		  return const0_rtx;
4838e4b17023SJohn Marino 		case NE:
4839e4b17023SJohn Marino 		case GTU:
4840e4b17023SJohn Marino 		  return const_true_rtx;
4841e4b17023SJohn Marino 		case LT:
4842e4b17023SJohn Marino 		case LE:
4843e4b17023SJohn Marino 		  if (has_sign)
4844e4b17023SJohn Marino 		    return const_true_rtx;
4845e4b17023SJohn Marino 		  break;
4846e4b17023SJohn Marino 		case GT:
4847e4b17023SJohn Marino 		case GE:
4848e4b17023SJohn Marino 		  if (has_sign)
4849e4b17023SJohn Marino 		    return const0_rtx;
4850e4b17023SJohn Marino 		  break;
4851e4b17023SJohn Marino 		default:
4852e4b17023SJohn Marino 		  break;
4853e4b17023SJohn Marino 		}
4854e4b17023SJohn Marino 	    }
4855e4b17023SJohn Marino 	}
4856e4b17023SJohn Marino     }
4857e4b17023SJohn Marino 
4858e4b17023SJohn Marino   /* Optimize comparison of ABS with zero.  */
4859e4b17023SJohn Marino   if (trueop1 == CONST0_RTX (mode)
4860e4b17023SJohn Marino       && (GET_CODE (trueop0) == ABS
4861e4b17023SJohn Marino 	  || (GET_CODE (trueop0) == FLOAT_EXTEND
4862e4b17023SJohn Marino 	      && GET_CODE (XEXP (trueop0, 0)) == ABS)))
4863e4b17023SJohn Marino     {
4864e4b17023SJohn Marino       switch (code)
4865e4b17023SJohn Marino 	{
4866e4b17023SJohn Marino 	case LT:
4867e4b17023SJohn Marino 	  /* Optimize abs(x) < 0.0.  */
4868e4b17023SJohn Marino 	  if (!HONOR_SNANS (mode)
4869e4b17023SJohn Marino 	      && (!INTEGRAL_MODE_P (mode)
4870e4b17023SJohn Marino 		  || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
4871e4b17023SJohn Marino 	    {
4872e4b17023SJohn Marino 	      if (INTEGRAL_MODE_P (mode)
4873e4b17023SJohn Marino 		  && (issue_strict_overflow_warning
4874e4b17023SJohn Marino 		      (WARN_STRICT_OVERFLOW_CONDITIONAL)))
4875e4b17023SJohn Marino 		warning (OPT_Wstrict_overflow,
4876e4b17023SJohn Marino 			 ("assuming signed overflow does not occur when "
4877e4b17023SJohn Marino 			  "assuming abs (x) < 0 is false"));
4878e4b17023SJohn Marino 	       return const0_rtx;
4879e4b17023SJohn Marino 	    }
4880e4b17023SJohn Marino 	  break;
4881e4b17023SJohn Marino 
4882e4b17023SJohn Marino 	case GE:
4883e4b17023SJohn Marino 	  /* Optimize abs(x) >= 0.0.  */
4884e4b17023SJohn Marino 	  if (!HONOR_NANS (mode)
4885e4b17023SJohn Marino 	      && (!INTEGRAL_MODE_P (mode)
4886e4b17023SJohn Marino 		  || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
4887e4b17023SJohn Marino 	    {
4888e4b17023SJohn Marino 	      if (INTEGRAL_MODE_P (mode)
4889e4b17023SJohn Marino 	          && (issue_strict_overflow_warning
4890e4b17023SJohn Marino 	    	  (WARN_STRICT_OVERFLOW_CONDITIONAL)))
4891e4b17023SJohn Marino 	        warning (OPT_Wstrict_overflow,
4892e4b17023SJohn Marino 			 ("assuming signed overflow does not occur when "
4893e4b17023SJohn Marino 			  "assuming abs (x) >= 0 is true"));
4894e4b17023SJohn Marino 	      return const_true_rtx;
4895e4b17023SJohn Marino 	    }
4896e4b17023SJohn Marino 	  break;
4897e4b17023SJohn Marino 
4898e4b17023SJohn Marino 	case UNGE:
4899e4b17023SJohn Marino 	  /* Optimize ! (abs(x) < 0.0).  */
4900e4b17023SJohn Marino 	  return const_true_rtx;
4901e4b17023SJohn Marino 
4902e4b17023SJohn Marino 	default:
4903e4b17023SJohn Marino 	  break;
4904e4b17023SJohn Marino 	}
4905e4b17023SJohn Marino     }
4906e4b17023SJohn Marino 
4907e4b17023SJohn Marino   return 0;
4908e4b17023SJohn Marino }
4909e4b17023SJohn Marino 
4910e4b17023SJohn Marino /* Simplify CODE, an operation with result mode MODE and three operands,
4911e4b17023SJohn Marino    OP0, OP1, and OP2.  OP0_MODE was the mode of OP0 before it became
4912e4b17023SJohn Marino    a constant.  Return 0 if no simplifications is possible.  */
4913e4b17023SJohn Marino 
4914e4b17023SJohn Marino rtx
simplify_ternary_operation(enum rtx_code code,enum machine_mode mode,enum machine_mode op0_mode,rtx op0,rtx op1,rtx op2)4915e4b17023SJohn Marino simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
4916e4b17023SJohn Marino 			    enum machine_mode op0_mode, rtx op0, rtx op1,
4917e4b17023SJohn Marino 			    rtx op2)
4918e4b17023SJohn Marino {
4919e4b17023SJohn Marino   unsigned int width = GET_MODE_PRECISION (mode);
4920e4b17023SJohn Marino   bool any_change = false;
4921e4b17023SJohn Marino   rtx tem;
4922e4b17023SJohn Marino 
4923e4b17023SJohn Marino   /* VOIDmode means "infinite" precision.  */
4924e4b17023SJohn Marino   if (width == 0)
4925e4b17023SJohn Marino     width = HOST_BITS_PER_WIDE_INT;
4926e4b17023SJohn Marino 
4927e4b17023SJohn Marino   switch (code)
4928e4b17023SJohn Marino     {
4929e4b17023SJohn Marino     case FMA:
4930e4b17023SJohn Marino       /* Simplify negations around the multiplication.  */
4931e4b17023SJohn Marino       /* -a * -b + c  =>  a * b + c.  */
4932e4b17023SJohn Marino       if (GET_CODE (op0) == NEG)
4933e4b17023SJohn Marino 	{
4934e4b17023SJohn Marino 	  tem = simplify_unary_operation (NEG, mode, op1, mode);
4935e4b17023SJohn Marino 	  if (tem)
4936e4b17023SJohn Marino 	    op1 = tem, op0 = XEXP (op0, 0), any_change = true;
4937e4b17023SJohn Marino 	}
4938e4b17023SJohn Marino       else if (GET_CODE (op1) == NEG)
4939e4b17023SJohn Marino 	{
4940e4b17023SJohn Marino 	  tem = simplify_unary_operation (NEG, mode, op0, mode);
4941e4b17023SJohn Marino 	  if (tem)
4942e4b17023SJohn Marino 	    op0 = tem, op1 = XEXP (op1, 0), any_change = true;
4943e4b17023SJohn Marino 	}
4944e4b17023SJohn Marino 
4945e4b17023SJohn Marino       /* Canonicalize the two multiplication operands.  */
4946e4b17023SJohn Marino       /* a * -b + c  =>  -b * a + c.  */
4947e4b17023SJohn Marino       if (swap_commutative_operands_p (op0, op1))
4948e4b17023SJohn Marino 	tem = op0, op0 = op1, op1 = tem, any_change = true;
4949e4b17023SJohn Marino 
4950e4b17023SJohn Marino       if (any_change)
4951e4b17023SJohn Marino 	return gen_rtx_FMA (mode, op0, op1, op2);
4952e4b17023SJohn Marino       return NULL_RTX;
4953e4b17023SJohn Marino 
4954e4b17023SJohn Marino     case SIGN_EXTRACT:
4955e4b17023SJohn Marino     case ZERO_EXTRACT:
4956e4b17023SJohn Marino       if (CONST_INT_P (op0)
4957e4b17023SJohn Marino 	  && CONST_INT_P (op1)
4958e4b17023SJohn Marino 	  && CONST_INT_P (op2)
4959e4b17023SJohn Marino 	  && ((unsigned) INTVAL (op1) + (unsigned) INTVAL (op2) <= width)
4960e4b17023SJohn Marino 	  && width <= (unsigned) HOST_BITS_PER_WIDE_INT)
4961e4b17023SJohn Marino 	{
4962e4b17023SJohn Marino 	  /* Extracting a bit-field from a constant */
4963e4b17023SJohn Marino 	  unsigned HOST_WIDE_INT val = UINTVAL (op0);
4964e4b17023SJohn Marino 	  HOST_WIDE_INT op1val = INTVAL (op1);
4965e4b17023SJohn Marino 	  HOST_WIDE_INT op2val = INTVAL (op2);
4966e4b17023SJohn Marino 	  if (BITS_BIG_ENDIAN)
4967e4b17023SJohn Marino 	    val >>= GET_MODE_PRECISION (op0_mode) - op2val - op1val;
4968e4b17023SJohn Marino 	  else
4969e4b17023SJohn Marino 	    val >>= op2val;
4970e4b17023SJohn Marino 
4971e4b17023SJohn Marino 	  if (HOST_BITS_PER_WIDE_INT != op1val)
4972e4b17023SJohn Marino 	    {
4973e4b17023SJohn Marino 	      /* First zero-extend.  */
4974e4b17023SJohn Marino 	      val &= ((unsigned HOST_WIDE_INT) 1 << op1val) - 1;
4975e4b17023SJohn Marino 	      /* If desired, propagate sign bit.  */
4976e4b17023SJohn Marino 	      if (code == SIGN_EXTRACT
4977e4b17023SJohn Marino 		  && (val & ((unsigned HOST_WIDE_INT) 1 << (op1val - 1)))
4978e4b17023SJohn Marino 		     != 0)
4979e4b17023SJohn Marino 		val |= ~ (((unsigned HOST_WIDE_INT) 1 << op1val) - 1);
4980e4b17023SJohn Marino 	    }
4981e4b17023SJohn Marino 
4982e4b17023SJohn Marino 	  return gen_int_mode (val, mode);
4983e4b17023SJohn Marino 	}
4984e4b17023SJohn Marino       break;
4985e4b17023SJohn Marino 
4986e4b17023SJohn Marino     case IF_THEN_ELSE:
4987e4b17023SJohn Marino       if (CONST_INT_P (op0))
4988e4b17023SJohn Marino 	return op0 != const0_rtx ? op1 : op2;
4989e4b17023SJohn Marino 
4990e4b17023SJohn Marino       /* Convert c ? a : a into "a".  */
4991e4b17023SJohn Marino       if (rtx_equal_p (op1, op2) && ! side_effects_p (op0))
4992e4b17023SJohn Marino 	return op1;
4993e4b17023SJohn Marino 
4994e4b17023SJohn Marino       /* Convert a != b ? a : b into "a".  */
4995e4b17023SJohn Marino       if (GET_CODE (op0) == NE
4996e4b17023SJohn Marino 	  && ! side_effects_p (op0)
4997e4b17023SJohn Marino 	  && ! HONOR_NANS (mode)
4998e4b17023SJohn Marino 	  && ! HONOR_SIGNED_ZEROS (mode)
4999e4b17023SJohn Marino 	  && ((rtx_equal_p (XEXP (op0, 0), op1)
5000e4b17023SJohn Marino 	       && rtx_equal_p (XEXP (op0, 1), op2))
5001e4b17023SJohn Marino 	      || (rtx_equal_p (XEXP (op0, 0), op2)
5002e4b17023SJohn Marino 		  && rtx_equal_p (XEXP (op0, 1), op1))))
5003e4b17023SJohn Marino 	return op1;
5004e4b17023SJohn Marino 
5005e4b17023SJohn Marino       /* Convert a == b ? a : b into "b".  */
5006e4b17023SJohn Marino       if (GET_CODE (op0) == EQ
5007e4b17023SJohn Marino 	  && ! side_effects_p (op0)
5008e4b17023SJohn Marino 	  && ! HONOR_NANS (mode)
5009e4b17023SJohn Marino 	  && ! HONOR_SIGNED_ZEROS (mode)
5010e4b17023SJohn Marino 	  && ((rtx_equal_p (XEXP (op0, 0), op1)
5011e4b17023SJohn Marino 	       && rtx_equal_p (XEXP (op0, 1), op2))
5012e4b17023SJohn Marino 	      || (rtx_equal_p (XEXP (op0, 0), op2)
5013e4b17023SJohn Marino 		  && rtx_equal_p (XEXP (op0, 1), op1))))
5014e4b17023SJohn Marino 	return op2;
5015e4b17023SJohn Marino 
5016e4b17023SJohn Marino       if (COMPARISON_P (op0) && ! side_effects_p (op0))
5017e4b17023SJohn Marino 	{
5018e4b17023SJohn Marino 	  enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
5019e4b17023SJohn Marino 					? GET_MODE (XEXP (op0, 1))
5020e4b17023SJohn Marino 					: GET_MODE (XEXP (op0, 0)));
5021e4b17023SJohn Marino 	  rtx temp;
5022e4b17023SJohn Marino 
5023e4b17023SJohn Marino 	  /* Look for happy constants in op1 and op2.  */
5024e4b17023SJohn Marino 	  if (CONST_INT_P (op1) && CONST_INT_P (op2))
5025e4b17023SJohn Marino 	    {
5026e4b17023SJohn Marino 	      HOST_WIDE_INT t = INTVAL (op1);
5027e4b17023SJohn Marino 	      HOST_WIDE_INT f = INTVAL (op2);
5028e4b17023SJohn Marino 
5029e4b17023SJohn Marino 	      if (t == STORE_FLAG_VALUE && f == 0)
5030e4b17023SJohn Marino 	        code = GET_CODE (op0);
5031e4b17023SJohn Marino 	      else if (t == 0 && f == STORE_FLAG_VALUE)
5032e4b17023SJohn Marino 		{
5033e4b17023SJohn Marino 		  enum rtx_code tmp;
5034e4b17023SJohn Marino 		  tmp = reversed_comparison_code (op0, NULL_RTX);
5035e4b17023SJohn Marino 		  if (tmp == UNKNOWN)
5036e4b17023SJohn Marino 		    break;
5037e4b17023SJohn Marino 		  code = tmp;
5038e4b17023SJohn Marino 		}
5039e4b17023SJohn Marino 	      else
5040e4b17023SJohn Marino 		break;
5041e4b17023SJohn Marino 
5042e4b17023SJohn Marino 	      return simplify_gen_relational (code, mode, cmp_mode,
5043e4b17023SJohn Marino 					      XEXP (op0, 0), XEXP (op0, 1));
5044e4b17023SJohn Marino 	    }
5045e4b17023SJohn Marino 
5046e4b17023SJohn Marino 	  if (cmp_mode == VOIDmode)
5047e4b17023SJohn Marino 	    cmp_mode = op0_mode;
5048e4b17023SJohn Marino 	  temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
5049e4b17023SJohn Marino 			  			cmp_mode, XEXP (op0, 0),
5050e4b17023SJohn Marino 						XEXP (op0, 1));
5051e4b17023SJohn Marino 
5052e4b17023SJohn Marino 	  /* See if any simplifications were possible.  */
5053e4b17023SJohn Marino 	  if (temp)
5054e4b17023SJohn Marino 	    {
5055e4b17023SJohn Marino 	      if (CONST_INT_P (temp))
5056e4b17023SJohn Marino 		return temp == const0_rtx ? op2 : op1;
5057e4b17023SJohn Marino 	      else if (temp)
5058e4b17023SJohn Marino 	        return gen_rtx_IF_THEN_ELSE (mode, temp, op1, op2);
5059e4b17023SJohn Marino 	    }
5060e4b17023SJohn Marino 	}
5061e4b17023SJohn Marino       break;
5062e4b17023SJohn Marino 
5063e4b17023SJohn Marino     case VEC_MERGE:
5064e4b17023SJohn Marino       gcc_assert (GET_MODE (op0) == mode);
5065e4b17023SJohn Marino       gcc_assert (GET_MODE (op1) == mode);
5066e4b17023SJohn Marino       gcc_assert (VECTOR_MODE_P (mode));
5067e4b17023SJohn Marino       op2 = avoid_constant_pool_reference (op2);
5068e4b17023SJohn Marino       if (CONST_INT_P (op2))
5069e4b17023SJohn Marino 	{
5070e4b17023SJohn Marino           int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
5071e4b17023SJohn Marino 	  unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
5072e4b17023SJohn Marino 	  int mask = (1 << n_elts) - 1;
5073e4b17023SJohn Marino 
5074e4b17023SJohn Marino 	  if (!(INTVAL (op2) & mask))
5075e4b17023SJohn Marino 	    return op1;
5076e4b17023SJohn Marino 	  if ((INTVAL (op2) & mask) == mask)
5077e4b17023SJohn Marino 	    return op0;
5078e4b17023SJohn Marino 
5079e4b17023SJohn Marino 	  op0 = avoid_constant_pool_reference (op0);
5080e4b17023SJohn Marino 	  op1 = avoid_constant_pool_reference (op1);
5081e4b17023SJohn Marino 	  if (GET_CODE (op0) == CONST_VECTOR
5082e4b17023SJohn Marino 	      && GET_CODE (op1) == CONST_VECTOR)
5083e4b17023SJohn Marino 	    {
5084e4b17023SJohn Marino 	      rtvec v = rtvec_alloc (n_elts);
5085e4b17023SJohn Marino 	      unsigned int i;
5086e4b17023SJohn Marino 
5087e4b17023SJohn Marino 	      for (i = 0; i < n_elts; i++)
5088e4b17023SJohn Marino 		RTVEC_ELT (v, i) = (INTVAL (op2) & (1 << i)
5089e4b17023SJohn Marino 				    ? CONST_VECTOR_ELT (op0, i)
5090e4b17023SJohn Marino 				    : CONST_VECTOR_ELT (op1, i));
5091e4b17023SJohn Marino 	      return gen_rtx_CONST_VECTOR (mode, v);
5092e4b17023SJohn Marino 	    }
5093e4b17023SJohn Marino 	}
5094e4b17023SJohn Marino       break;
5095e4b17023SJohn Marino 
5096e4b17023SJohn Marino     default:
5097e4b17023SJohn Marino       gcc_unreachable ();
5098e4b17023SJohn Marino     }
5099e4b17023SJohn Marino 
5100e4b17023SJohn Marino   return 0;
5101e4b17023SJohn Marino }
5102e4b17023SJohn Marino 
5103e4b17023SJohn Marino /* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_FIXED
5104e4b17023SJohn Marino    or CONST_VECTOR,
5105e4b17023SJohn Marino    returning another CONST_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
5106e4b17023SJohn Marino 
5107e4b17023SJohn Marino    Works by unpacking OP into a collection of 8-bit values
5108e4b17023SJohn Marino    represented as a little-endian array of 'unsigned char', selecting by BYTE,
5109e4b17023SJohn Marino    and then repacking them again for OUTERMODE.  */
5110e4b17023SJohn Marino 
5111e4b17023SJohn Marino static rtx
simplify_immed_subreg(enum machine_mode outermode,rtx op,enum machine_mode innermode,unsigned int byte)5112e4b17023SJohn Marino simplify_immed_subreg (enum machine_mode outermode, rtx op,
5113e4b17023SJohn Marino 		       enum machine_mode innermode, unsigned int byte)
5114e4b17023SJohn Marino {
5115e4b17023SJohn Marino   /* We support up to 512-bit values (for V8DFmode).  */
5116e4b17023SJohn Marino   enum {
5117e4b17023SJohn Marino     max_bitsize = 512,
5118e4b17023SJohn Marino     value_bit = 8,
5119e4b17023SJohn Marino     value_mask = (1 << value_bit) - 1
5120e4b17023SJohn Marino   };
5121e4b17023SJohn Marino   unsigned char value[max_bitsize / value_bit];
5122e4b17023SJohn Marino   int value_start;
5123e4b17023SJohn Marino   int i;
5124e4b17023SJohn Marino   int elem;
5125e4b17023SJohn Marino 
5126e4b17023SJohn Marino   int num_elem;
5127e4b17023SJohn Marino   rtx * elems;
5128e4b17023SJohn Marino   int elem_bitsize;
5129e4b17023SJohn Marino   rtx result_s;
5130e4b17023SJohn Marino   rtvec result_v = NULL;
5131e4b17023SJohn Marino   enum mode_class outer_class;
5132e4b17023SJohn Marino   enum machine_mode outer_submode;
5133e4b17023SJohn Marino 
5134e4b17023SJohn Marino   /* Some ports misuse CCmode.  */
5135e4b17023SJohn Marino   if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (op))
5136e4b17023SJohn Marino     return op;
5137e4b17023SJohn Marino 
5138e4b17023SJohn Marino   /* We have no way to represent a complex constant at the rtl level.  */
5139e4b17023SJohn Marino   if (COMPLEX_MODE_P (outermode))
5140e4b17023SJohn Marino     return NULL_RTX;
5141e4b17023SJohn Marino 
5142e4b17023SJohn Marino   /* Unpack the value.  */
5143e4b17023SJohn Marino 
5144e4b17023SJohn Marino   if (GET_CODE (op) == CONST_VECTOR)
5145e4b17023SJohn Marino     {
5146e4b17023SJohn Marino       num_elem = CONST_VECTOR_NUNITS (op);
5147e4b17023SJohn Marino       elems = &CONST_VECTOR_ELT (op, 0);
5148e4b17023SJohn Marino       elem_bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (innermode));
5149e4b17023SJohn Marino     }
5150e4b17023SJohn Marino   else
5151e4b17023SJohn Marino     {
5152e4b17023SJohn Marino       num_elem = 1;
5153e4b17023SJohn Marino       elems = &op;
5154e4b17023SJohn Marino       elem_bitsize = max_bitsize;
5155e4b17023SJohn Marino     }
5156e4b17023SJohn Marino   /* If this asserts, it is too complicated; reducing value_bit may help.  */
5157e4b17023SJohn Marino   gcc_assert (BITS_PER_UNIT % value_bit == 0);
5158e4b17023SJohn Marino   /* I don't know how to handle endianness of sub-units.  */
5159e4b17023SJohn Marino   gcc_assert (elem_bitsize % BITS_PER_UNIT == 0);
5160e4b17023SJohn Marino 
5161e4b17023SJohn Marino   for (elem = 0; elem < num_elem; elem++)
5162e4b17023SJohn Marino     {
5163e4b17023SJohn Marino       unsigned char * vp;
5164e4b17023SJohn Marino       rtx el = elems[elem];
5165e4b17023SJohn Marino 
5166e4b17023SJohn Marino       /* Vectors are kept in target memory order.  (This is probably
5167e4b17023SJohn Marino 	 a mistake.)  */
5168e4b17023SJohn Marino       {
5169e4b17023SJohn Marino 	unsigned byte = (elem * elem_bitsize) / BITS_PER_UNIT;
5170e4b17023SJohn Marino 	unsigned ibyte = (((num_elem - 1 - elem) * elem_bitsize)
5171e4b17023SJohn Marino 			  / BITS_PER_UNIT);
5172e4b17023SJohn Marino 	unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
5173e4b17023SJohn Marino 	unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
5174e4b17023SJohn Marino 	unsigned bytele = (subword_byte % UNITS_PER_WORD
5175e4b17023SJohn Marino 			 + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
5176e4b17023SJohn Marino 	vp = value + (bytele * BITS_PER_UNIT) / value_bit;
5177e4b17023SJohn Marino       }
5178e4b17023SJohn Marino 
5179e4b17023SJohn Marino       switch (GET_CODE (el))
5180e4b17023SJohn Marino 	{
5181e4b17023SJohn Marino 	case CONST_INT:
5182e4b17023SJohn Marino 	  for (i = 0;
5183e4b17023SJohn Marino 	       i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
5184e4b17023SJohn Marino 	       i += value_bit)
5185e4b17023SJohn Marino 	    *vp++ = INTVAL (el) >> i;
5186e4b17023SJohn Marino 	  /* CONST_INTs are always logically sign-extended.  */
5187e4b17023SJohn Marino 	  for (; i < elem_bitsize; i += value_bit)
5188e4b17023SJohn Marino 	    *vp++ = INTVAL (el) < 0 ? -1 : 0;
5189e4b17023SJohn Marino 	  break;
5190e4b17023SJohn Marino 
5191e4b17023SJohn Marino 	case CONST_DOUBLE:
5192e4b17023SJohn Marino 	  if (GET_MODE (el) == VOIDmode)
5193e4b17023SJohn Marino 	    {
5194e4b17023SJohn Marino 	      /* If this triggers, someone should have generated a
5195e4b17023SJohn Marino 		 CONST_INT instead.  */
5196e4b17023SJohn Marino 	      gcc_assert (elem_bitsize > HOST_BITS_PER_WIDE_INT);
5197e4b17023SJohn Marino 
5198e4b17023SJohn Marino 	      for (i = 0; i < HOST_BITS_PER_WIDE_INT; i += value_bit)
5199e4b17023SJohn Marino 		*vp++ = CONST_DOUBLE_LOW (el) >> i;
5200e4b17023SJohn Marino 	      while (i < HOST_BITS_PER_WIDE_INT * 2 && i < elem_bitsize)
5201e4b17023SJohn Marino 		{
5202e4b17023SJohn Marino 		  *vp++
5203e4b17023SJohn Marino 		    = CONST_DOUBLE_HIGH (el) >> (i - HOST_BITS_PER_WIDE_INT);
5204e4b17023SJohn Marino 		  i += value_bit;
5205e4b17023SJohn Marino 		}
5206e4b17023SJohn Marino 	      /* It shouldn't matter what's done here, so fill it with
5207e4b17023SJohn Marino 		 zero.  */
5208e4b17023SJohn Marino 	      for (; i < elem_bitsize; i += value_bit)
5209e4b17023SJohn Marino 		*vp++ = 0;
5210e4b17023SJohn Marino 	    }
5211e4b17023SJohn Marino 	  else
5212e4b17023SJohn Marino 	    {
5213e4b17023SJohn Marino 	      long tmp[max_bitsize / 32];
5214e4b17023SJohn Marino 	      int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
5215e4b17023SJohn Marino 
5216e4b17023SJohn Marino 	      gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
5217e4b17023SJohn Marino 	      gcc_assert (bitsize <= elem_bitsize);
5218e4b17023SJohn Marino 	      gcc_assert (bitsize % value_bit == 0);
5219e4b17023SJohn Marino 
5220e4b17023SJohn Marino 	      real_to_target (tmp, CONST_DOUBLE_REAL_VALUE (el),
5221e4b17023SJohn Marino 			      GET_MODE (el));
5222e4b17023SJohn Marino 
5223e4b17023SJohn Marino 	      /* real_to_target produces its result in words affected by
5224e4b17023SJohn Marino 		 FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
5225e4b17023SJohn Marino 		 and use WORDS_BIG_ENDIAN instead; see the documentation
5226e4b17023SJohn Marino 	         of SUBREG in rtl.texi.  */
5227e4b17023SJohn Marino 	      for (i = 0; i < bitsize; i += value_bit)
5228e4b17023SJohn Marino 		{
5229e4b17023SJohn Marino 		  int ibase;
5230e4b17023SJohn Marino 		  if (WORDS_BIG_ENDIAN)
5231e4b17023SJohn Marino 		    ibase = bitsize - 1 - i;
5232e4b17023SJohn Marino 		  else
5233e4b17023SJohn Marino 		    ibase = i;
5234e4b17023SJohn Marino 		  *vp++ = tmp[ibase / 32] >> i % 32;
5235e4b17023SJohn Marino 		}
5236e4b17023SJohn Marino 
5237e4b17023SJohn Marino 	      /* It shouldn't matter what's done here, so fill it with
5238e4b17023SJohn Marino 		 zero.  */
5239e4b17023SJohn Marino 	      for (; i < elem_bitsize; i += value_bit)
5240e4b17023SJohn Marino 		*vp++ = 0;
5241e4b17023SJohn Marino 	    }
5242e4b17023SJohn Marino 	  break;
5243e4b17023SJohn Marino 
5244e4b17023SJohn Marino         case CONST_FIXED:
5245e4b17023SJohn Marino 	  if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
5246e4b17023SJohn Marino 	    {
5247e4b17023SJohn Marino 	      for (i = 0; i < elem_bitsize; i += value_bit)
5248e4b17023SJohn Marino 		*vp++ = CONST_FIXED_VALUE_LOW (el) >> i;
5249e4b17023SJohn Marino 	    }
5250e4b17023SJohn Marino 	  else
5251e4b17023SJohn Marino 	    {
5252e4b17023SJohn Marino 	      for (i = 0; i < HOST_BITS_PER_WIDE_INT; i += value_bit)
5253e4b17023SJohn Marino 		*vp++ = CONST_FIXED_VALUE_LOW (el) >> i;
5254e4b17023SJohn Marino               for (; i < 2 * HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
5255e4b17023SJohn Marino 		   i += value_bit)
5256e4b17023SJohn Marino 		*vp++ = CONST_FIXED_VALUE_HIGH (el)
5257e4b17023SJohn Marino 			>> (i - HOST_BITS_PER_WIDE_INT);
5258e4b17023SJohn Marino 	      for (; i < elem_bitsize; i += value_bit)
5259e4b17023SJohn Marino 		*vp++ = 0;
5260e4b17023SJohn Marino 	    }
5261e4b17023SJohn Marino           break;
5262e4b17023SJohn Marino 
5263e4b17023SJohn Marino 	default:
5264e4b17023SJohn Marino 	  gcc_unreachable ();
5265e4b17023SJohn Marino 	}
5266e4b17023SJohn Marino     }
5267e4b17023SJohn Marino 
5268e4b17023SJohn Marino   /* Now, pick the right byte to start with.  */
5269e4b17023SJohn Marino   /* Renumber BYTE so that the least-significant byte is byte 0.  A special
5270e4b17023SJohn Marino      case is paradoxical SUBREGs, which shouldn't be adjusted since they
5271e4b17023SJohn Marino      will already have offset 0.  */
5272e4b17023SJohn Marino   if (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode))
5273e4b17023SJohn Marino     {
5274e4b17023SJohn Marino       unsigned ibyte = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)
5275e4b17023SJohn Marino 			- byte);
5276e4b17023SJohn Marino       unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
5277e4b17023SJohn Marino       unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
5278e4b17023SJohn Marino       byte = (subword_byte % UNITS_PER_WORD
5279e4b17023SJohn Marino 	      + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
5280e4b17023SJohn Marino     }
5281e4b17023SJohn Marino 
5282e4b17023SJohn Marino   /* BYTE should still be inside OP.  (Note that BYTE is unsigned,
5283e4b17023SJohn Marino      so if it's become negative it will instead be very large.)  */
5284e4b17023SJohn Marino   gcc_assert (byte < GET_MODE_SIZE (innermode));
5285e4b17023SJohn Marino 
5286e4b17023SJohn Marino   /* Convert from bytes to chunks of size value_bit.  */
5287e4b17023SJohn Marino   value_start = byte * (BITS_PER_UNIT / value_bit);
5288e4b17023SJohn Marino 
5289e4b17023SJohn Marino   /* Re-pack the value.  */
5290e4b17023SJohn Marino 
5291e4b17023SJohn Marino   if (VECTOR_MODE_P (outermode))
5292e4b17023SJohn Marino     {
5293e4b17023SJohn Marino       num_elem = GET_MODE_NUNITS (outermode);
5294e4b17023SJohn Marino       result_v = rtvec_alloc (num_elem);
5295e4b17023SJohn Marino       elems = &RTVEC_ELT (result_v, 0);
5296e4b17023SJohn Marino       outer_submode = GET_MODE_INNER (outermode);
5297e4b17023SJohn Marino     }
5298e4b17023SJohn Marino   else
5299e4b17023SJohn Marino     {
5300e4b17023SJohn Marino       num_elem = 1;
5301e4b17023SJohn Marino       elems = &result_s;
5302e4b17023SJohn Marino       outer_submode = outermode;
5303e4b17023SJohn Marino     }
5304e4b17023SJohn Marino 
5305e4b17023SJohn Marino   outer_class = GET_MODE_CLASS (outer_submode);
5306e4b17023SJohn Marino   elem_bitsize = GET_MODE_BITSIZE (outer_submode);
5307e4b17023SJohn Marino 
5308e4b17023SJohn Marino   gcc_assert (elem_bitsize % value_bit == 0);
5309e4b17023SJohn Marino   gcc_assert (elem_bitsize + value_start * value_bit <= max_bitsize);
5310e4b17023SJohn Marino 
5311e4b17023SJohn Marino   for (elem = 0; elem < num_elem; elem++)
5312e4b17023SJohn Marino     {
5313e4b17023SJohn Marino       unsigned char *vp;
5314e4b17023SJohn Marino 
5315e4b17023SJohn Marino       /* Vectors are stored in target memory order.  (This is probably
5316e4b17023SJohn Marino 	 a mistake.)  */
5317e4b17023SJohn Marino       {
5318e4b17023SJohn Marino 	unsigned byte = (elem * elem_bitsize) / BITS_PER_UNIT;
5319e4b17023SJohn Marino 	unsigned ibyte = (((num_elem - 1 - elem) * elem_bitsize)
5320e4b17023SJohn Marino 			  / BITS_PER_UNIT);
5321e4b17023SJohn Marino 	unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
5322e4b17023SJohn Marino 	unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
5323e4b17023SJohn Marino 	unsigned bytele = (subword_byte % UNITS_PER_WORD
5324e4b17023SJohn Marino 			 + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD);
5325e4b17023SJohn Marino 	vp = value + value_start + (bytele * BITS_PER_UNIT) / value_bit;
5326e4b17023SJohn Marino       }
5327e4b17023SJohn Marino 
5328e4b17023SJohn Marino       switch (outer_class)
5329e4b17023SJohn Marino 	{
5330e4b17023SJohn Marino 	case MODE_INT:
5331e4b17023SJohn Marino 	case MODE_PARTIAL_INT:
5332e4b17023SJohn Marino 	  {
5333e4b17023SJohn Marino 	    unsigned HOST_WIDE_INT hi = 0, lo = 0;
5334e4b17023SJohn Marino 
5335e4b17023SJohn Marino 	    for (i = 0;
5336e4b17023SJohn Marino 		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
5337e4b17023SJohn Marino 		 i += value_bit)
5338e4b17023SJohn Marino 	      lo |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
5339e4b17023SJohn Marino 	    for (; i < elem_bitsize; i += value_bit)
5340e4b17023SJohn Marino 	      hi |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask)
5341e4b17023SJohn Marino 		     << (i - HOST_BITS_PER_WIDE_INT);
5342e4b17023SJohn Marino 
5343e4b17023SJohn Marino 	    /* immed_double_const doesn't call trunc_int_for_mode.  I don't
5344e4b17023SJohn Marino 	       know why.  */
5345e4b17023SJohn Marino 	    if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
5346e4b17023SJohn Marino 	      elems[elem] = gen_int_mode (lo, outer_submode);
5347e4b17023SJohn Marino 	    else if (elem_bitsize <= 2 * HOST_BITS_PER_WIDE_INT)
5348e4b17023SJohn Marino 	      elems[elem] = immed_double_const (lo, hi, outer_submode);
5349e4b17023SJohn Marino 	    else
5350e4b17023SJohn Marino 	      return NULL_RTX;
5351e4b17023SJohn Marino 	  }
5352e4b17023SJohn Marino 	  break;
5353e4b17023SJohn Marino 
5354e4b17023SJohn Marino 	case MODE_FLOAT:
5355e4b17023SJohn Marino 	case MODE_DECIMAL_FLOAT:
5356e4b17023SJohn Marino 	  {
5357e4b17023SJohn Marino 	    REAL_VALUE_TYPE r;
5358e4b17023SJohn Marino 	    long tmp[max_bitsize / 32];
5359e4b17023SJohn Marino 
5360e4b17023SJohn Marino 	    /* real_from_target wants its input in words affected by
5361e4b17023SJohn Marino 	       FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
5362e4b17023SJohn Marino 	       and use WORDS_BIG_ENDIAN instead; see the documentation
5363e4b17023SJohn Marino 	       of SUBREG in rtl.texi.  */
5364e4b17023SJohn Marino 	    for (i = 0; i < max_bitsize / 32; i++)
5365e4b17023SJohn Marino 	      tmp[i] = 0;
5366e4b17023SJohn Marino 	    for (i = 0; i < elem_bitsize; i += value_bit)
5367e4b17023SJohn Marino 	      {
5368e4b17023SJohn Marino 		int ibase;
5369e4b17023SJohn Marino 		if (WORDS_BIG_ENDIAN)
5370e4b17023SJohn Marino 		  ibase = elem_bitsize - 1 - i;
5371e4b17023SJohn Marino 		else
5372e4b17023SJohn Marino 		  ibase = i;
5373e4b17023SJohn Marino 		tmp[ibase / 32] |= (*vp++ & value_mask) << i % 32;
5374e4b17023SJohn Marino 	      }
5375e4b17023SJohn Marino 
5376e4b17023SJohn Marino 	    real_from_target (&r, tmp, outer_submode);
5377e4b17023SJohn Marino 	    elems[elem] = CONST_DOUBLE_FROM_REAL_VALUE (r, outer_submode);
5378e4b17023SJohn Marino 	  }
5379e4b17023SJohn Marino 	  break;
5380e4b17023SJohn Marino 
5381e4b17023SJohn Marino 	case MODE_FRACT:
5382e4b17023SJohn Marino 	case MODE_UFRACT:
5383e4b17023SJohn Marino 	case MODE_ACCUM:
5384e4b17023SJohn Marino 	case MODE_UACCUM:
5385e4b17023SJohn Marino 	  {
5386e4b17023SJohn Marino 	    FIXED_VALUE_TYPE f;
5387e4b17023SJohn Marino 	    f.data.low = 0;
5388e4b17023SJohn Marino 	    f.data.high = 0;
5389e4b17023SJohn Marino 	    f.mode = outer_submode;
5390e4b17023SJohn Marino 
5391e4b17023SJohn Marino 	    for (i = 0;
5392e4b17023SJohn Marino 		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
5393e4b17023SJohn Marino 		 i += value_bit)
5394e4b17023SJohn Marino 	      f.data.low |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
5395e4b17023SJohn Marino 	    for (; i < elem_bitsize; i += value_bit)
5396e4b17023SJohn Marino 	      f.data.high |= ((unsigned HOST_WIDE_INT)(*vp++ & value_mask)
5397e4b17023SJohn Marino 			     << (i - HOST_BITS_PER_WIDE_INT));
5398e4b17023SJohn Marino 
5399e4b17023SJohn Marino 	    elems[elem] = CONST_FIXED_FROM_FIXED_VALUE (f, outer_submode);
5400e4b17023SJohn Marino           }
5401e4b17023SJohn Marino           break;
5402e4b17023SJohn Marino 
5403e4b17023SJohn Marino 	default:
5404e4b17023SJohn Marino 	  gcc_unreachable ();
5405e4b17023SJohn Marino 	}
5406e4b17023SJohn Marino     }
5407e4b17023SJohn Marino   if (VECTOR_MODE_P (outermode))
5408e4b17023SJohn Marino     return gen_rtx_CONST_VECTOR (outermode, result_v);
5409e4b17023SJohn Marino   else
5410e4b17023SJohn Marino     return result_s;
5411e4b17023SJohn Marino }
5412e4b17023SJohn Marino 
5413e4b17023SJohn Marino /* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
5414e4b17023SJohn Marino    Return 0 if no simplifications are possible.  */
5415e4b17023SJohn Marino rtx
simplify_subreg(enum machine_mode outermode,rtx op,enum machine_mode innermode,unsigned int byte)5416e4b17023SJohn Marino simplify_subreg (enum machine_mode outermode, rtx op,
5417e4b17023SJohn Marino 		 enum machine_mode innermode, unsigned int byte)
5418e4b17023SJohn Marino {
5419e4b17023SJohn Marino   /* Little bit of sanity checking.  */
5420e4b17023SJohn Marino   gcc_assert (innermode != VOIDmode);
5421e4b17023SJohn Marino   gcc_assert (outermode != VOIDmode);
5422e4b17023SJohn Marino   gcc_assert (innermode != BLKmode);
5423e4b17023SJohn Marino   gcc_assert (outermode != BLKmode);
5424e4b17023SJohn Marino 
5425e4b17023SJohn Marino   gcc_assert (GET_MODE (op) == innermode
5426e4b17023SJohn Marino 	      || GET_MODE (op) == VOIDmode);
5427e4b17023SJohn Marino 
5428e4b17023SJohn Marino   gcc_assert ((byte % GET_MODE_SIZE (outermode)) == 0);
5429e4b17023SJohn Marino   gcc_assert (byte < GET_MODE_SIZE (innermode));
5430e4b17023SJohn Marino 
5431e4b17023SJohn Marino   if (outermode == innermode && !byte)
5432e4b17023SJohn Marino     return op;
5433e4b17023SJohn Marino 
5434e4b17023SJohn Marino   if (CONST_INT_P (op)
5435e4b17023SJohn Marino       || GET_CODE (op) == CONST_DOUBLE
5436e4b17023SJohn Marino       || GET_CODE (op) == CONST_FIXED
5437e4b17023SJohn Marino       || GET_CODE (op) == CONST_VECTOR)
5438e4b17023SJohn Marino     return simplify_immed_subreg (outermode, op, innermode, byte);
5439e4b17023SJohn Marino 
5440e4b17023SJohn Marino   /* Changing mode twice with SUBREG => just change it once,
5441e4b17023SJohn Marino      or not at all if changing back op starting mode.  */
5442e4b17023SJohn Marino   if (GET_CODE (op) == SUBREG)
5443e4b17023SJohn Marino     {
5444e4b17023SJohn Marino       enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
5445e4b17023SJohn Marino       int final_offset = byte + SUBREG_BYTE (op);
5446e4b17023SJohn Marino       rtx newx;
5447e4b17023SJohn Marino 
5448e4b17023SJohn Marino       if (outermode == innermostmode
5449e4b17023SJohn Marino 	  && byte == 0 && SUBREG_BYTE (op) == 0)
5450e4b17023SJohn Marino 	return SUBREG_REG (op);
5451e4b17023SJohn Marino 
5452e4b17023SJohn Marino       /* The SUBREG_BYTE represents offset, as if the value were stored
5453e4b17023SJohn Marino 	 in memory.  Irritating exception is paradoxical subreg, where
5454e4b17023SJohn Marino 	 we define SUBREG_BYTE to be 0.  On big endian machines, this
5455e4b17023SJohn Marino 	 value should be negative.  For a moment, undo this exception.  */
5456e4b17023SJohn Marino       if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
5457e4b17023SJohn Marino 	{
5458e4b17023SJohn Marino 	  int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
5459e4b17023SJohn Marino 	  if (WORDS_BIG_ENDIAN)
5460e4b17023SJohn Marino 	    final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
5461e4b17023SJohn Marino 	  if (BYTES_BIG_ENDIAN)
5462e4b17023SJohn Marino 	    final_offset += difference % UNITS_PER_WORD;
5463e4b17023SJohn Marino 	}
5464e4b17023SJohn Marino       if (SUBREG_BYTE (op) == 0
5465e4b17023SJohn Marino 	  && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
5466e4b17023SJohn Marino 	{
5467e4b17023SJohn Marino 	  int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
5468e4b17023SJohn Marino 	  if (WORDS_BIG_ENDIAN)
5469e4b17023SJohn Marino 	    final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
5470e4b17023SJohn Marino 	  if (BYTES_BIG_ENDIAN)
5471e4b17023SJohn Marino 	    final_offset += difference % UNITS_PER_WORD;
5472e4b17023SJohn Marino 	}
5473e4b17023SJohn Marino 
5474e4b17023SJohn Marino       /* See whether resulting subreg will be paradoxical.  */
5475e4b17023SJohn Marino       if (GET_MODE_SIZE (innermostmode) > GET_MODE_SIZE (outermode))
5476e4b17023SJohn Marino 	{
5477e4b17023SJohn Marino 	  /* In nonparadoxical subregs we can't handle negative offsets.  */
5478e4b17023SJohn Marino 	  if (final_offset < 0)
5479e4b17023SJohn Marino 	    return NULL_RTX;
5480e4b17023SJohn Marino 	  /* Bail out in case resulting subreg would be incorrect.  */
5481e4b17023SJohn Marino 	  if (final_offset % GET_MODE_SIZE (outermode)
5482e4b17023SJohn Marino 	      || (unsigned) final_offset >= GET_MODE_SIZE (innermostmode))
5483e4b17023SJohn Marino 	    return NULL_RTX;
5484e4b17023SJohn Marino 	}
5485e4b17023SJohn Marino       else
5486e4b17023SJohn Marino 	{
5487e4b17023SJohn Marino 	  int offset = 0;
5488e4b17023SJohn Marino 	  int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode));
5489e4b17023SJohn Marino 
5490e4b17023SJohn Marino 	  /* In paradoxical subreg, see if we are still looking on lower part.
5491e4b17023SJohn Marino 	     If so, our SUBREG_BYTE will be 0.  */
5492e4b17023SJohn Marino 	  if (WORDS_BIG_ENDIAN)
5493e4b17023SJohn Marino 	    offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
5494e4b17023SJohn Marino 	  if (BYTES_BIG_ENDIAN)
5495e4b17023SJohn Marino 	    offset += difference % UNITS_PER_WORD;
5496e4b17023SJohn Marino 	  if (offset == final_offset)
5497e4b17023SJohn Marino 	    final_offset = 0;
5498e4b17023SJohn Marino 	  else
5499e4b17023SJohn Marino 	    return NULL_RTX;
5500e4b17023SJohn Marino 	}
5501e4b17023SJohn Marino 
5502e4b17023SJohn Marino       /* Recurse for further possible simplifications.  */
5503e4b17023SJohn Marino       newx = simplify_subreg (outermode, SUBREG_REG (op), innermostmode,
5504e4b17023SJohn Marino 			      final_offset);
5505e4b17023SJohn Marino       if (newx)
5506e4b17023SJohn Marino 	return newx;
5507e4b17023SJohn Marino       if (validate_subreg (outermode, innermostmode,
5508e4b17023SJohn Marino 			   SUBREG_REG (op), final_offset))
5509e4b17023SJohn Marino 	{
5510e4b17023SJohn Marino 	  newx = gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
5511e4b17023SJohn Marino 	  if (SUBREG_PROMOTED_VAR_P (op)
5512e4b17023SJohn Marino 	      && SUBREG_PROMOTED_UNSIGNED_P (op) >= 0
5513e4b17023SJohn Marino 	      && GET_MODE_CLASS (outermode) == MODE_INT
5514e4b17023SJohn Marino 	      && IN_RANGE (GET_MODE_SIZE (outermode),
5515e4b17023SJohn Marino 			   GET_MODE_SIZE (innermode),
5516e4b17023SJohn Marino 			   GET_MODE_SIZE (innermostmode))
5517e4b17023SJohn Marino 	      && subreg_lowpart_p (newx))
5518e4b17023SJohn Marino 	    {
5519e4b17023SJohn Marino 	      SUBREG_PROMOTED_VAR_P (newx) = 1;
5520e4b17023SJohn Marino 	      SUBREG_PROMOTED_UNSIGNED_SET
5521e4b17023SJohn Marino 		(newx, SUBREG_PROMOTED_UNSIGNED_P (op));
5522e4b17023SJohn Marino 	    }
5523e4b17023SJohn Marino 	  return newx;
5524e4b17023SJohn Marino 	}
5525e4b17023SJohn Marino       return NULL_RTX;
5526e4b17023SJohn Marino     }
5527e4b17023SJohn Marino 
5528e4b17023SJohn Marino   /* Merge implicit and explicit truncations.  */
5529e4b17023SJohn Marino 
5530e4b17023SJohn Marino   if (GET_CODE (op) == TRUNCATE
5531e4b17023SJohn Marino       && GET_MODE_SIZE (outermode) < GET_MODE_SIZE (innermode)
5532e4b17023SJohn Marino       && subreg_lowpart_offset (outermode, innermode) == byte)
5533e4b17023SJohn Marino     return simplify_gen_unary (TRUNCATE, outermode, XEXP (op, 0),
5534e4b17023SJohn Marino 			       GET_MODE (XEXP (op, 0)));
5535e4b17023SJohn Marino 
5536e4b17023SJohn Marino   /* SUBREG of a hard register => just change the register number
5537e4b17023SJohn Marino      and/or mode.  If the hard register is not valid in that mode,
5538e4b17023SJohn Marino      suppress this simplification.  If the hard register is the stack,
5539e4b17023SJohn Marino      frame, or argument pointer, leave this as a SUBREG.  */
5540e4b17023SJohn Marino 
5541e4b17023SJohn Marino   if (REG_P (op) && HARD_REGISTER_P (op))
5542e4b17023SJohn Marino     {
5543e4b17023SJohn Marino       unsigned int regno, final_regno;
5544e4b17023SJohn Marino 
5545e4b17023SJohn Marino       regno = REGNO (op);
5546e4b17023SJohn Marino       final_regno = simplify_subreg_regno (regno, innermode, byte, outermode);
5547e4b17023SJohn Marino       if (HARD_REGISTER_NUM_P (final_regno))
5548e4b17023SJohn Marino 	{
5549e4b17023SJohn Marino 	  rtx x;
5550e4b17023SJohn Marino 	  int final_offset = byte;
5551e4b17023SJohn Marino 
5552e4b17023SJohn Marino 	  /* Adjust offset for paradoxical subregs.  */
5553e4b17023SJohn Marino 	  if (byte == 0
5554e4b17023SJohn Marino 	      && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
5555e4b17023SJohn Marino 	    {
5556e4b17023SJohn Marino 	      int difference = (GET_MODE_SIZE (innermode)
5557e4b17023SJohn Marino 				- GET_MODE_SIZE (outermode));
5558e4b17023SJohn Marino 	      if (WORDS_BIG_ENDIAN)
5559e4b17023SJohn Marino 		final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
5560e4b17023SJohn Marino 	      if (BYTES_BIG_ENDIAN)
5561e4b17023SJohn Marino 		final_offset += difference % UNITS_PER_WORD;
5562e4b17023SJohn Marino 	    }
5563e4b17023SJohn Marino 
5564e4b17023SJohn Marino 	  x = gen_rtx_REG_offset (op, outermode, final_regno, final_offset);
5565e4b17023SJohn Marino 
5566e4b17023SJohn Marino 	  /* Propagate original regno.  We don't have any way to specify
5567e4b17023SJohn Marino 	     the offset inside original regno, so do so only for lowpart.
5568e4b17023SJohn Marino 	     The information is used only by alias analysis that can not
5569e4b17023SJohn Marino 	     grog partial register anyway.  */
5570e4b17023SJohn Marino 
5571e4b17023SJohn Marino 	  if (subreg_lowpart_offset (outermode, innermode) == byte)
5572e4b17023SJohn Marino 	    ORIGINAL_REGNO (x) = ORIGINAL_REGNO (op);
5573e4b17023SJohn Marino 	  return x;
5574e4b17023SJohn Marino 	}
5575e4b17023SJohn Marino     }
5576e4b17023SJohn Marino 
5577e4b17023SJohn Marino   /* If we have a SUBREG of a register that we are replacing and we are
5578e4b17023SJohn Marino      replacing it with a MEM, make a new MEM and try replacing the
5579e4b17023SJohn Marino      SUBREG with it.  Don't do this if the MEM has a mode-dependent address
5580e4b17023SJohn Marino      or if we would be widening it.  */
5581e4b17023SJohn Marino 
5582e4b17023SJohn Marino   if (MEM_P (op)
5583e4b17023SJohn Marino       && ! mode_dependent_address_p (XEXP (op, 0))
5584e4b17023SJohn Marino       /* Allow splitting of volatile memory references in case we don't
5585e4b17023SJohn Marino          have instruction to move the whole thing.  */
5586e4b17023SJohn Marino       && (! MEM_VOLATILE_P (op)
5587e4b17023SJohn Marino 	  || ! have_insn_for (SET, innermode))
5588e4b17023SJohn Marino       && GET_MODE_SIZE (outermode) <= GET_MODE_SIZE (GET_MODE (op)))
5589e4b17023SJohn Marino     return adjust_address_nv (op, outermode, byte);
5590e4b17023SJohn Marino 
5591e4b17023SJohn Marino   /* Handle complex values represented as CONCAT
5592e4b17023SJohn Marino      of real and imaginary part.  */
5593e4b17023SJohn Marino   if (GET_CODE (op) == CONCAT)
5594e4b17023SJohn Marino     {
5595e4b17023SJohn Marino       unsigned int part_size, final_offset;
5596e4b17023SJohn Marino       rtx part, res;
5597e4b17023SJohn Marino 
5598e4b17023SJohn Marino       part_size = GET_MODE_UNIT_SIZE (GET_MODE (XEXP (op, 0)));
5599e4b17023SJohn Marino       if (byte < part_size)
5600e4b17023SJohn Marino 	{
5601e4b17023SJohn Marino 	  part = XEXP (op, 0);
5602e4b17023SJohn Marino 	  final_offset = byte;
5603e4b17023SJohn Marino 	}
5604e4b17023SJohn Marino       else
5605e4b17023SJohn Marino 	{
5606e4b17023SJohn Marino 	  part = XEXP (op, 1);
5607e4b17023SJohn Marino 	  final_offset = byte - part_size;
5608e4b17023SJohn Marino 	}
5609e4b17023SJohn Marino 
5610e4b17023SJohn Marino       if (final_offset + GET_MODE_SIZE (outermode) > part_size)
5611e4b17023SJohn Marino 	return NULL_RTX;
5612e4b17023SJohn Marino 
5613e4b17023SJohn Marino       res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
5614e4b17023SJohn Marino       if (res)
5615e4b17023SJohn Marino 	return res;
5616e4b17023SJohn Marino       if (validate_subreg (outermode, GET_MODE (part), part, final_offset))
5617e4b17023SJohn Marino 	return gen_rtx_SUBREG (outermode, part, final_offset);
5618e4b17023SJohn Marino       return NULL_RTX;
5619e4b17023SJohn Marino     }
5620e4b17023SJohn Marino 
5621e4b17023SJohn Marino   /* Optimize SUBREG truncations of zero and sign extended values.  */
5622e4b17023SJohn Marino   if ((GET_CODE (op) == ZERO_EXTEND
5623e4b17023SJohn Marino        || GET_CODE (op) == SIGN_EXTEND)
5624e4b17023SJohn Marino       && SCALAR_INT_MODE_P (innermode)
5625e4b17023SJohn Marino       && GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode))
5626e4b17023SJohn Marino     {
5627e4b17023SJohn Marino       unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
5628e4b17023SJohn Marino 
5629e4b17023SJohn Marino       /* If we're requesting the lowpart of a zero or sign extension,
5630e4b17023SJohn Marino 	 there are three possibilities.  If the outermode is the same
5631e4b17023SJohn Marino 	 as the origmode, we can omit both the extension and the subreg.
5632e4b17023SJohn Marino 	 If the outermode is not larger than the origmode, we can apply
5633e4b17023SJohn Marino 	 the truncation without the extension.  Finally, if the outermode
5634e4b17023SJohn Marino 	 is larger than the origmode, but both are integer modes, we
5635e4b17023SJohn Marino 	 can just extend to the appropriate mode.  */
5636e4b17023SJohn Marino       if (bitpos == 0)
5637e4b17023SJohn Marino 	{
5638e4b17023SJohn Marino 	  enum machine_mode origmode = GET_MODE (XEXP (op, 0));
5639e4b17023SJohn Marino 	  if (outermode == origmode)
5640e4b17023SJohn Marino 	    return XEXP (op, 0);
5641e4b17023SJohn Marino 	  if (GET_MODE_PRECISION (outermode) <= GET_MODE_PRECISION (origmode))
5642e4b17023SJohn Marino 	    return simplify_gen_subreg (outermode, XEXP (op, 0), origmode,
5643e4b17023SJohn Marino 					subreg_lowpart_offset (outermode,
5644e4b17023SJohn Marino 							       origmode));
5645e4b17023SJohn Marino 	  if (SCALAR_INT_MODE_P (outermode))
5646e4b17023SJohn Marino 	    return simplify_gen_unary (GET_CODE (op), outermode,
5647e4b17023SJohn Marino 				       XEXP (op, 0), origmode);
5648e4b17023SJohn Marino 	}
5649e4b17023SJohn Marino 
5650e4b17023SJohn Marino       /* A SUBREG resulting from a zero extension may fold to zero if
5651e4b17023SJohn Marino 	 it extracts higher bits that the ZERO_EXTEND's source bits.  */
5652e4b17023SJohn Marino       if (GET_CODE (op) == ZERO_EXTEND
5653e4b17023SJohn Marino 	  && bitpos >= GET_MODE_PRECISION (GET_MODE (XEXP (op, 0))))
5654e4b17023SJohn Marino 	return CONST0_RTX (outermode);
5655e4b17023SJohn Marino     }
5656e4b17023SJohn Marino 
5657e4b17023SJohn Marino   /* Simplify (subreg:QI (lshiftrt:SI (sign_extend:SI (x:QI)) C), 0) into
5658e4b17023SJohn Marino      to (ashiftrt:QI (x:QI) C), where C is a suitable small constant and
5659e4b17023SJohn Marino      the outer subreg is effectively a truncation to the original mode.  */
5660e4b17023SJohn Marino   if ((GET_CODE (op) == LSHIFTRT
5661e4b17023SJohn Marino        || GET_CODE (op) == ASHIFTRT)
5662e4b17023SJohn Marino       && SCALAR_INT_MODE_P (outermode)
5663e4b17023SJohn Marino       && SCALAR_INT_MODE_P (innermode)
5664e4b17023SJohn Marino       /* Ensure that OUTERMODE is at least twice as wide as the INNERMODE
5665e4b17023SJohn Marino 	 to avoid the possibility that an outer LSHIFTRT shifts by more
5666e4b17023SJohn Marino 	 than the sign extension's sign_bit_copies and introduces zeros
5667e4b17023SJohn Marino 	 into the high bits of the result.  */
5668e4b17023SJohn Marino       && (2 * GET_MODE_PRECISION (outermode)) <= GET_MODE_PRECISION (innermode)
5669e4b17023SJohn Marino       && CONST_INT_P (XEXP (op, 1))
5670e4b17023SJohn Marino       && GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
5671e4b17023SJohn Marino       && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
5672e4b17023SJohn Marino       && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
5673e4b17023SJohn Marino       && subreg_lsb_1 (outermode, innermode, byte) == 0)
5674e4b17023SJohn Marino     return simplify_gen_binary (ASHIFTRT, outermode,
5675e4b17023SJohn Marino 				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
5676e4b17023SJohn Marino 
5677e4b17023SJohn Marino   /* Likewise (subreg:QI (lshiftrt:SI (zero_extend:SI (x:QI)) C), 0) into
5678e4b17023SJohn Marino      to (lshiftrt:QI (x:QI) C), where C is a suitable small constant and
5679e4b17023SJohn Marino      the outer subreg is effectively a truncation to the original mode.  */
5680e4b17023SJohn Marino   if ((GET_CODE (op) == LSHIFTRT
5681e4b17023SJohn Marino        || GET_CODE (op) == ASHIFTRT)
5682e4b17023SJohn Marino       && SCALAR_INT_MODE_P (outermode)
5683e4b17023SJohn Marino       && SCALAR_INT_MODE_P (innermode)
5684e4b17023SJohn Marino       && GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
5685e4b17023SJohn Marino       && CONST_INT_P (XEXP (op, 1))
5686e4b17023SJohn Marino       && GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
5687e4b17023SJohn Marino       && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
5688e4b17023SJohn Marino       && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
5689e4b17023SJohn Marino       && subreg_lsb_1 (outermode, innermode, byte) == 0)
5690e4b17023SJohn Marino     return simplify_gen_binary (LSHIFTRT, outermode,
5691e4b17023SJohn Marino 				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
5692e4b17023SJohn Marino 
5693e4b17023SJohn Marino   /* Likewise (subreg:QI (ashift:SI (zero_extend:SI (x:QI)) C), 0) into
5694e4b17023SJohn Marino      to (ashift:QI (x:QI) C), where C is a suitable small constant and
5695e4b17023SJohn Marino      the outer subreg is effectively a truncation to the original mode.  */
5696e4b17023SJohn Marino   if (GET_CODE (op) == ASHIFT
5697e4b17023SJohn Marino       && SCALAR_INT_MODE_P (outermode)
5698e4b17023SJohn Marino       && SCALAR_INT_MODE_P (innermode)
5699e4b17023SJohn Marino       && GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
5700e4b17023SJohn Marino       && CONST_INT_P (XEXP (op, 1))
5701e4b17023SJohn Marino       && (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
5702e4b17023SJohn Marino 	  || GET_CODE (XEXP (op, 0)) == SIGN_EXTEND)
5703e4b17023SJohn Marino       && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
5704e4b17023SJohn Marino       && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
5705e4b17023SJohn Marino       && subreg_lsb_1 (outermode, innermode, byte) == 0)
5706e4b17023SJohn Marino     return simplify_gen_binary (ASHIFT, outermode,
5707e4b17023SJohn Marino 				XEXP (XEXP (op, 0), 0), XEXP (op, 1));
5708e4b17023SJohn Marino 
5709e4b17023SJohn Marino   /* Recognize a word extraction from a multi-word subreg.  */
5710e4b17023SJohn Marino   if ((GET_CODE (op) == LSHIFTRT
5711e4b17023SJohn Marino        || GET_CODE (op) == ASHIFTRT)
5712e4b17023SJohn Marino       && SCALAR_INT_MODE_P (innermode)
5713e4b17023SJohn Marino       && GET_MODE_PRECISION (outermode) >= BITS_PER_WORD
5714e4b17023SJohn Marino       && GET_MODE_PRECISION (innermode) >= (2 * GET_MODE_PRECISION (outermode))
5715e4b17023SJohn Marino       && CONST_INT_P (XEXP (op, 1))
5716e4b17023SJohn Marino       && (INTVAL (XEXP (op, 1)) & (GET_MODE_PRECISION (outermode) - 1)) == 0
5717e4b17023SJohn Marino       && INTVAL (XEXP (op, 1)) >= 0
5718e4b17023SJohn Marino       && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (innermode)
5719e4b17023SJohn Marino       && byte == subreg_lowpart_offset (outermode, innermode))
5720e4b17023SJohn Marino     {
5721e4b17023SJohn Marino       int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
5722e4b17023SJohn Marino       return simplify_gen_subreg (outermode, XEXP (op, 0), innermode,
5723e4b17023SJohn Marino 				  (WORDS_BIG_ENDIAN
5724e4b17023SJohn Marino 				   ? byte - shifted_bytes
5725e4b17023SJohn Marino 				   : byte + shifted_bytes));
5726e4b17023SJohn Marino     }
5727e4b17023SJohn Marino 
5728e4b17023SJohn Marino   /* If we have a lowpart SUBREG of a right shift of MEM, make a new MEM
5729e4b17023SJohn Marino      and try replacing the SUBREG and shift with it.  Don't do this if
5730e4b17023SJohn Marino      the MEM has a mode-dependent address or if we would be widening it.  */
5731e4b17023SJohn Marino 
5732e4b17023SJohn Marino   if ((GET_CODE (op) == LSHIFTRT
5733e4b17023SJohn Marino        || GET_CODE (op) == ASHIFTRT)
5734e4b17023SJohn Marino       && SCALAR_INT_MODE_P (innermode)
5735e4b17023SJohn Marino       && MEM_P (XEXP (op, 0))
5736e4b17023SJohn Marino       && CONST_INT_P (XEXP (op, 1))
5737e4b17023SJohn Marino       && GET_MODE_SIZE (outermode) < GET_MODE_SIZE (GET_MODE (op))
5738e4b17023SJohn Marino       && (INTVAL (XEXP (op, 1)) % GET_MODE_BITSIZE (outermode)) == 0
5739e4b17023SJohn Marino       && INTVAL (XEXP (op, 1)) > 0
5740e4b17023SJohn Marino       && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (innermode)
5741e4b17023SJohn Marino       && ! mode_dependent_address_p (XEXP (XEXP (op, 0), 0))
5742e4b17023SJohn Marino       && ! MEM_VOLATILE_P (XEXP (op, 0))
5743e4b17023SJohn Marino       && byte == subreg_lowpart_offset (outermode, innermode)
5744e4b17023SJohn Marino       && (GET_MODE_SIZE (outermode) >= UNITS_PER_WORD
5745e4b17023SJohn Marino 	  || WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN))
5746e4b17023SJohn Marino     {
5747e4b17023SJohn Marino       int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
5748e4b17023SJohn Marino       return adjust_address_nv (XEXP (op, 0), outermode,
5749e4b17023SJohn Marino 				(WORDS_BIG_ENDIAN
5750e4b17023SJohn Marino 				 ? byte - shifted_bytes
5751e4b17023SJohn Marino 				 : byte + shifted_bytes));
5752e4b17023SJohn Marino     }
5753e4b17023SJohn Marino 
5754e4b17023SJohn Marino   return NULL_RTX;
5755e4b17023SJohn Marino }
5756e4b17023SJohn Marino 
5757e4b17023SJohn Marino /* Make a SUBREG operation or equivalent if it folds.  */
5758e4b17023SJohn Marino 
5759e4b17023SJohn Marino rtx
simplify_gen_subreg(enum machine_mode outermode,rtx op,enum machine_mode innermode,unsigned int byte)5760e4b17023SJohn Marino simplify_gen_subreg (enum machine_mode outermode, rtx op,
5761e4b17023SJohn Marino 		     enum machine_mode innermode, unsigned int byte)
5762e4b17023SJohn Marino {
5763e4b17023SJohn Marino   rtx newx;
5764e4b17023SJohn Marino 
5765e4b17023SJohn Marino   newx = simplify_subreg (outermode, op, innermode, byte);
5766e4b17023SJohn Marino   if (newx)
5767e4b17023SJohn Marino     return newx;
5768e4b17023SJohn Marino 
5769e4b17023SJohn Marino   if (GET_CODE (op) == SUBREG
5770e4b17023SJohn Marino       || GET_CODE (op) == CONCAT
5771e4b17023SJohn Marino       || GET_MODE (op) == VOIDmode)
5772e4b17023SJohn Marino     return NULL_RTX;
5773e4b17023SJohn Marino 
5774e4b17023SJohn Marino   if (validate_subreg (outermode, innermode, op, byte))
5775e4b17023SJohn Marino     return gen_rtx_SUBREG (outermode, op, byte);
5776e4b17023SJohn Marino 
5777e4b17023SJohn Marino   return NULL_RTX;
5778e4b17023SJohn Marino }
5779e4b17023SJohn Marino 
5780e4b17023SJohn Marino /* Simplify X, an rtx expression.
5781e4b17023SJohn Marino 
5782e4b17023SJohn Marino    Return the simplified expression or NULL if no simplifications
5783e4b17023SJohn Marino    were possible.
5784e4b17023SJohn Marino 
5785e4b17023SJohn Marino    This is the preferred entry point into the simplification routines;
5786e4b17023SJohn Marino    however, we still allow passes to call the more specific routines.
5787e4b17023SJohn Marino 
5788e4b17023SJohn Marino    Right now GCC has three (yes, three) major bodies of RTL simplification
5789e4b17023SJohn Marino    code that need to be unified.
5790e4b17023SJohn Marino 
5791e4b17023SJohn Marino 	1. fold_rtx in cse.c.  This code uses various CSE specific
5792e4b17023SJohn Marino 	   information to aid in RTL simplification.
5793e4b17023SJohn Marino 
5794e4b17023SJohn Marino 	2. simplify_rtx in combine.c.  Similar to fold_rtx, except that
5795e4b17023SJohn Marino 	   it uses combine specific information to aid in RTL
5796e4b17023SJohn Marino 	   simplification.
5797e4b17023SJohn Marino 
5798e4b17023SJohn Marino 	3. The routines in this file.
5799e4b17023SJohn Marino 
5800e4b17023SJohn Marino 
5801e4b17023SJohn Marino    Long term we want to only have one body of simplification code; to
5802e4b17023SJohn Marino    get to that state I recommend the following steps:
5803e4b17023SJohn Marino 
5804e4b17023SJohn Marino 	1. Pour over fold_rtx & simplify_rtx and move any simplifications
5805e4b17023SJohn Marino 	   which are not pass dependent state into these routines.
5806e4b17023SJohn Marino 
5807e4b17023SJohn Marino 	2. As code is moved by #1, change fold_rtx & simplify_rtx to
5808e4b17023SJohn Marino 	   use this routine whenever possible.
5809e4b17023SJohn Marino 
5810e4b17023SJohn Marino 	3. Allow for pass dependent state to be provided to these
5811e4b17023SJohn Marino 	   routines and add simplifications based on the pass dependent
5812e4b17023SJohn Marino 	   state.  Remove code from cse.c & combine.c that becomes
5813e4b17023SJohn Marino 	   redundant/dead.
5814e4b17023SJohn Marino 
5815e4b17023SJohn Marino     It will take time, but ultimately the compiler will be easier to
5816e4b17023SJohn Marino     maintain and improve.  It's totally silly that when we add a
5817e4b17023SJohn Marino     simplification that it needs to be added to 4 places (3 for RTL
5818e4b17023SJohn Marino     simplification and 1 for tree simplification.  */
5819e4b17023SJohn Marino 
5820e4b17023SJohn Marino rtx
simplify_rtx(const_rtx x)5821e4b17023SJohn Marino simplify_rtx (const_rtx x)
5822e4b17023SJohn Marino {
5823e4b17023SJohn Marino   const enum rtx_code code = GET_CODE (x);
5824e4b17023SJohn Marino   const enum machine_mode mode = GET_MODE (x);
5825e4b17023SJohn Marino 
5826e4b17023SJohn Marino   switch (GET_RTX_CLASS (code))
5827e4b17023SJohn Marino     {
5828e4b17023SJohn Marino     case RTX_UNARY:
5829e4b17023SJohn Marino       return simplify_unary_operation (code, mode,
5830e4b17023SJohn Marino 				       XEXP (x, 0), GET_MODE (XEXP (x, 0)));
5831e4b17023SJohn Marino     case RTX_COMM_ARITH:
5832e4b17023SJohn Marino       if (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
5833e4b17023SJohn Marino 	return simplify_gen_binary (code, mode, XEXP (x, 1), XEXP (x, 0));
5834e4b17023SJohn Marino 
5835e4b17023SJohn Marino       /* Fall through....  */
5836e4b17023SJohn Marino 
5837e4b17023SJohn Marino     case RTX_BIN_ARITH:
5838e4b17023SJohn Marino       return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
5839e4b17023SJohn Marino 
5840e4b17023SJohn Marino     case RTX_TERNARY:
5841e4b17023SJohn Marino     case RTX_BITFIELD_OPS:
5842e4b17023SJohn Marino       return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)),
5843e4b17023SJohn Marino 					 XEXP (x, 0), XEXP (x, 1),
5844e4b17023SJohn Marino 					 XEXP (x, 2));
5845e4b17023SJohn Marino 
5846e4b17023SJohn Marino     case RTX_COMPARE:
5847e4b17023SJohn Marino     case RTX_COMM_COMPARE:
5848e4b17023SJohn Marino       return simplify_relational_operation (code, mode,
5849e4b17023SJohn Marino                                             ((GET_MODE (XEXP (x, 0))
5850e4b17023SJohn Marino                                              != VOIDmode)
5851e4b17023SJohn Marino                                             ? GET_MODE (XEXP (x, 0))
5852e4b17023SJohn Marino                                             : GET_MODE (XEXP (x, 1))),
5853e4b17023SJohn Marino                                             XEXP (x, 0),
5854e4b17023SJohn Marino                                             XEXP (x, 1));
5855e4b17023SJohn Marino 
5856e4b17023SJohn Marino     case RTX_EXTRA:
5857e4b17023SJohn Marino       if (code == SUBREG)
5858e4b17023SJohn Marino 	return simplify_subreg (mode, SUBREG_REG (x),
5859e4b17023SJohn Marino 				GET_MODE (SUBREG_REG (x)),
5860e4b17023SJohn Marino 				SUBREG_BYTE (x));
5861e4b17023SJohn Marino       break;
5862e4b17023SJohn Marino 
5863e4b17023SJohn Marino     case RTX_OBJ:
5864e4b17023SJohn Marino       if (code == LO_SUM)
5865e4b17023SJohn Marino 	{
5866e4b17023SJohn Marino 	  /* Convert (lo_sum (high FOO) FOO) to FOO.  */
5867e4b17023SJohn Marino 	  if (GET_CODE (XEXP (x, 0)) == HIGH
5868e4b17023SJohn Marino 	      && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1)))
5869e4b17023SJohn Marino 	  return XEXP (x, 1);
5870e4b17023SJohn Marino 	}
5871e4b17023SJohn Marino       break;
5872e4b17023SJohn Marino 
5873e4b17023SJohn Marino     default:
5874e4b17023SJohn Marino       break;
5875e4b17023SJohn Marino     }
5876e4b17023SJohn Marino   return NULL;
5877e4b17023SJohn Marino }
5878