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