simplify-rtx.c revision 117395
190075Sobrien/* RTL simplification functions for GNU compiler.
290075Sobrien   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3117395Skan   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
490075Sobrien
590075SobrienThis file is part of GCC.
690075Sobrien
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU General Public License as published by the Free
990075SobrienSoftware Foundation; either version 2, or (at your option) any later
1090075Sobrienversion.
1190075Sobrien
1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590075Sobrienfor more details.
1690075Sobrien
1790075SobrienYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090075Sobrien02111-1307, USA.  */
2190075Sobrien
2290075Sobrien
2390075Sobrien#include "config.h"
2490075Sobrien#include "system.h"
2590075Sobrien#include "rtl.h"
26117395Skan#include "tree.h"
2790075Sobrien#include "tm_p.h"
2890075Sobrien#include "regs.h"
2990075Sobrien#include "hard-reg-set.h"
3090075Sobrien#include "flags.h"
3190075Sobrien#include "real.h"
3290075Sobrien#include "insn-config.h"
3390075Sobrien#include "recog.h"
3490075Sobrien#include "function.h"
3590075Sobrien#include "expr.h"
3690075Sobrien#include "toplev.h"
3790075Sobrien#include "output.h"
3890075Sobrien#include "ggc.h"
3990075Sobrien
4090075Sobrien/* Simplification and canonicalization of RTL.  */
4190075Sobrien
4290075Sobrien/* Nonzero if X has the form (PLUS frame-pointer integer).  We check for
4390075Sobrien   virtual regs here because the simplify_*_operation routines are called
4490075Sobrien   by integrate.c, which is called before virtual register instantiation.
4590075Sobrien
46117395Skan   ?!? NONZERO_BASE_PLUS_P needs to move into
4790075Sobrien   a header file so that their definitions can be shared with the
4890075Sobrien   simplification routines in simplify-rtx.c.  Until then, do not
49117395Skan   change this macro without also changing the copy in simplify-rtx.c.  */
5090075Sobrien
51117395Skan/* Allows reference to the stack pointer.
5290075Sobrien
5390075Sobrien   This used to include FIXED_BASE_PLUS_P, however, we can't assume that
5490075Sobrien   arg_pointer_rtx by itself is nonzero, because on at least one machine,
5590075Sobrien   the i960, the arg pointer is zero when it is unused.  */
5690075Sobrien
5790075Sobrien#define NONZERO_BASE_PLUS_P(X)					\
5890075Sobrien  ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx	\
5990075Sobrien   || (X) == virtual_stack_vars_rtx				\
6090075Sobrien   || (X) == virtual_incoming_args_rtx				\
6190075Sobrien   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
6290075Sobrien       && (XEXP (X, 0) == frame_pointer_rtx			\
6390075Sobrien	   || XEXP (X, 0) == hard_frame_pointer_rtx		\
6490075Sobrien	   || ((X) == arg_pointer_rtx				\
6590075Sobrien	       && fixed_regs[ARG_POINTER_REGNUM])		\
6690075Sobrien	   || XEXP (X, 0) == virtual_stack_vars_rtx		\
6790075Sobrien	   || XEXP (X, 0) == virtual_incoming_args_rtx))	\
6890075Sobrien   || (X) == stack_pointer_rtx					\
6990075Sobrien   || (X) == virtual_stack_dynamic_rtx				\
7090075Sobrien   || (X) == virtual_outgoing_args_rtx				\
7190075Sobrien   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
7290075Sobrien       && (XEXP (X, 0) == stack_pointer_rtx			\
7390075Sobrien	   || XEXP (X, 0) == virtual_stack_dynamic_rtx		\
7490075Sobrien	   || XEXP (X, 0) == virtual_outgoing_args_rtx))	\
7590075Sobrien   || GET_CODE (X) == ADDRESSOF)
7690075Sobrien
7790075Sobrien/* Much code operates on (low, high) pairs; the low value is an
7890075Sobrien   unsigned wide int, the high value a signed wide int.  We
7990075Sobrien   occasionally need to sign extend from low to high as if low were a
8090075Sobrien   signed wide int.  */
8190075Sobrien#define HWI_SIGN_EXTEND(low) \
8290075Sobrien ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
8390075Sobrien
8490075Sobrienstatic rtx neg_const_int PARAMS ((enum machine_mode, rtx));
8590075Sobrienstatic int simplify_plus_minus_op_data_cmp PARAMS ((const void *,
8690075Sobrien						    const void *));
8790075Sobrienstatic rtx simplify_plus_minus		PARAMS ((enum rtx_code,
8896263Sobrien						 enum machine_mode, rtx,
8996263Sobrien						 rtx, int));
9090075Sobrien
9190075Sobrien/* Negate a CONST_INT rtx, truncating (because a conversion from a
9290075Sobrien   maximally negative number can overflow).  */
9390075Sobrienstatic rtx
9490075Sobrienneg_const_int (mode, i)
9590075Sobrien     enum machine_mode mode;
9690075Sobrien     rtx i;
9790075Sobrien{
98117395Skan  return gen_int_mode (- INTVAL (i), mode);
9990075Sobrien}
10090075Sobrien
10190075Sobrien
102117395Skan/* Make a binary operation by properly ordering the operands and
10390075Sobrien   seeing if the expression folds.  */
10490075Sobrien
10590075Sobrienrtx
10690075Sobriensimplify_gen_binary (code, mode, op0, op1)
10790075Sobrien     enum rtx_code code;
10890075Sobrien     enum machine_mode mode;
10990075Sobrien     rtx op0, op1;
11090075Sobrien{
11190075Sobrien  rtx tem;
11290075Sobrien
11390075Sobrien  /* Put complex operands first and constants second if commutative.  */
11490075Sobrien  if (GET_RTX_CLASS (code) == 'c'
11590075Sobrien      && swap_commutative_operands_p (op0, op1))
11690075Sobrien    tem = op0, op0 = op1, op1 = tem;
11790075Sobrien
11890075Sobrien  /* If this simplifies, do it.  */
11990075Sobrien  tem = simplify_binary_operation (code, mode, op0, op1);
12090075Sobrien  if (tem)
12190075Sobrien    return tem;
12290075Sobrien
12396263Sobrien  /* Handle addition and subtraction specially.  Otherwise, just form
12496263Sobrien     the operation.  */
12590075Sobrien
12696263Sobrien  if (code == PLUS || code == MINUS)
12790075Sobrien    {
12896263Sobrien      tem = simplify_plus_minus (code, mode, op0, op1, 1);
12996263Sobrien      if (tem)
13096263Sobrien	return tem;
13190075Sobrien    }
13296263Sobrien
13396263Sobrien  return gen_rtx_fmt_ee (code, mode, op0, op1);
13490075Sobrien}
13590075Sobrien
13690075Sobrien/* If X is a MEM referencing the constant pool, return the real value.
13790075Sobrien   Otherwise return X.  */
13890075Sobrienrtx
13990075Sobrienavoid_constant_pool_reference (x)
14090075Sobrien     rtx x;
14190075Sobrien{
14290075Sobrien  rtx c, addr;
14390075Sobrien  enum machine_mode cmode;
14490075Sobrien
14590075Sobrien  if (GET_CODE (x) != MEM)
14690075Sobrien    return x;
14790075Sobrien  addr = XEXP (x, 0);
14890075Sobrien
149117395Skan  if (GET_CODE (addr) == LO_SUM)
150117395Skan    addr = XEXP (addr, 1);
151117395Skan
15290075Sobrien  if (GET_CODE (addr) != SYMBOL_REF
15390075Sobrien      || ! CONSTANT_POOL_ADDRESS_P (addr))
15490075Sobrien    return x;
15590075Sobrien
15690075Sobrien  c = get_pool_constant (addr);
15790075Sobrien  cmode = get_pool_mode (addr);
15890075Sobrien
15990075Sobrien  /* If we're accessing the constant in a different mode than it was
16090075Sobrien     originally stored, attempt to fix that up via subreg simplifications.
16190075Sobrien     If that fails we have no choice but to return the original memory.  */
16290075Sobrien  if (cmode != GET_MODE (x))
16390075Sobrien    {
16490075Sobrien      c = simplify_subreg (GET_MODE (x), c, cmode, 0);
16590075Sobrien      return c ? c : x;
16690075Sobrien    }
16790075Sobrien
16890075Sobrien  return c;
16990075Sobrien}
17090075Sobrien
17190075Sobrien/* Make a unary operation by first seeing if it folds and otherwise making
17290075Sobrien   the specified operation.  */
17390075Sobrien
17490075Sobrienrtx
17590075Sobriensimplify_gen_unary (code, mode, op, op_mode)
17690075Sobrien     enum rtx_code code;
17790075Sobrien     enum machine_mode mode;
17890075Sobrien     rtx op;
17990075Sobrien     enum machine_mode op_mode;
18090075Sobrien{
18190075Sobrien  rtx tem;
18290075Sobrien
18390075Sobrien  /* If this simplifies, use it.  */
18490075Sobrien  if ((tem = simplify_unary_operation (code, mode, op, op_mode)) != 0)
18590075Sobrien    return tem;
18690075Sobrien
18790075Sobrien  return gen_rtx_fmt_e (code, mode, op);
18890075Sobrien}
18990075Sobrien
19090075Sobrien/* Likewise for ternary operations.  */
19190075Sobrien
19290075Sobrienrtx
19390075Sobriensimplify_gen_ternary (code, mode, op0_mode, op0, op1, op2)
19490075Sobrien     enum rtx_code code;
19590075Sobrien     enum machine_mode mode, op0_mode;
19690075Sobrien     rtx op0, op1, op2;
19790075Sobrien{
19890075Sobrien  rtx tem;
19990075Sobrien
20090075Sobrien  /* If this simplifies, use it.  */
20190075Sobrien  if (0 != (tem = simplify_ternary_operation (code, mode, op0_mode,
20290075Sobrien					      op0, op1, op2)))
20390075Sobrien    return tem;
20490075Sobrien
20590075Sobrien  return gen_rtx_fmt_eee (code, mode, op0, op1, op2);
20690075Sobrien}
20790075Sobrien
20890075Sobrien/* Likewise, for relational operations.
20990075Sobrien   CMP_MODE specifies mode comparison is done in.
21090075Sobrien  */
21190075Sobrien
21290075Sobrienrtx
21390075Sobriensimplify_gen_relational (code, mode, cmp_mode, op0, op1)
21490075Sobrien     enum rtx_code code;
21590075Sobrien     enum machine_mode mode;
21690075Sobrien     enum machine_mode cmp_mode;
21790075Sobrien     rtx op0, op1;
21890075Sobrien{
21990075Sobrien  rtx tem;
22090075Sobrien
22190075Sobrien  if ((tem = simplify_relational_operation (code, cmp_mode, op0, op1)) != 0)
22290075Sobrien    return tem;
22390075Sobrien
224117395Skan  /* For the following tests, ensure const0_rtx is op1.  */
225117395Skan  if (op0 == const0_rtx && swap_commutative_operands_p (op0, op1))
226117395Skan    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
227117395Skan
228117395Skan  /* If op0 is a compare, extract the comparison arguments from it.  */
229117395Skan  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
230117395Skan    op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
231117395Skan
232117395Skan  /* If op0 is a comparison, extract the comparison arguments form it.  */
233117395Skan  if (code == NE && op1 == const0_rtx
234117395Skan      && GET_RTX_CLASS (GET_CODE (op0)) == '<')
235117395Skan    return op0;
236117395Skan  else if (code == EQ && op1 == const0_rtx)
237117395Skan    {
238117395Skan      /* The following tests GET_RTX_CLASS (GET_CODE (op0)) == '<'.  */
239117395Skan      enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
240117395Skan      if (new != UNKNOWN)
241117395Skan        {
242117395Skan	  code = new;
243117395Skan	  mode = cmp_mode;
244117395Skan	  op1 = XEXP (op0, 1);
245117395Skan	  op0 = XEXP (op0, 0);
246117395Skan        }
247117395Skan    }
248117395Skan
24990075Sobrien  /* Put complex operands first and constants second.  */
25090075Sobrien  if (swap_commutative_operands_p (op0, op1))
25190075Sobrien    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
25290075Sobrien
25390075Sobrien  return gen_rtx_fmt_ee (code, mode, op0, op1);
25490075Sobrien}
25590075Sobrien
25690075Sobrien/* Replace all occurrences of OLD in X with NEW and try to simplify the
25790075Sobrien   resulting RTX.  Return a new RTX which is as simplified as possible.  */
25890075Sobrien
25990075Sobrienrtx
26090075Sobriensimplify_replace_rtx (x, old, new)
26190075Sobrien     rtx x;
26290075Sobrien     rtx old;
26390075Sobrien     rtx new;
26490075Sobrien{
26590075Sobrien  enum rtx_code code = GET_CODE (x);
26690075Sobrien  enum machine_mode mode = GET_MODE (x);
26790075Sobrien
26890075Sobrien  /* If X is OLD, return NEW.  Otherwise, if this is an expression, try
26990075Sobrien     to build a new expression substituting recursively.  If we can't do
27090075Sobrien     anything, return our input.  */
27190075Sobrien
27290075Sobrien  if (x == old)
27390075Sobrien    return new;
27490075Sobrien
27590075Sobrien  switch (GET_RTX_CLASS (code))
27690075Sobrien    {
27790075Sobrien    case '1':
27890075Sobrien      {
27990075Sobrien	enum machine_mode op_mode = GET_MODE (XEXP (x, 0));
28090075Sobrien	rtx op = (XEXP (x, 0) == old
28190075Sobrien		  ? new : simplify_replace_rtx (XEXP (x, 0), old, new));
28290075Sobrien
28390075Sobrien	return simplify_gen_unary (code, mode, op, op_mode);
28490075Sobrien      }
28590075Sobrien
28690075Sobrien    case '2':
28790075Sobrien    case 'c':
28890075Sobrien      return
28990075Sobrien	simplify_gen_binary (code, mode,
29090075Sobrien			     simplify_replace_rtx (XEXP (x, 0), old, new),
29190075Sobrien			     simplify_replace_rtx (XEXP (x, 1), old, new));
29290075Sobrien    case '<':
29390075Sobrien      {
29490075Sobrien	enum machine_mode op_mode = (GET_MODE (XEXP (x, 0)) != VOIDmode
29590075Sobrien				     ? GET_MODE (XEXP (x, 0))
29690075Sobrien				     : GET_MODE (XEXP (x, 1)));
29790075Sobrien	rtx op0 = simplify_replace_rtx (XEXP (x, 0), old, new);
29890075Sobrien	rtx op1 = simplify_replace_rtx (XEXP (x, 1), old, new);
29990075Sobrien
30090075Sobrien	return
30190075Sobrien	  simplify_gen_relational (code, mode,
30290075Sobrien				   (op_mode != VOIDmode
30390075Sobrien				    ? op_mode
30490075Sobrien				    : GET_MODE (op0) != VOIDmode
30590075Sobrien				    ? GET_MODE (op0)
30690075Sobrien				    : GET_MODE (op1)),
30790075Sobrien				   op0, op1);
30890075Sobrien      }
30990075Sobrien
31090075Sobrien    case '3':
31190075Sobrien    case 'b':
31290075Sobrien      {
31390075Sobrien	enum machine_mode op_mode = GET_MODE (XEXP (x, 0));
31490075Sobrien	rtx op0 = simplify_replace_rtx (XEXP (x, 0), old, new);
31590075Sobrien
31690075Sobrien	return
317117395Skan	  simplify_gen_ternary (code, mode,
31890075Sobrien				(op_mode != VOIDmode
31990075Sobrien				 ? op_mode
32090075Sobrien				 : GET_MODE (op0)),
32190075Sobrien				op0,
32290075Sobrien				simplify_replace_rtx (XEXP (x, 1), old, new),
32390075Sobrien				simplify_replace_rtx (XEXP (x, 2), old, new));
32490075Sobrien      }
32590075Sobrien
32690075Sobrien    case 'x':
32790075Sobrien      /* The only case we try to handle is a SUBREG.  */
32890075Sobrien      if (code == SUBREG)
32990075Sobrien	{
33090075Sobrien	  rtx exp;
33190075Sobrien	  exp = simplify_gen_subreg (GET_MODE (x),
33290075Sobrien				     simplify_replace_rtx (SUBREG_REG (x),
33390075Sobrien				     			   old, new),
33490075Sobrien				     GET_MODE (SUBREG_REG (x)),
33590075Sobrien				     SUBREG_BYTE (x));
33690075Sobrien	  if (exp)
33790075Sobrien	   x = exp;
33890075Sobrien	}
33990075Sobrien      return x;
34090075Sobrien
341117395Skan    case 'o':
342117395Skan      if (code == MEM)
343117395Skan	return replace_equiv_address_nv (x,
344117395Skan					 simplify_replace_rtx (XEXP (x, 0),
345117395Skan							       old, new));
346117395Skan      else if (code == LO_SUM)
347117395Skan	{
348117395Skan	  rtx op0 = simplify_replace_rtx (XEXP (x, 0), old, new);
349117395Skan	  rtx op1 = simplify_replace_rtx (XEXP (x, 1), old, new);
35090075Sobrien
351117395Skan	  /* (lo_sum (high x) x) -> x  */
352117395Skan	  if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
353117395Skan	    return op1;
35490075Sobrien
355117395Skan	  return gen_rtx_LO_SUM (mode, op0, op1);
356117395Skan	}
357117395Skan      else if (code == REG)
35890075Sobrien	{
359117395Skan	  if (REG_P (old) && REGNO (x) == REGNO (old))
360117395Skan	    return new;
36190075Sobrien	}
36290075Sobrien
363117395Skan      return x;
364117395Skan
365117395Skan    default:
366117395Skan      return x;
36790075Sobrien    }
368117395Skan  return x;
36990075Sobrien}
370117395Skan
37190075Sobrien/* Try to simplify a unary operation CODE whose output mode is to be
37290075Sobrien   MODE with input operand OP whose mode was originally OP_MODE.
37390075Sobrien   Return zero if no simplification can be made.  */
37490075Sobrienrtx
37590075Sobriensimplify_unary_operation (code, mode, op, op_mode)
37690075Sobrien     enum rtx_code code;
37790075Sobrien     enum machine_mode mode;
37890075Sobrien     rtx op;
37990075Sobrien     enum machine_mode op_mode;
38090075Sobrien{
38190075Sobrien  unsigned int width = GET_MODE_BITSIZE (mode);
38290075Sobrien  rtx trueop = avoid_constant_pool_reference (op);
38390075Sobrien
384117395Skan  if (code == VEC_DUPLICATE)
385117395Skan    {
386117395Skan      if (!VECTOR_MODE_P (mode))
387117395Skan	abort ();
388117395Skan      if (GET_MODE (trueop) != VOIDmode
389117395Skan	  && !VECTOR_MODE_P (GET_MODE (trueop))
390117395Skan	  && GET_MODE_INNER (mode) != GET_MODE (trueop))
391117395Skan	abort ();
392117395Skan      if (GET_MODE (trueop) != VOIDmode
393117395Skan	  && VECTOR_MODE_P (GET_MODE (trueop))
394117395Skan	  && GET_MODE_INNER (mode) != GET_MODE_INNER (GET_MODE (trueop)))
395117395Skan	abort ();
396117395Skan      if (GET_CODE (trueop) == CONST_INT || GET_CODE (trueop) == CONST_DOUBLE
397117395Skan	  || GET_CODE (trueop) == CONST_VECTOR)
398117395Skan	{
399117395Skan          int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
400117395Skan          unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
401117395Skan	  rtvec v = rtvec_alloc (n_elts);
402117395Skan	  unsigned int i;
403117395Skan
404117395Skan	  if (GET_CODE (trueop) != CONST_VECTOR)
405117395Skan	    for (i = 0; i < n_elts; i++)
406117395Skan	      RTVEC_ELT (v, i) = trueop;
407117395Skan	  else
408117395Skan	    {
409117395Skan	      enum machine_mode inmode = GET_MODE (trueop);
410117395Skan              int in_elt_size = GET_MODE_SIZE (GET_MODE_INNER (inmode));
411117395Skan              unsigned in_n_elts = (GET_MODE_SIZE (inmode) / in_elt_size);
412117395Skan
413117395Skan	      if (in_n_elts >= n_elts || n_elts % in_n_elts)
414117395Skan		abort ();
415117395Skan	      for (i = 0; i < n_elts; i++)
416117395Skan	        RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop, i % in_n_elts);
417117395Skan	    }
418117395Skan	  return gen_rtx_CONST_VECTOR (mode, v);
419117395Skan	}
420117395Skan    }
421117395Skan
42290075Sobrien  /* The order of these tests is critical so that, for example, we don't
42390075Sobrien     check the wrong mode (input vs. output) for a conversion operation,
42490075Sobrien     such as FIX.  At some point, this should be simplified.  */
42590075Sobrien
42690075Sobrien  if (code == FLOAT && GET_MODE (trueop) == VOIDmode
42790075Sobrien      && (GET_CODE (trueop) == CONST_DOUBLE || GET_CODE (trueop) == CONST_INT))
42890075Sobrien    {
42990075Sobrien      HOST_WIDE_INT hv, lv;
43090075Sobrien      REAL_VALUE_TYPE d;
43190075Sobrien
43290075Sobrien      if (GET_CODE (trueop) == CONST_INT)
43390075Sobrien	lv = INTVAL (trueop), hv = HWI_SIGN_EXTEND (lv);
43490075Sobrien      else
43590075Sobrien	lv = CONST_DOUBLE_LOW (trueop),  hv = CONST_DOUBLE_HIGH (trueop);
43690075Sobrien
43790075Sobrien      REAL_VALUE_FROM_INT (d, lv, hv, mode);
43890075Sobrien      d = real_value_truncate (mode, d);
43990075Sobrien      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
44090075Sobrien    }
44190075Sobrien  else if (code == UNSIGNED_FLOAT && GET_MODE (trueop) == VOIDmode
44290075Sobrien	   && (GET_CODE (trueop) == CONST_DOUBLE
44390075Sobrien	       || GET_CODE (trueop) == CONST_INT))
44490075Sobrien    {
44590075Sobrien      HOST_WIDE_INT hv, lv;
44690075Sobrien      REAL_VALUE_TYPE d;
44790075Sobrien
44890075Sobrien      if (GET_CODE (trueop) == CONST_INT)
44990075Sobrien	lv = INTVAL (trueop), hv = HWI_SIGN_EXTEND (lv);
45090075Sobrien      else
45190075Sobrien	lv = CONST_DOUBLE_LOW (trueop),  hv = CONST_DOUBLE_HIGH (trueop);
45290075Sobrien
45390075Sobrien      if (op_mode == VOIDmode)
45490075Sobrien	{
45590075Sobrien	  /* We don't know how to interpret negative-looking numbers in
45690075Sobrien	     this case, so don't try to fold those.  */
45790075Sobrien	  if (hv < 0)
45890075Sobrien	    return 0;
45990075Sobrien	}
46090075Sobrien      else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
46190075Sobrien	;
46290075Sobrien      else
46390075Sobrien	hv = 0, lv &= GET_MODE_MASK (op_mode);
46490075Sobrien
46590075Sobrien      REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
46690075Sobrien      d = real_value_truncate (mode, d);
46790075Sobrien      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
46890075Sobrien    }
46990075Sobrien
47090075Sobrien  if (GET_CODE (trueop) == CONST_INT
47190075Sobrien      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
47290075Sobrien    {
47390075Sobrien      HOST_WIDE_INT arg0 = INTVAL (trueop);
47490075Sobrien      HOST_WIDE_INT val;
47590075Sobrien
47690075Sobrien      switch (code)
47790075Sobrien	{
47890075Sobrien	case NOT:
47990075Sobrien	  val = ~ arg0;
48090075Sobrien	  break;
48190075Sobrien
48290075Sobrien	case NEG:
48390075Sobrien	  val = - arg0;
48490075Sobrien	  break;
48590075Sobrien
48690075Sobrien	case ABS:
48790075Sobrien	  val = (arg0 >= 0 ? arg0 : - arg0);
48890075Sobrien	  break;
48990075Sobrien
49090075Sobrien	case FFS:
49190075Sobrien	  /* Don't use ffs here.  Instead, get low order bit and then its
49290075Sobrien	     number.  If arg0 is zero, this will return 0, as desired.  */
49390075Sobrien	  arg0 &= GET_MODE_MASK (mode);
49490075Sobrien	  val = exact_log2 (arg0 & (- arg0)) + 1;
49590075Sobrien	  break;
49690075Sobrien
49790075Sobrien	case TRUNCATE:
49890075Sobrien	  val = arg0;
49990075Sobrien	  break;
50090075Sobrien
50190075Sobrien	case ZERO_EXTEND:
50296263Sobrien	  /* When zero-extending a CONST_INT, we need to know its
50396263Sobrien             original mode.  */
50490075Sobrien	  if (op_mode == VOIDmode)
50596263Sobrien	    abort ();
50690075Sobrien	  if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
50790075Sobrien	    {
50890075Sobrien	      /* If we were really extending the mode,
50990075Sobrien		 we would have to distinguish between zero-extension
51090075Sobrien		 and sign-extension.  */
51190075Sobrien	      if (width != GET_MODE_BITSIZE (op_mode))
51290075Sobrien		abort ();
51390075Sobrien	      val = arg0;
51490075Sobrien	    }
51590075Sobrien	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
51690075Sobrien	    val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
51790075Sobrien	  else
51890075Sobrien	    return 0;
51990075Sobrien	  break;
52090075Sobrien
52190075Sobrien	case SIGN_EXTEND:
52290075Sobrien	  if (op_mode == VOIDmode)
52390075Sobrien	    op_mode = mode;
52490075Sobrien	  if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
52590075Sobrien	    {
52690075Sobrien	      /* If we were really extending the mode,
52790075Sobrien		 we would have to distinguish between zero-extension
52890075Sobrien		 and sign-extension.  */
52990075Sobrien	      if (width != GET_MODE_BITSIZE (op_mode))
53090075Sobrien		abort ();
53190075Sobrien	      val = arg0;
53290075Sobrien	    }
53390075Sobrien	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
53490075Sobrien	    {
53590075Sobrien	      val
53690075Sobrien		= arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
53790075Sobrien	      if (val
53890075Sobrien		  & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1)))
53990075Sobrien		val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
54090075Sobrien	    }
54190075Sobrien	  else
54290075Sobrien	    return 0;
54390075Sobrien	  break;
54490075Sobrien
54590075Sobrien	case SQRT:
54690075Sobrien	case FLOAT_EXTEND:
54790075Sobrien	case FLOAT_TRUNCATE:
54890075Sobrien	case SS_TRUNCATE:
54990075Sobrien	case US_TRUNCATE:
55090075Sobrien	  return 0;
55190075Sobrien
55290075Sobrien	default:
55390075Sobrien	  abort ();
55490075Sobrien	}
55590075Sobrien
55690075Sobrien      val = trunc_int_for_mode (val, mode);
55790075Sobrien
55890075Sobrien      return GEN_INT (val);
55990075Sobrien    }
56090075Sobrien
56190075Sobrien  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
56290075Sobrien     for a DImode operation on a CONST_INT.  */
56396263Sobrien  else if (GET_MODE (trueop) == VOIDmode
56496263Sobrien	   && width <= HOST_BITS_PER_WIDE_INT * 2
56590075Sobrien	   && (GET_CODE (trueop) == CONST_DOUBLE
56690075Sobrien	       || GET_CODE (trueop) == CONST_INT))
56790075Sobrien    {
56890075Sobrien      unsigned HOST_WIDE_INT l1, lv;
56990075Sobrien      HOST_WIDE_INT h1, hv;
57090075Sobrien
57190075Sobrien      if (GET_CODE (trueop) == CONST_DOUBLE)
57290075Sobrien	l1 = CONST_DOUBLE_LOW (trueop), h1 = CONST_DOUBLE_HIGH (trueop);
57390075Sobrien      else
57490075Sobrien	l1 = INTVAL (trueop), h1 = HWI_SIGN_EXTEND (l1);
57590075Sobrien
57690075Sobrien      switch (code)
57790075Sobrien	{
57890075Sobrien	case NOT:
57990075Sobrien	  lv = ~ l1;
58090075Sobrien	  hv = ~ h1;
58190075Sobrien	  break;
58290075Sobrien
58390075Sobrien	case NEG:
58490075Sobrien	  neg_double (l1, h1, &lv, &hv);
58590075Sobrien	  break;
58690075Sobrien
58790075Sobrien	case ABS:
58890075Sobrien	  if (h1 < 0)
58990075Sobrien	    neg_double (l1, h1, &lv, &hv);
59090075Sobrien	  else
59190075Sobrien	    lv = l1, hv = h1;
59290075Sobrien	  break;
59390075Sobrien
59490075Sobrien	case FFS:
59590075Sobrien	  hv = 0;
59690075Sobrien	  if (l1 == 0)
59790075Sobrien	    lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & (-h1)) + 1;
59890075Sobrien	  else
59990075Sobrien	    lv = exact_log2 (l1 & (-l1)) + 1;
60090075Sobrien	  break;
60190075Sobrien
60290075Sobrien	case TRUNCATE:
60390075Sobrien	  /* This is just a change-of-mode, so do nothing.  */
60490075Sobrien	  lv = l1, hv = h1;
60590075Sobrien	  break;
60690075Sobrien
60790075Sobrien	case ZERO_EXTEND:
60896263Sobrien	  if (op_mode == VOIDmode)
60996263Sobrien	    abort ();
61096263Sobrien
61196263Sobrien	  if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
61290075Sobrien	    return 0;
61390075Sobrien
61490075Sobrien	  hv = 0;
61590075Sobrien	  lv = l1 & GET_MODE_MASK (op_mode);
61690075Sobrien	  break;
61790075Sobrien
61890075Sobrien	case SIGN_EXTEND:
61990075Sobrien	  if (op_mode == VOIDmode
62090075Sobrien	      || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
62190075Sobrien	    return 0;
62290075Sobrien	  else
62390075Sobrien	    {
62490075Sobrien	      lv = l1 & GET_MODE_MASK (op_mode);
62590075Sobrien	      if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
62690075Sobrien		  && (lv & ((HOST_WIDE_INT) 1
62790075Sobrien			    << (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
62890075Sobrien		lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
62990075Sobrien
63090075Sobrien	      hv = HWI_SIGN_EXTEND (lv);
63190075Sobrien	    }
63290075Sobrien	  break;
63390075Sobrien
63490075Sobrien	case SQRT:
63590075Sobrien	  return 0;
63690075Sobrien
63790075Sobrien	default:
63890075Sobrien	  return 0;
63990075Sobrien	}
64090075Sobrien
64190075Sobrien      return immed_double_const (lv, hv, mode);
64290075Sobrien    }
64390075Sobrien
64490075Sobrien  else if (GET_CODE (trueop) == CONST_DOUBLE
64590075Sobrien	   && GET_MODE_CLASS (mode) == MODE_FLOAT)
64690075Sobrien    {
647117395Skan      REAL_VALUE_TYPE d;
648117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (d, trueop);
64990075Sobrien
650117395Skan      switch (code)
651117395Skan	{
652117395Skan	case SQRT:
653117395Skan	  /* We don't attempt to optimize this.  */
654117395Skan	  return 0;
65590075Sobrien
656117395Skan	case ABS:
657117395Skan	  d = REAL_VALUE_ABS (d);
658117395Skan	  break;
659117395Skan	case NEG:
660117395Skan	  d = REAL_VALUE_NEGATE (d);
661117395Skan	  break;
662117395Skan	case FLOAT_TRUNCATE:
663117395Skan	  d = real_value_truncate (mode, d);
664117395Skan	  break;
665117395Skan	case FLOAT_EXTEND:
666117395Skan	  /* All this does is change the mode.  */
667117395Skan	  break;
668117395Skan	case FIX:
669117395Skan	  real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
670117395Skan	  break;
671117395Skan
672117395Skan	default:
673117395Skan	  abort ();
674117395Skan	}
675117395Skan      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
67690075Sobrien    }
67790075Sobrien
67890075Sobrien  else if (GET_CODE (trueop) == CONST_DOUBLE
67990075Sobrien	   && GET_MODE_CLASS (GET_MODE (trueop)) == MODE_FLOAT
68090075Sobrien	   && GET_MODE_CLASS (mode) == MODE_INT
68190075Sobrien	   && width <= HOST_BITS_PER_WIDE_INT && width > 0)
68290075Sobrien    {
683117395Skan      HOST_WIDE_INT i;
684117395Skan      REAL_VALUE_TYPE d;
685117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (d, trueop);
686117395Skan      switch (code)
687117395Skan	{
688117395Skan	case FIX:		i = REAL_VALUE_FIX (d);		  break;
689117395Skan	case UNSIGNED_FIX:	i = REAL_VALUE_UNSIGNED_FIX (d);  break;
690117395Skan	default:
691117395Skan	  abort ();
692117395Skan	}
693117395Skan      return gen_int_mode (i, mode);
694117395Skan    }
69590075Sobrien
69690075Sobrien  /* This was formerly used only for non-IEEE float.
69790075Sobrien     eggert@twinsun.com says it is safe for IEEE also.  */
69890075Sobrien  else
69990075Sobrien    {
70090075Sobrien      enum rtx_code reversed;
70190075Sobrien      /* There are some simplifications we can do even if the operands
70290075Sobrien	 aren't constant.  */
70390075Sobrien      switch (code)
70490075Sobrien	{
70590075Sobrien	case NOT:
70690075Sobrien	  /* (not (not X)) == X.  */
70790075Sobrien	  if (GET_CODE (op) == NOT)
70890075Sobrien	    return XEXP (op, 0);
70990075Sobrien
71090075Sobrien	  /* (not (eq X Y)) == (ne X Y), etc.  */
71190075Sobrien	  if (mode == BImode && GET_RTX_CLASS (GET_CODE (op)) == '<'
71290075Sobrien	      && ((reversed = reversed_comparison_code (op, NULL_RTX))
71390075Sobrien		  != UNKNOWN))
71490075Sobrien	    return gen_rtx_fmt_ee (reversed,
71590075Sobrien				   op_mode, XEXP (op, 0), XEXP (op, 1));
71690075Sobrien	  break;
71790075Sobrien
71890075Sobrien	case NEG:
71990075Sobrien	  /* (neg (neg X)) == X.  */
72090075Sobrien	  if (GET_CODE (op) == NEG)
72190075Sobrien	    return XEXP (op, 0);
72290075Sobrien	  break;
72390075Sobrien
72490075Sobrien	case SIGN_EXTEND:
72590075Sobrien	  /* (sign_extend (truncate (minus (label_ref L1) (label_ref L2))))
72690075Sobrien	     becomes just the MINUS if its mode is MODE.  This allows
72790075Sobrien	     folding switch statements on machines using casesi (such as
72890075Sobrien	     the VAX).  */
72990075Sobrien	  if (GET_CODE (op) == TRUNCATE
73090075Sobrien	      && GET_MODE (XEXP (op, 0)) == mode
73190075Sobrien	      && GET_CODE (XEXP (op, 0)) == MINUS
73290075Sobrien	      && GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF
73390075Sobrien	      && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
73490075Sobrien	    return XEXP (op, 0);
73590075Sobrien
73690075Sobrien#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
73790075Sobrien	  if (! POINTERS_EXTEND_UNSIGNED
73890075Sobrien	      && mode == Pmode && GET_MODE (op) == ptr_mode
73990075Sobrien	      && (CONSTANT_P (op)
74090075Sobrien		  || (GET_CODE (op) == SUBREG
74190075Sobrien		      && GET_CODE (SUBREG_REG (op)) == REG
74290075Sobrien		      && REG_POINTER (SUBREG_REG (op))
74390075Sobrien		      && GET_MODE (SUBREG_REG (op)) == Pmode)))
74490075Sobrien	    return convert_memory_address (Pmode, op);
74590075Sobrien#endif
74690075Sobrien	  break;
74790075Sobrien
74890075Sobrien#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
74990075Sobrien	case ZERO_EXTEND:
75090075Sobrien	  if (POINTERS_EXTEND_UNSIGNED > 0
75190075Sobrien	      && mode == Pmode && GET_MODE (op) == ptr_mode
75290075Sobrien	      && (CONSTANT_P (op)
75390075Sobrien		  || (GET_CODE (op) == SUBREG
75490075Sobrien		      && GET_CODE (SUBREG_REG (op)) == REG
75590075Sobrien		      && REG_POINTER (SUBREG_REG (op))
75690075Sobrien		      && GET_MODE (SUBREG_REG (op)) == Pmode)))
75790075Sobrien	    return convert_memory_address (Pmode, op);
75890075Sobrien	  break;
75990075Sobrien#endif
760117395Skan
76190075Sobrien	default:
76290075Sobrien	  break;
76390075Sobrien	}
76490075Sobrien
76590075Sobrien      return 0;
76690075Sobrien    }
76790075Sobrien}
76890075Sobrien
76990075Sobrien/* Simplify a binary operation CODE with result mode MODE, operating on OP0
77090075Sobrien   and OP1.  Return 0 if no simplification is possible.
77190075Sobrien
77290075Sobrien   Don't use this for relational operations such as EQ or LT.
77390075Sobrien   Use simplify_relational_operation instead.  */
77490075Sobrienrtx
77590075Sobriensimplify_binary_operation (code, mode, op0, op1)
77690075Sobrien     enum rtx_code code;
77790075Sobrien     enum machine_mode mode;
77890075Sobrien     rtx op0, op1;
77990075Sobrien{
78090075Sobrien  HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
78190075Sobrien  HOST_WIDE_INT val;
78290075Sobrien  unsigned int width = GET_MODE_BITSIZE (mode);
78390075Sobrien  rtx tem;
78490075Sobrien  rtx trueop0 = avoid_constant_pool_reference (op0);
78590075Sobrien  rtx trueop1 = avoid_constant_pool_reference (op1);
78690075Sobrien
78790075Sobrien  /* Relational operations don't work here.  We must know the mode
78890075Sobrien     of the operands in order to do the comparison correctly.
78990075Sobrien     Assuming a full word can give incorrect results.
79090075Sobrien     Consider comparing 128 with -128 in QImode.  */
79190075Sobrien
79290075Sobrien  if (GET_RTX_CLASS (code) == '<')
79390075Sobrien    abort ();
79490075Sobrien
79590075Sobrien  /* Make sure the constant is second.  */
79690075Sobrien  if (GET_RTX_CLASS (code) == 'c'
79790075Sobrien      && swap_commutative_operands_p (trueop0, trueop1))
79890075Sobrien    {
79990075Sobrien      tem = op0, op0 = op1, op1 = tem;
80090075Sobrien      tem = trueop0, trueop0 = trueop1, trueop1 = tem;
80190075Sobrien    }
80290075Sobrien
80390075Sobrien  if (GET_MODE_CLASS (mode) == MODE_FLOAT
80490075Sobrien      && GET_CODE (trueop0) == CONST_DOUBLE
80590075Sobrien      && GET_CODE (trueop1) == CONST_DOUBLE
80690075Sobrien      && mode == GET_MODE (op0) && mode == GET_MODE (op1))
80790075Sobrien    {
808117395Skan      REAL_VALUE_TYPE f0, f1, value;
80990075Sobrien
810117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (f0, trueop0);
811117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1);
812117395Skan      f0 = real_value_truncate (mode, f0);
813117395Skan      f1 = real_value_truncate (mode, f1);
814117395Skan
815117395Skan      if (code == DIV
816117395Skan	  && !MODE_HAS_INFINITIES (mode)
817117395Skan	  && REAL_VALUES_EQUAL (f1, dconst0))
818117395Skan	return 0;
819117395Skan
820117395Skan      REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
821117395Skan
822117395Skan      value = real_value_truncate (mode, value);
823117395Skan      return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
82490075Sobrien    }
82590075Sobrien
82690075Sobrien  /* We can fold some multi-word operations.  */
82790075Sobrien  if (GET_MODE_CLASS (mode) == MODE_INT
82890075Sobrien      && width == HOST_BITS_PER_WIDE_INT * 2
82990075Sobrien      && (GET_CODE (trueop0) == CONST_DOUBLE
83090075Sobrien	  || GET_CODE (trueop0) == CONST_INT)
83190075Sobrien      && (GET_CODE (trueop1) == CONST_DOUBLE
83290075Sobrien	  || GET_CODE (trueop1) == CONST_INT))
83390075Sobrien    {
83490075Sobrien      unsigned HOST_WIDE_INT l1, l2, lv;
83590075Sobrien      HOST_WIDE_INT h1, h2, hv;
83690075Sobrien
83790075Sobrien      if (GET_CODE (trueop0) == CONST_DOUBLE)
83890075Sobrien	l1 = CONST_DOUBLE_LOW (trueop0), h1 = CONST_DOUBLE_HIGH (trueop0);
83990075Sobrien      else
84090075Sobrien	l1 = INTVAL (trueop0), h1 = HWI_SIGN_EXTEND (l1);
84190075Sobrien
84290075Sobrien      if (GET_CODE (trueop1) == CONST_DOUBLE)
84390075Sobrien	l2 = CONST_DOUBLE_LOW (trueop1), h2 = CONST_DOUBLE_HIGH (trueop1);
84490075Sobrien      else
84590075Sobrien	l2 = INTVAL (trueop1), h2 = HWI_SIGN_EXTEND (l2);
84690075Sobrien
84790075Sobrien      switch (code)
84890075Sobrien	{
84990075Sobrien	case MINUS:
85090075Sobrien	  /* A - B == A + (-B).  */
85190075Sobrien	  neg_double (l2, h2, &lv, &hv);
85290075Sobrien	  l2 = lv, h2 = hv;
85390075Sobrien
85490075Sobrien	  /* .. fall through ...  */
85590075Sobrien
85690075Sobrien	case PLUS:
85790075Sobrien	  add_double (l1, h1, l2, h2, &lv, &hv);
85890075Sobrien	  break;
85990075Sobrien
86090075Sobrien	case MULT:
86190075Sobrien	  mul_double (l1, h1, l2, h2, &lv, &hv);
86290075Sobrien	  break;
86390075Sobrien
86490075Sobrien	case DIV:  case MOD:   case UDIV:  case UMOD:
86590075Sobrien	  /* We'd need to include tree.h to do this and it doesn't seem worth
86690075Sobrien	     it.  */
86790075Sobrien	  return 0;
86890075Sobrien
86990075Sobrien	case AND:
87090075Sobrien	  lv = l1 & l2, hv = h1 & h2;
87190075Sobrien	  break;
87290075Sobrien
87390075Sobrien	case IOR:
87490075Sobrien	  lv = l1 | l2, hv = h1 | h2;
87590075Sobrien	  break;
87690075Sobrien
87790075Sobrien	case XOR:
87890075Sobrien	  lv = l1 ^ l2, hv = h1 ^ h2;
87990075Sobrien	  break;
88090075Sobrien
88190075Sobrien	case SMIN:
88290075Sobrien	  if (h1 < h2
88390075Sobrien	      || (h1 == h2
88490075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
88590075Sobrien		      < (unsigned HOST_WIDE_INT) l2)))
88690075Sobrien	    lv = l1, hv = h1;
88790075Sobrien	  else
88890075Sobrien	    lv = l2, hv = h2;
88990075Sobrien	  break;
89090075Sobrien
89190075Sobrien	case SMAX:
89290075Sobrien	  if (h1 > h2
89390075Sobrien	      || (h1 == h2
89490075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
89590075Sobrien		      > (unsigned HOST_WIDE_INT) l2)))
89690075Sobrien	    lv = l1, hv = h1;
89790075Sobrien	  else
89890075Sobrien	    lv = l2, hv = h2;
89990075Sobrien	  break;
90090075Sobrien
90190075Sobrien	case UMIN:
90290075Sobrien	  if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2
90390075Sobrien	      || (h1 == h2
90490075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
90590075Sobrien		      < (unsigned HOST_WIDE_INT) l2)))
90690075Sobrien	    lv = l1, hv = h1;
90790075Sobrien	  else
90890075Sobrien	    lv = l2, hv = h2;
90990075Sobrien	  break;
91090075Sobrien
91190075Sobrien	case UMAX:
91290075Sobrien	  if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2
91390075Sobrien	      || (h1 == h2
91490075Sobrien		  && ((unsigned HOST_WIDE_INT) l1
91590075Sobrien		      > (unsigned HOST_WIDE_INT) l2)))
91690075Sobrien	    lv = l1, hv = h1;
91790075Sobrien	  else
91890075Sobrien	    lv = l2, hv = h2;
91990075Sobrien	  break;
92090075Sobrien
92190075Sobrien	case LSHIFTRT:   case ASHIFTRT:
92290075Sobrien	case ASHIFT:
92390075Sobrien	case ROTATE:     case ROTATERT:
92490075Sobrien#ifdef SHIFT_COUNT_TRUNCATED
92590075Sobrien	  if (SHIFT_COUNT_TRUNCATED)
92690075Sobrien	    l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
92790075Sobrien#endif
92890075Sobrien
92990075Sobrien	  if (h2 != 0 || l2 >= GET_MODE_BITSIZE (mode))
93090075Sobrien	    return 0;
93190075Sobrien
93290075Sobrien	  if (code == LSHIFTRT || code == ASHIFTRT)
93390075Sobrien	    rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
93490075Sobrien			   code == ASHIFTRT);
93590075Sobrien	  else if (code == ASHIFT)
93690075Sobrien	    lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
93790075Sobrien	  else if (code == ROTATE)
93890075Sobrien	    lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
93990075Sobrien	  else /* code == ROTATERT */
94090075Sobrien	    rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
94190075Sobrien	  break;
94290075Sobrien
94390075Sobrien	default:
94490075Sobrien	  return 0;
94590075Sobrien	}
94690075Sobrien
94790075Sobrien      return immed_double_const (lv, hv, mode);
94890075Sobrien    }
94990075Sobrien
95090075Sobrien  if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
95190075Sobrien      || width > HOST_BITS_PER_WIDE_INT || width == 0)
95290075Sobrien    {
95390075Sobrien      /* Even if we can't compute a constant result,
95490075Sobrien	 there are some cases worth simplifying.  */
95590075Sobrien
95690075Sobrien      switch (code)
95790075Sobrien	{
95890075Sobrien	case PLUS:
959117395Skan	  /* Maybe simplify x + 0 to x.  The two expressions are equivalent
960117395Skan	     when x is NaN, infinite, or finite and nonzero.  They aren't
961117395Skan	     when x is -0 and the rounding mode is not towards -infinity,
962117395Skan	     since (-0) + 0 is then 0.  */
963117395Skan	  if (!HONOR_SIGNED_ZEROS (mode) && trueop1 == CONST0_RTX (mode))
96490075Sobrien	    return op0;
96590075Sobrien
966117395Skan	  /* ((-a) + b) -> (b - a) and similarly for (a + (-b)).  These
967117395Skan	     transformations are safe even for IEEE.  */
96890075Sobrien	  if (GET_CODE (op0) == NEG)
96990075Sobrien	    return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
97090075Sobrien	  else if (GET_CODE (op1) == NEG)
97190075Sobrien	    return simplify_gen_binary (MINUS, mode, op0, XEXP (op1, 0));
97290075Sobrien
97390075Sobrien	  /* (~a) + 1 -> -a */
97490075Sobrien	  if (INTEGRAL_MODE_P (mode)
97590075Sobrien	      && GET_CODE (op0) == NOT
97690075Sobrien	      && trueop1 == const1_rtx)
97790075Sobrien	    return gen_rtx_NEG (mode, XEXP (op0, 0));
97890075Sobrien
97990075Sobrien	  /* Handle both-operands-constant cases.  We can only add
98090075Sobrien	     CONST_INTs to constants since the sum of relocatable symbols
98190075Sobrien	     can't be handled by most assemblers.  Don't add CONST_INT
98290075Sobrien	     to CONST_INT since overflow won't be computed properly if wider
98390075Sobrien	     than HOST_BITS_PER_WIDE_INT.  */
98490075Sobrien
98590075Sobrien	  if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode
98690075Sobrien	      && GET_CODE (op1) == CONST_INT)
98790075Sobrien	    return plus_constant (op0, INTVAL (op1));
98890075Sobrien	  else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode
98990075Sobrien		   && GET_CODE (op0) == CONST_INT)
99090075Sobrien	    return plus_constant (op1, INTVAL (op0));
99190075Sobrien
99290075Sobrien	  /* See if this is something like X * C - X or vice versa or
99390075Sobrien	     if the multiplication is written as a shift.  If so, we can
99490075Sobrien	     distribute and make a new multiply, shift, or maybe just
99590075Sobrien	     have X (if C is 2 in the example above).  But don't make
99690075Sobrien	     real multiply if we didn't have one before.  */
99790075Sobrien
99890075Sobrien	  if (! FLOAT_MODE_P (mode))
99990075Sobrien	    {
100090075Sobrien	      HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
100190075Sobrien	      rtx lhs = op0, rhs = op1;
100290075Sobrien	      int had_mult = 0;
100390075Sobrien
100490075Sobrien	      if (GET_CODE (lhs) == NEG)
100590075Sobrien		coeff0 = -1, lhs = XEXP (lhs, 0);
100690075Sobrien	      else if (GET_CODE (lhs) == MULT
100790075Sobrien		       && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
100890075Sobrien		{
100990075Sobrien		  coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
101090075Sobrien		  had_mult = 1;
101190075Sobrien		}
101290075Sobrien	      else if (GET_CODE (lhs) == ASHIFT
101390075Sobrien		       && GET_CODE (XEXP (lhs, 1)) == CONST_INT
101490075Sobrien		       && INTVAL (XEXP (lhs, 1)) >= 0
101590075Sobrien		       && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
101690075Sobrien		{
101790075Sobrien		  coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
101890075Sobrien		  lhs = XEXP (lhs, 0);
101990075Sobrien		}
102090075Sobrien
102190075Sobrien	      if (GET_CODE (rhs) == NEG)
102290075Sobrien		coeff1 = -1, rhs = XEXP (rhs, 0);
102390075Sobrien	      else if (GET_CODE (rhs) == MULT
102490075Sobrien		       && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
102590075Sobrien		{
102690075Sobrien		  coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
102790075Sobrien		  had_mult = 1;
102890075Sobrien		}
102990075Sobrien	      else if (GET_CODE (rhs) == ASHIFT
103090075Sobrien		       && GET_CODE (XEXP (rhs, 1)) == CONST_INT
103190075Sobrien		       && INTVAL (XEXP (rhs, 1)) >= 0
103290075Sobrien		       && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
103390075Sobrien		{
103490075Sobrien		  coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
103590075Sobrien		  rhs = XEXP (rhs, 0);
103690075Sobrien		}
103790075Sobrien
103890075Sobrien	      if (rtx_equal_p (lhs, rhs))
103990075Sobrien		{
104090075Sobrien		  tem = simplify_gen_binary (MULT, mode, lhs,
104190075Sobrien					GEN_INT (coeff0 + coeff1));
104290075Sobrien		  return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
104390075Sobrien		}
104490075Sobrien	    }
104590075Sobrien
104690075Sobrien	  /* If one of the operands is a PLUS or a MINUS, see if we can
1047117395Skan	     simplify this by the associative law.
104890075Sobrien	     Don't use the associative law for floating point.
104990075Sobrien	     The inaccuracy makes it nonassociative,
105090075Sobrien	     and subtle programs can break if operations are associated.  */
105190075Sobrien
105290075Sobrien	  if (INTEGRAL_MODE_P (mode)
105390075Sobrien	      && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
105490075Sobrien		  || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS
105590075Sobrien		  || (GET_CODE (op0) == CONST
105690075Sobrien		      && GET_CODE (XEXP (op0, 0)) == PLUS)
105790075Sobrien		  || (GET_CODE (op1) == CONST
105890075Sobrien		      && GET_CODE (XEXP (op1, 0)) == PLUS))
105996263Sobrien	      && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0)
106090075Sobrien	    return tem;
106190075Sobrien	  break;
106290075Sobrien
106390075Sobrien	case COMPARE:
106490075Sobrien#ifdef HAVE_cc0
106590075Sobrien	  /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
106690075Sobrien	     using cc0, in which case we want to leave it as a COMPARE
106790075Sobrien	     so we can distinguish it from a register-register-copy.
106890075Sobrien
106990075Sobrien	     In IEEE floating point, x-0 is not the same as x.  */
107090075Sobrien
107190075Sobrien	  if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
107290075Sobrien	       || ! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
107390075Sobrien	      && trueop1 == CONST0_RTX (mode))
107490075Sobrien	    return op0;
107590075Sobrien#endif
107690075Sobrien
107790075Sobrien	  /* Convert (compare (gt (flags) 0) (lt (flags) 0)) to (flags).  */
107890075Sobrien	  if (((GET_CODE (op0) == GT && GET_CODE (op1) == LT)
107990075Sobrien	       || (GET_CODE (op0) == GTU && GET_CODE (op1) == LTU))
108090075Sobrien	      && XEXP (op0, 1) == const0_rtx && XEXP (op1, 1) == const0_rtx)
108190075Sobrien	    {
108290075Sobrien	      rtx xop00 = XEXP (op0, 0);
108390075Sobrien	      rtx xop10 = XEXP (op1, 0);
108490075Sobrien
108590075Sobrien#ifdef HAVE_cc0
108690075Sobrien	      if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
108790075Sobrien#else
108890075Sobrien	      if (GET_CODE (xop00) == REG && GET_CODE (xop10) == REG
108990075Sobrien		  && GET_MODE (xop00) == GET_MODE (xop10)
109090075Sobrien		  && REGNO (xop00) == REGNO (xop10)
109190075Sobrien		  && GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
109290075Sobrien		  && GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
109390075Sobrien#endif
109490075Sobrien		return xop00;
109590075Sobrien	    }
1096117395Skan	  break;
109790075Sobrien
109890075Sobrien	case MINUS:
109990075Sobrien	  /* We can't assume x-x is 0 even with non-IEEE floating point,
110090075Sobrien	     but since it is zero except in very strange circumstances, we
110190075Sobrien	     will treat it as zero with -funsafe-math-optimizations.  */
110290075Sobrien	  if (rtx_equal_p (trueop0, trueop1)
110390075Sobrien	      && ! side_effects_p (op0)
110490075Sobrien	      && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations))
110590075Sobrien	    return CONST0_RTX (mode);
110690075Sobrien
1107117395Skan	  /* Change subtraction from zero into negation.  (0 - x) is the
1108117395Skan	     same as -x when x is NaN, infinite, or finite and nonzero.
1109117395Skan	     But if the mode has signed zeros, and does not round towards
1110117395Skan	     -infinity, then 0 - 0 is 0, not -0.  */
1111117395Skan	  if (!HONOR_SIGNED_ZEROS (mode) && trueop0 == CONST0_RTX (mode))
111290075Sobrien	    return gen_rtx_NEG (mode, op1);
111390075Sobrien
111490075Sobrien	  /* (-1 - a) is ~a.  */
111590075Sobrien	  if (trueop0 == constm1_rtx)
111690075Sobrien	    return gen_rtx_NOT (mode, op1);
111790075Sobrien
1118117395Skan	  /* Subtracting 0 has no effect unless the mode has signed zeros
1119117395Skan	     and supports rounding towards -infinity.  In such a case,
1120117395Skan	     0 - 0 is -0.  */
1121117395Skan	  if (!(HONOR_SIGNED_ZEROS (mode)
1122117395Skan		&& HONOR_SIGN_DEPENDENT_ROUNDING (mode))
1123117395Skan	      && trueop1 == CONST0_RTX (mode))
112490075Sobrien	    return op0;
112590075Sobrien
112690075Sobrien	  /* See if this is something like X * C - X or vice versa or
112790075Sobrien	     if the multiplication is written as a shift.  If so, we can
112890075Sobrien	     distribute and make a new multiply, shift, or maybe just
112990075Sobrien	     have X (if C is 2 in the example above).  But don't make
113090075Sobrien	     real multiply if we didn't have one before.  */
113190075Sobrien
113290075Sobrien	  if (! FLOAT_MODE_P (mode))
113390075Sobrien	    {
113490075Sobrien	      HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
113590075Sobrien	      rtx lhs = op0, rhs = op1;
113690075Sobrien	      int had_mult = 0;
113790075Sobrien
113890075Sobrien	      if (GET_CODE (lhs) == NEG)
113990075Sobrien		coeff0 = -1, lhs = XEXP (lhs, 0);
114090075Sobrien	      else if (GET_CODE (lhs) == MULT
114190075Sobrien		       && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
114290075Sobrien		{
114390075Sobrien		  coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
114490075Sobrien		  had_mult = 1;
114590075Sobrien		}
114690075Sobrien	      else if (GET_CODE (lhs) == ASHIFT
114790075Sobrien		       && GET_CODE (XEXP (lhs, 1)) == CONST_INT
114890075Sobrien		       && INTVAL (XEXP (lhs, 1)) >= 0
114990075Sobrien		       && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
115090075Sobrien		{
115190075Sobrien		  coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
115290075Sobrien		  lhs = XEXP (lhs, 0);
115390075Sobrien		}
115490075Sobrien
115590075Sobrien	      if (GET_CODE (rhs) == NEG)
115690075Sobrien		coeff1 = - 1, rhs = XEXP (rhs, 0);
115790075Sobrien	      else if (GET_CODE (rhs) == MULT
115890075Sobrien		       && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
115990075Sobrien		{
116090075Sobrien		  coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
116190075Sobrien		  had_mult = 1;
116290075Sobrien		}
116390075Sobrien	      else if (GET_CODE (rhs) == ASHIFT
116490075Sobrien		       && GET_CODE (XEXP (rhs, 1)) == CONST_INT
116590075Sobrien		       && INTVAL (XEXP (rhs, 1)) >= 0
116690075Sobrien		       && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
116790075Sobrien		{
116890075Sobrien		  coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
116990075Sobrien		  rhs = XEXP (rhs, 0);
117090075Sobrien		}
117190075Sobrien
117290075Sobrien	      if (rtx_equal_p (lhs, rhs))
117390075Sobrien		{
117490075Sobrien		  tem = simplify_gen_binary (MULT, mode, lhs,
117590075Sobrien					     GEN_INT (coeff0 - coeff1));
117690075Sobrien		  return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
117790075Sobrien		}
117890075Sobrien	    }
117990075Sobrien
1180117395Skan	  /* (a - (-b)) -> (a + b).  True even for IEEE.  */
118190075Sobrien	  if (GET_CODE (op1) == NEG)
118290075Sobrien	    return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
118390075Sobrien
118490075Sobrien	  /* If one of the operands is a PLUS or a MINUS, see if we can
1185117395Skan	     simplify this by the associative law.
118690075Sobrien	     Don't use the associative law for floating point.
118790075Sobrien	     The inaccuracy makes it nonassociative,
118890075Sobrien	     and subtle programs can break if operations are associated.  */
118990075Sobrien
119090075Sobrien	  if (INTEGRAL_MODE_P (mode)
119190075Sobrien	      && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
119290075Sobrien		  || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS
119390075Sobrien		  || (GET_CODE (op0) == CONST
119490075Sobrien		      && GET_CODE (XEXP (op0, 0)) == PLUS)
119590075Sobrien		  || (GET_CODE (op1) == CONST
119690075Sobrien		      && GET_CODE (XEXP (op1, 0)) == PLUS))
119796263Sobrien	      && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0)
119890075Sobrien	    return tem;
119990075Sobrien
120090075Sobrien	  /* Don't let a relocatable value get a negative coeff.  */
120190075Sobrien	  if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode)
120290075Sobrien	    return simplify_gen_binary (PLUS, mode,
120390075Sobrien					op0,
120490075Sobrien					neg_const_int (mode, op1));
120590075Sobrien
120690075Sobrien	  /* (x - (x & y)) -> (x & ~y) */
120790075Sobrien	  if (GET_CODE (op1) == AND)
120890075Sobrien	    {
120990075Sobrien	     if (rtx_equal_p (op0, XEXP (op1, 0)))
121090075Sobrien	       return simplify_gen_binary (AND, mode, op0,
121190075Sobrien					   gen_rtx_NOT (mode, XEXP (op1, 1)));
121290075Sobrien	     if (rtx_equal_p (op0, XEXP (op1, 1)))
121390075Sobrien	       return simplify_gen_binary (AND, mode, op0,
121490075Sobrien					   gen_rtx_NOT (mode, XEXP (op1, 0)));
121590075Sobrien	   }
121690075Sobrien	  break;
121790075Sobrien
121890075Sobrien	case MULT:
121990075Sobrien	  if (trueop1 == constm1_rtx)
122090075Sobrien	    {
122190075Sobrien	      tem = simplify_unary_operation (NEG, mode, op0, mode);
122290075Sobrien
122390075Sobrien	      return tem ? tem : gen_rtx_NEG (mode, op0);
122490075Sobrien	    }
122590075Sobrien
1226117395Skan	  /* Maybe simplify x * 0 to 0.  The reduction is not valid if
1227117395Skan	     x is NaN, since x * 0 is then also NaN.  Nor is it valid
1228117395Skan	     when the mode has signed zeros, since multiplying a negative
1229117395Skan	     number by 0 will give -0, not 0.  */
1230117395Skan	  if (!HONOR_NANS (mode)
1231117395Skan	      && !HONOR_SIGNED_ZEROS (mode)
123290075Sobrien	      && trueop1 == CONST0_RTX (mode)
123390075Sobrien	      && ! side_effects_p (op0))
123490075Sobrien	    return op1;
123590075Sobrien
1236117395Skan	  /* In IEEE floating point, x*1 is not equivalent to x for
1237117395Skan	     signalling NaNs.  */
1238117395Skan	  if (!HONOR_SNANS (mode)
1239117395Skan	      && trueop1 == CONST1_RTX (mode))
124090075Sobrien	    return op0;
124190075Sobrien
124290075Sobrien	  /* Convert multiply by constant power of two into shift unless
124390075Sobrien	     we are still generating RTL.  This test is a kludge.  */
124490075Sobrien	  if (GET_CODE (trueop1) == CONST_INT
124590075Sobrien	      && (val = exact_log2 (INTVAL (trueop1))) >= 0
124690075Sobrien	      /* If the mode is larger than the host word size, and the
124790075Sobrien		 uppermost bit is set, then this isn't a power of two due
124890075Sobrien		 to implicit sign extension.  */
124990075Sobrien	      && (width <= HOST_BITS_PER_WIDE_INT
125090075Sobrien		  || val != HOST_BITS_PER_WIDE_INT - 1)
125190075Sobrien	      && ! rtx_equal_function_value_matters)
125290075Sobrien	    return gen_rtx_ASHIFT (mode, op0, GEN_INT (val));
125390075Sobrien
1254117395Skan	  /* x*2 is x+x and x*(-1) is -x */
125590075Sobrien	  if (GET_CODE (trueop1) == CONST_DOUBLE
1256117395Skan	      && GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT
1257117395Skan	      && GET_MODE (op0) == mode)
125890075Sobrien	    {
1259117395Skan	      REAL_VALUE_TYPE d;
1260117395Skan	      REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
126190075Sobrien
1262117395Skan	      if (REAL_VALUES_EQUAL (d, dconst2))
126390075Sobrien		return gen_rtx_PLUS (mode, op0, copy_rtx (op0));
126490075Sobrien
1265117395Skan	      if (REAL_VALUES_EQUAL (d, dconstm1))
126690075Sobrien		return gen_rtx_NEG (mode, op0);
126790075Sobrien	    }
126890075Sobrien	  break;
126990075Sobrien
127090075Sobrien	case IOR:
127190075Sobrien	  if (trueop1 == const0_rtx)
127290075Sobrien	    return op0;
127390075Sobrien	  if (GET_CODE (trueop1) == CONST_INT
127490075Sobrien	      && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
127590075Sobrien	          == GET_MODE_MASK (mode)))
127690075Sobrien	    return op1;
127790075Sobrien	  if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
127890075Sobrien	    return op0;
127990075Sobrien	  /* A | (~A) -> -1 */
128090075Sobrien	  if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
128190075Sobrien	       || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
128290075Sobrien	      && ! side_effects_p (op0)
128390075Sobrien	      && GET_MODE_CLASS (mode) != MODE_CC)
128490075Sobrien	    return constm1_rtx;
128590075Sobrien	  break;
128690075Sobrien
128790075Sobrien	case XOR:
128890075Sobrien	  if (trueop1 == const0_rtx)
128990075Sobrien	    return op0;
129090075Sobrien	  if (GET_CODE (trueop1) == CONST_INT
129190075Sobrien	      && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
129290075Sobrien		  == GET_MODE_MASK (mode)))
129390075Sobrien	    return gen_rtx_NOT (mode, op0);
129490075Sobrien	  if (trueop0 == trueop1 && ! side_effects_p (op0)
129590075Sobrien	      && GET_MODE_CLASS (mode) != MODE_CC)
129690075Sobrien	    return const0_rtx;
129790075Sobrien	  break;
129890075Sobrien
129990075Sobrien	case AND:
130090075Sobrien	  if (trueop1 == const0_rtx && ! side_effects_p (op0))
130190075Sobrien	    return const0_rtx;
130290075Sobrien	  if (GET_CODE (trueop1) == CONST_INT
130390075Sobrien	      && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
130490075Sobrien		  == GET_MODE_MASK (mode)))
130590075Sobrien	    return op0;
130690075Sobrien	  if (trueop0 == trueop1 && ! side_effects_p (op0)
130790075Sobrien	      && GET_MODE_CLASS (mode) != MODE_CC)
130890075Sobrien	    return op0;
130990075Sobrien	  /* A & (~A) -> 0 */
131090075Sobrien	  if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
131190075Sobrien	       || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
131290075Sobrien	      && ! side_effects_p (op0)
131390075Sobrien	      && GET_MODE_CLASS (mode) != MODE_CC)
131490075Sobrien	    return const0_rtx;
131590075Sobrien	  break;
131690075Sobrien
131790075Sobrien	case UDIV:
131890075Sobrien	  /* Convert divide by power of two into shift (divide by 1 handled
131990075Sobrien	     below).  */
132090075Sobrien	  if (GET_CODE (trueop1) == CONST_INT
132190075Sobrien	      && (arg1 = exact_log2 (INTVAL (trueop1))) > 0)
132290075Sobrien	    return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1));
132390075Sobrien
132490075Sobrien	  /* ... fall through ...  */
132590075Sobrien
132690075Sobrien	case DIV:
132790075Sobrien	  if (trueop1 == CONST1_RTX (mode))
132890075Sobrien	    {
132990075Sobrien	      /* On some platforms DIV uses narrower mode than its
133090075Sobrien		 operands.  */
133190075Sobrien	      rtx x = gen_lowpart_common (mode, op0);
133290075Sobrien	      if (x)
133390075Sobrien		return x;
133490075Sobrien	      else if (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
133590075Sobrien		return gen_lowpart_SUBREG (mode, op0);
133690075Sobrien	      else
133790075Sobrien		return op0;
133890075Sobrien	    }
133990075Sobrien
1340117395Skan	  /* Maybe change 0 / x to 0.  This transformation isn't safe for
1341117395Skan	     modes with NaNs, since 0 / 0 will then be NaN rather than 0.
1342117395Skan	     Nor is it safe for modes with signed zeros, since dividing
1343117395Skan	     0 by a negative number gives -0, not 0.  */
1344117395Skan	  if (!HONOR_NANS (mode)
1345117395Skan	      && !HONOR_SIGNED_ZEROS (mode)
134690075Sobrien	      && trueop0 == CONST0_RTX (mode)
134790075Sobrien	      && ! side_effects_p (op1))
134890075Sobrien	    return op0;
134990075Sobrien
135090075Sobrien	  /* Change division by a constant into multiplication.  Only do
135190075Sobrien	     this with -funsafe-math-optimizations.  */
135290075Sobrien	  else if (GET_CODE (trueop1) == CONST_DOUBLE
135390075Sobrien		   && GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT
135490075Sobrien		   && trueop1 != CONST0_RTX (mode)
135590075Sobrien		   && flag_unsafe_math_optimizations)
135690075Sobrien	    {
135790075Sobrien	      REAL_VALUE_TYPE d;
135890075Sobrien	      REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
135990075Sobrien
136090075Sobrien	      if (! REAL_VALUES_EQUAL (d, dconst0))
136190075Sobrien		{
136290075Sobrien		  REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
1363117395Skan		  return gen_rtx_MULT (mode, op0,
136490075Sobrien				       CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
136590075Sobrien		}
136690075Sobrien	    }
136790075Sobrien	  break;
136890075Sobrien
136990075Sobrien	case UMOD:
137090075Sobrien	  /* Handle modulus by power of two (mod with 1 handled below).  */
137190075Sobrien	  if (GET_CODE (trueop1) == CONST_INT
137290075Sobrien	      && exact_log2 (INTVAL (trueop1)) > 0)
137390075Sobrien	    return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1));
137490075Sobrien
137590075Sobrien	  /* ... fall through ...  */
137690075Sobrien
137790075Sobrien	case MOD:
137890075Sobrien	  if ((trueop0 == const0_rtx || trueop1 == const1_rtx)
137990075Sobrien	      && ! side_effects_p (op0) && ! side_effects_p (op1))
138090075Sobrien	    return const0_rtx;
138190075Sobrien	  break;
138290075Sobrien
138390075Sobrien	case ROTATERT:
138490075Sobrien	case ROTATE:
138590075Sobrien	  /* Rotating ~0 always results in ~0.  */
138690075Sobrien	  if (GET_CODE (trueop0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
138790075Sobrien	      && (unsigned HOST_WIDE_INT) INTVAL (trueop0) == GET_MODE_MASK (mode)
138890075Sobrien	      && ! side_effects_p (op1))
138990075Sobrien	    return op0;
139090075Sobrien
139190075Sobrien	  /* ... fall through ...  */
139290075Sobrien
139390075Sobrien	case ASHIFT:
139490075Sobrien	case ASHIFTRT:
139590075Sobrien	case LSHIFTRT:
139690075Sobrien	  if (trueop1 == const0_rtx)
139790075Sobrien	    return op0;
139890075Sobrien	  if (trueop0 == const0_rtx && ! side_effects_p (op1))
139990075Sobrien	    return op0;
140090075Sobrien	  break;
140190075Sobrien
140290075Sobrien	case SMIN:
1403117395Skan	  if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (trueop1) == CONST_INT
140490075Sobrien	      && INTVAL (trueop1) == (HOST_WIDE_INT) 1 << (width -1)
140590075Sobrien	      && ! side_effects_p (op0))
140690075Sobrien	    return op1;
140790075Sobrien	  else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
140890075Sobrien	    return op0;
140990075Sobrien	  break;
1410117395Skan
141190075Sobrien	case SMAX:
141290075Sobrien	  if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (trueop1) == CONST_INT
141390075Sobrien	      && ((unsigned HOST_WIDE_INT) INTVAL (trueop1)
141490075Sobrien		  == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
141590075Sobrien	      && ! side_effects_p (op0))
141690075Sobrien	    return op1;
141790075Sobrien	  else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
141890075Sobrien	    return op0;
141990075Sobrien	  break;
142090075Sobrien
142190075Sobrien	case UMIN:
142290075Sobrien	  if (trueop1 == const0_rtx && ! side_effects_p (op0))
142390075Sobrien	    return op1;
142490075Sobrien	  else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
142590075Sobrien	    return op0;
142690075Sobrien	  break;
1427117395Skan
142890075Sobrien	case UMAX:
142990075Sobrien	  if (trueop1 == constm1_rtx && ! side_effects_p (op0))
143090075Sobrien	    return op1;
143190075Sobrien	  else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
143290075Sobrien	    return op0;
143390075Sobrien	  break;
143490075Sobrien
143590075Sobrien	case SS_PLUS:
143690075Sobrien	case US_PLUS:
143790075Sobrien	case SS_MINUS:
143890075Sobrien	case US_MINUS:
143990075Sobrien	  /* ??? There are simplifications that can be done.  */
144090075Sobrien	  return 0;
144190075Sobrien
1442117395Skan	case VEC_SELECT:
1443117395Skan	case VEC_CONCAT:
1444117395Skan	  return 0;
1445117395Skan
144690075Sobrien	default:
144790075Sobrien	  abort ();
144890075Sobrien	}
1449117395Skan
145090075Sobrien      return 0;
145190075Sobrien    }
145290075Sobrien
145390075Sobrien  /* Get the integer argument values in two forms:
145490075Sobrien     zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
145590075Sobrien
145690075Sobrien  arg0 = INTVAL (trueop0);
145790075Sobrien  arg1 = INTVAL (trueop1);
145890075Sobrien
145990075Sobrien  if (width < HOST_BITS_PER_WIDE_INT)
146090075Sobrien    {
146190075Sobrien      arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
146290075Sobrien      arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
146390075Sobrien
146490075Sobrien      arg0s = arg0;
146590075Sobrien      if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
146690075Sobrien	arg0s |= ((HOST_WIDE_INT) (-1) << width);
146790075Sobrien
146890075Sobrien      arg1s = arg1;
146990075Sobrien      if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
147090075Sobrien	arg1s |= ((HOST_WIDE_INT) (-1) << width);
147190075Sobrien    }
147290075Sobrien  else
147390075Sobrien    {
147490075Sobrien      arg0s = arg0;
147590075Sobrien      arg1s = arg1;
147690075Sobrien    }
147790075Sobrien
147890075Sobrien  /* Compute the value of the arithmetic.  */
147990075Sobrien
148090075Sobrien  switch (code)
148190075Sobrien    {
148290075Sobrien    case PLUS:
148390075Sobrien      val = arg0s + arg1s;
148490075Sobrien      break;
148590075Sobrien
148690075Sobrien    case MINUS:
148790075Sobrien      val = arg0s - arg1s;
148890075Sobrien      break;
148990075Sobrien
149090075Sobrien    case MULT:
149190075Sobrien      val = arg0s * arg1s;
149290075Sobrien      break;
149390075Sobrien
149490075Sobrien    case DIV:
149590075Sobrien      if (arg1s == 0
149690075Sobrien	  || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
149790075Sobrien	      && arg1s == -1))
149890075Sobrien	return 0;
149990075Sobrien      val = arg0s / arg1s;
150090075Sobrien      break;
150190075Sobrien
150290075Sobrien    case MOD:
150390075Sobrien      if (arg1s == 0
150490075Sobrien	  || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
150590075Sobrien	      && arg1s == -1))
150690075Sobrien	return 0;
150790075Sobrien      val = arg0s % arg1s;
150890075Sobrien      break;
150990075Sobrien
151090075Sobrien    case UDIV:
151190075Sobrien      if (arg1 == 0
151290075Sobrien	  || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
151390075Sobrien	      && arg1s == -1))
151490075Sobrien	return 0;
151590075Sobrien      val = (unsigned HOST_WIDE_INT) arg0 / arg1;
151690075Sobrien      break;
151790075Sobrien
151890075Sobrien    case UMOD:
151990075Sobrien      if (arg1 == 0
152090075Sobrien	  || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
152190075Sobrien	      && arg1s == -1))
152290075Sobrien	return 0;
152390075Sobrien      val = (unsigned HOST_WIDE_INT) arg0 % arg1;
152490075Sobrien      break;
152590075Sobrien
152690075Sobrien    case AND:
152790075Sobrien      val = arg0 & arg1;
152890075Sobrien      break;
152990075Sobrien
153090075Sobrien    case IOR:
153190075Sobrien      val = arg0 | arg1;
153290075Sobrien      break;
153390075Sobrien
153490075Sobrien    case XOR:
153590075Sobrien      val = arg0 ^ arg1;
153690075Sobrien      break;
153790075Sobrien
153890075Sobrien    case LSHIFTRT:
153990075Sobrien      /* If shift count is undefined, don't fold it; let the machine do
154090075Sobrien	 what it wants.  But truncate it if the machine will do that.  */
154190075Sobrien      if (arg1 < 0)
154290075Sobrien	return 0;
154390075Sobrien
154490075Sobrien#ifdef SHIFT_COUNT_TRUNCATED
154590075Sobrien      if (SHIFT_COUNT_TRUNCATED)
154690075Sobrien	arg1 %= width;
154790075Sobrien#endif
154890075Sobrien
154990075Sobrien      val = ((unsigned HOST_WIDE_INT) arg0) >> arg1;
155090075Sobrien      break;
155190075Sobrien
155290075Sobrien    case ASHIFT:
155390075Sobrien      if (arg1 < 0)
155490075Sobrien	return 0;
155590075Sobrien
155690075Sobrien#ifdef SHIFT_COUNT_TRUNCATED
155790075Sobrien      if (SHIFT_COUNT_TRUNCATED)
155890075Sobrien	arg1 %= width;
155990075Sobrien#endif
156090075Sobrien
156190075Sobrien      val = ((unsigned HOST_WIDE_INT) arg0) << arg1;
156290075Sobrien      break;
156390075Sobrien
156490075Sobrien    case ASHIFTRT:
156590075Sobrien      if (arg1 < 0)
156690075Sobrien	return 0;
156790075Sobrien
156890075Sobrien#ifdef SHIFT_COUNT_TRUNCATED
156990075Sobrien      if (SHIFT_COUNT_TRUNCATED)
157090075Sobrien	arg1 %= width;
157190075Sobrien#endif
157290075Sobrien
157390075Sobrien      val = arg0s >> arg1;
157490075Sobrien
157590075Sobrien      /* Bootstrap compiler may not have sign extended the right shift.
157690075Sobrien	 Manually extend the sign to insure bootstrap cc matches gcc.  */
157790075Sobrien      if (arg0s < 0 && arg1 > 0)
157890075Sobrien	val |= ((HOST_WIDE_INT) -1) << (HOST_BITS_PER_WIDE_INT - arg1);
157990075Sobrien
158090075Sobrien      break;
158190075Sobrien
158290075Sobrien    case ROTATERT:
158390075Sobrien      if (arg1 < 0)
158490075Sobrien	return 0;
158590075Sobrien
158690075Sobrien      arg1 %= width;
158790075Sobrien      val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
158890075Sobrien	     | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
158990075Sobrien      break;
159090075Sobrien
159190075Sobrien    case ROTATE:
159290075Sobrien      if (arg1 < 0)
159390075Sobrien	return 0;
159490075Sobrien
159590075Sobrien      arg1 %= width;
159690075Sobrien      val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
159790075Sobrien	     | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
159890075Sobrien      break;
159990075Sobrien
160090075Sobrien    case COMPARE:
160190075Sobrien      /* Do nothing here.  */
160290075Sobrien      return 0;
160390075Sobrien
160490075Sobrien    case SMIN:
160590075Sobrien      val = arg0s <= arg1s ? arg0s : arg1s;
160690075Sobrien      break;
160790075Sobrien
160890075Sobrien    case UMIN:
160990075Sobrien      val = ((unsigned HOST_WIDE_INT) arg0
161090075Sobrien	     <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
161190075Sobrien      break;
161290075Sobrien
161390075Sobrien    case SMAX:
161490075Sobrien      val = arg0s > arg1s ? arg0s : arg1s;
161590075Sobrien      break;
161690075Sobrien
161790075Sobrien    case UMAX:
161890075Sobrien      val = ((unsigned HOST_WIDE_INT) arg0
161990075Sobrien	     > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
162090075Sobrien      break;
162190075Sobrien
162290075Sobrien    default:
162390075Sobrien      abort ();
162490075Sobrien    }
162590075Sobrien
162690075Sobrien  val = trunc_int_for_mode (val, mode);
162790075Sobrien
162890075Sobrien  return GEN_INT (val);
162990075Sobrien}
163090075Sobrien
163190075Sobrien/* Simplify a PLUS or MINUS, at least one of whose operands may be another
163290075Sobrien   PLUS or MINUS.
163390075Sobrien
163490075Sobrien   Rather than test for specific case, we do this by a brute-force method
163590075Sobrien   and do all possible simplifications until no more changes occur.  Then
1636117395Skan   we rebuild the operation.
163790075Sobrien
1638117395Skan   If FORCE is true, then always generate the rtx.  This is used to
163996263Sobrien   canonicalize stuff emitted from simplify_gen_binary.  Note that this
164096263Sobrien   can still fail if the rtx is too complex.  It won't fail just because
164196263Sobrien   the result is not 'simpler' than the input, however.  */
164296263Sobrien
164390075Sobrienstruct simplify_plus_minus_op_data
164490075Sobrien{
164590075Sobrien  rtx op;
164690075Sobrien  int neg;
164790075Sobrien};
164890075Sobrien
164990075Sobrienstatic int
165090075Sobriensimplify_plus_minus_op_data_cmp (p1, p2)
165190075Sobrien     const void *p1;
165290075Sobrien     const void *p2;
165390075Sobrien{
165490075Sobrien  const struct simplify_plus_minus_op_data *d1 = p1;
165590075Sobrien  const struct simplify_plus_minus_op_data *d2 = p2;
165690075Sobrien
165790075Sobrien  return (commutative_operand_precedence (d2->op)
165890075Sobrien	  - commutative_operand_precedence (d1->op));
165990075Sobrien}
166090075Sobrien
166190075Sobrienstatic rtx
166296263Sobriensimplify_plus_minus (code, mode, op0, op1, force)
166390075Sobrien     enum rtx_code code;
166490075Sobrien     enum machine_mode mode;
166590075Sobrien     rtx op0, op1;
166696263Sobrien     int force;
166790075Sobrien{
166890075Sobrien  struct simplify_plus_minus_op_data ops[8];
166990075Sobrien  rtx result, tem;
167090075Sobrien  int n_ops = 2, input_ops = 2, input_consts = 0, n_consts;
167190075Sobrien  int first, negate, changed;
167290075Sobrien  int i, j;
167390075Sobrien
167490075Sobrien  memset ((char *) ops, 0, sizeof ops);
1675117395Skan
167690075Sobrien  /* Set up the two operands and then expand them until nothing has been
167790075Sobrien     changed.  If we run out of room in our array, give up; this should
167890075Sobrien     almost never happen.  */
167990075Sobrien
168090075Sobrien  ops[0].op = op0;
168190075Sobrien  ops[0].neg = 0;
168290075Sobrien  ops[1].op = op1;
168390075Sobrien  ops[1].neg = (code == MINUS);
168490075Sobrien
168590075Sobrien  do
168690075Sobrien    {
168790075Sobrien      changed = 0;
168890075Sobrien
168990075Sobrien      for (i = 0; i < n_ops; i++)
169090075Sobrien	{
169190075Sobrien	  rtx this_op = ops[i].op;
169290075Sobrien	  int this_neg = ops[i].neg;
169390075Sobrien	  enum rtx_code this_code = GET_CODE (this_op);
169490075Sobrien
169590075Sobrien	  switch (this_code)
169690075Sobrien	    {
169790075Sobrien	    case PLUS:
169890075Sobrien	    case MINUS:
169990075Sobrien	      if (n_ops == 7)
170096263Sobrien		return NULL_RTX;
170190075Sobrien
170290075Sobrien	      ops[n_ops].op = XEXP (this_op, 1);
170390075Sobrien	      ops[n_ops].neg = (this_code == MINUS) ^ this_neg;
170490075Sobrien	      n_ops++;
170590075Sobrien
170690075Sobrien	      ops[i].op = XEXP (this_op, 0);
170790075Sobrien	      input_ops++;
170890075Sobrien	      changed = 1;
170990075Sobrien	      break;
171090075Sobrien
171190075Sobrien	    case NEG:
171290075Sobrien	      ops[i].op = XEXP (this_op, 0);
171390075Sobrien	      ops[i].neg = ! this_neg;
171490075Sobrien	      changed = 1;
171590075Sobrien	      break;
171690075Sobrien
171790075Sobrien	    case CONST:
171896263Sobrien	      if (n_ops < 7
171996263Sobrien		  && GET_CODE (XEXP (this_op, 0)) == PLUS
172096263Sobrien		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 0))
172196263Sobrien		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 1)))
172296263Sobrien		{
172396263Sobrien		  ops[i].op = XEXP (XEXP (this_op, 0), 0);
172496263Sobrien		  ops[n_ops].op = XEXP (XEXP (this_op, 0), 1);
172596263Sobrien		  ops[n_ops].neg = this_neg;
172696263Sobrien		  n_ops++;
172796263Sobrien		  input_consts++;
172896263Sobrien		  changed = 1;
172996263Sobrien		}
173090075Sobrien	      break;
173190075Sobrien
173290075Sobrien	    case NOT:
173390075Sobrien	      /* ~a -> (-a - 1) */
173490075Sobrien	      if (n_ops != 7)
173590075Sobrien		{
173690075Sobrien		  ops[n_ops].op = constm1_rtx;
173790075Sobrien		  ops[n_ops++].neg = this_neg;
173890075Sobrien		  ops[i].op = XEXP (this_op, 0);
173990075Sobrien		  ops[i].neg = !this_neg;
174090075Sobrien		  changed = 1;
174190075Sobrien		}
174290075Sobrien	      break;
174390075Sobrien
174490075Sobrien	    case CONST_INT:
174590075Sobrien	      if (this_neg)
174690075Sobrien		{
174790075Sobrien		  ops[i].op = neg_const_int (mode, this_op);
174890075Sobrien		  ops[i].neg = 0;
174990075Sobrien		  changed = 1;
175090075Sobrien		}
175190075Sobrien	      break;
175290075Sobrien
175390075Sobrien	    default:
175490075Sobrien	      break;
175590075Sobrien	    }
175690075Sobrien	}
175790075Sobrien    }
175890075Sobrien  while (changed);
175990075Sobrien
176090075Sobrien  /* If we only have two operands, we can't do anything.  */
176196263Sobrien  if (n_ops <= 2 && !force)
176290075Sobrien    return NULL_RTX;
176390075Sobrien
176496263Sobrien  /* Count the number of CONSTs we didn't split above.  */
176596263Sobrien  for (i = 0; i < n_ops; i++)
176696263Sobrien    if (GET_CODE (ops[i].op) == CONST)
176796263Sobrien      input_consts++;
176896263Sobrien
176990075Sobrien  /* Now simplify each pair of operands until nothing changes.  The first
177090075Sobrien     time through just simplify constants against each other.  */
177190075Sobrien
177290075Sobrien  first = 1;
177390075Sobrien  do
177490075Sobrien    {
177590075Sobrien      changed = first;
177690075Sobrien
177790075Sobrien      for (i = 0; i < n_ops - 1; i++)
177890075Sobrien	for (j = i + 1; j < n_ops; j++)
177990075Sobrien	  {
178090075Sobrien	    rtx lhs = ops[i].op, rhs = ops[j].op;
178190075Sobrien	    int lneg = ops[i].neg, rneg = ops[j].neg;
178290075Sobrien
178390075Sobrien	    if (lhs != 0 && rhs != 0
178490075Sobrien		&& (! first || (CONSTANT_P (lhs) && CONSTANT_P (rhs))))
178590075Sobrien	      {
178690075Sobrien		enum rtx_code ncode = PLUS;
178790075Sobrien
178890075Sobrien		if (lneg != rneg)
178990075Sobrien		  {
179090075Sobrien		    ncode = MINUS;
179190075Sobrien		    if (lneg)
179290075Sobrien		      tem = lhs, lhs = rhs, rhs = tem;
179390075Sobrien		  }
179490075Sobrien		else if (swap_commutative_operands_p (lhs, rhs))
179590075Sobrien		  tem = lhs, lhs = rhs, rhs = tem;
179690075Sobrien
179790075Sobrien		tem = simplify_binary_operation (ncode, mode, lhs, rhs);
179890075Sobrien
1799117395Skan		/* Reject "simplifications" that just wrap the two
180090075Sobrien		   arguments in a CONST.  Failure to do so can result
180190075Sobrien		   in infinite recursion with simplify_binary_operation
180290075Sobrien		   when it calls us to simplify CONST operations.  */
180390075Sobrien		if (tem
180490075Sobrien		    && ! (GET_CODE (tem) == CONST
180590075Sobrien			  && GET_CODE (XEXP (tem, 0)) == ncode
180690075Sobrien			  && XEXP (XEXP (tem, 0), 0) == lhs
180790075Sobrien			  && XEXP (XEXP (tem, 0), 1) == rhs)
180890075Sobrien		    /* Don't allow -x + -1 -> ~x simplifications in the
180990075Sobrien		       first pass.  This allows us the chance to combine
181090075Sobrien		       the -1 with other constants.  */
181190075Sobrien		    && ! (first
181290075Sobrien			  && GET_CODE (tem) == NOT
181390075Sobrien			  && XEXP (tem, 0) == rhs))
181490075Sobrien		  {
181590075Sobrien		    lneg &= rneg;
181690075Sobrien		    if (GET_CODE (tem) == NEG)
181790075Sobrien		      tem = XEXP (tem, 0), lneg = !lneg;
181890075Sobrien		    if (GET_CODE (tem) == CONST_INT && lneg)
181990075Sobrien		      tem = neg_const_int (mode, tem), lneg = 0;
182090075Sobrien
182190075Sobrien		    ops[i].op = tem;
182290075Sobrien		    ops[i].neg = lneg;
182390075Sobrien		    ops[j].op = NULL_RTX;
182490075Sobrien		    changed = 1;
182590075Sobrien		  }
182690075Sobrien	      }
182790075Sobrien	  }
182890075Sobrien
182990075Sobrien      first = 0;
183090075Sobrien    }
183190075Sobrien  while (changed);
183290075Sobrien
183390075Sobrien  /* Pack all the operands to the lower-numbered entries.  */
183490075Sobrien  for (i = 0, j = 0; j < n_ops; j++)
183590075Sobrien    if (ops[j].op)
183690075Sobrien      ops[i++] = ops[j];
183790075Sobrien  n_ops = i;
183890075Sobrien
183990075Sobrien  /* Sort the operations based on swap_commutative_operands_p.  */
184090075Sobrien  qsort (ops, n_ops, sizeof (*ops), simplify_plus_minus_op_data_cmp);
184190075Sobrien
184290075Sobrien  /* We suppressed creation of trivial CONST expressions in the
184390075Sobrien     combination loop to avoid recursion.  Create one manually now.
184490075Sobrien     The combination loop should have ensured that there is exactly
184590075Sobrien     one CONST_INT, and the sort will have ensured that it is last
184690075Sobrien     in the array and that any other constant will be next-to-last.  */
184790075Sobrien
184890075Sobrien  if (n_ops > 1
184990075Sobrien      && GET_CODE (ops[n_ops - 1].op) == CONST_INT
185090075Sobrien      && CONSTANT_P (ops[n_ops - 2].op))
185190075Sobrien    {
185290075Sobrien      rtx value = ops[n_ops - 1].op;
185390075Sobrien      if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg)
185490075Sobrien	value = neg_const_int (mode, value);
185590075Sobrien      ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value));
185690075Sobrien      n_ops--;
185790075Sobrien    }
185890075Sobrien
185990075Sobrien  /* Count the number of CONSTs that we generated.  */
186090075Sobrien  n_consts = 0;
186190075Sobrien  for (i = 0; i < n_ops; i++)
186290075Sobrien    if (GET_CODE (ops[i].op) == CONST)
186390075Sobrien      n_consts++;
186490075Sobrien
186590075Sobrien  /* Give up if we didn't reduce the number of operands we had.  Make
186690075Sobrien     sure we count a CONST as two operands.  If we have the same
186790075Sobrien     number of operands, but have made more CONSTs than before, this
186890075Sobrien     is also an improvement, so accept it.  */
186996263Sobrien  if (!force
187096263Sobrien      && (n_ops + n_consts > input_ops
1871117395Skan	  || (n_ops + n_consts == input_ops && n_consts <= input_consts)))
187290075Sobrien    return NULL_RTX;
187390075Sobrien
187490075Sobrien  /* Put a non-negated operand first.  If there aren't any, make all
187590075Sobrien     operands positive and negate the whole thing later.  */
187690075Sobrien
187790075Sobrien  negate = 0;
187890075Sobrien  for (i = 0; i < n_ops && ops[i].neg; i++)
187990075Sobrien    continue;
188090075Sobrien  if (i == n_ops)
188190075Sobrien    {
188290075Sobrien      for (i = 0; i < n_ops; i++)
188390075Sobrien	ops[i].neg = 0;
188490075Sobrien      negate = 1;
188590075Sobrien    }
188690075Sobrien  else if (i != 0)
188790075Sobrien    {
188890075Sobrien      tem = ops[0].op;
188990075Sobrien      ops[0] = ops[i];
189090075Sobrien      ops[i].op = tem;
189190075Sobrien      ops[i].neg = 1;
189290075Sobrien    }
189390075Sobrien
189490075Sobrien  /* Now make the result by performing the requested operations.  */
189590075Sobrien  result = ops[0].op;
189690075Sobrien  for (i = 1; i < n_ops; i++)
189790075Sobrien    result = gen_rtx_fmt_ee (ops[i].neg ? MINUS : PLUS,
189890075Sobrien			     mode, result, ops[i].op);
189990075Sobrien
190090075Sobrien  return negate ? gen_rtx_NEG (mode, result) : result;
190190075Sobrien}
190290075Sobrien
190390075Sobrien/* Like simplify_binary_operation except used for relational operators.
190490075Sobrien   MODE is the mode of the operands, not that of the result.  If MODE
190590075Sobrien   is VOIDmode, both operands must also be VOIDmode and we compare the
190690075Sobrien   operands in "infinite precision".
190790075Sobrien
190890075Sobrien   If no simplification is possible, this function returns zero.  Otherwise,
190990075Sobrien   it returns either const_true_rtx or const0_rtx.  */
191090075Sobrien
191190075Sobrienrtx
191290075Sobriensimplify_relational_operation (code, mode, op0, op1)
191390075Sobrien     enum rtx_code code;
191490075Sobrien     enum machine_mode mode;
191590075Sobrien     rtx op0, op1;
191690075Sobrien{
191790075Sobrien  int equal, op0lt, op0ltu, op1lt, op1ltu;
191890075Sobrien  rtx tem;
191990075Sobrien  rtx trueop0;
192090075Sobrien  rtx trueop1;
192190075Sobrien
192290075Sobrien  if (mode == VOIDmode
192390075Sobrien      && (GET_MODE (op0) != VOIDmode
192490075Sobrien	  || GET_MODE (op1) != VOIDmode))
192590075Sobrien    abort ();
192690075Sobrien
192790075Sobrien  /* If op0 is a compare, extract the comparison arguments from it.  */
192890075Sobrien  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
192990075Sobrien    op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
193090075Sobrien
193190075Sobrien  trueop0 = avoid_constant_pool_reference (op0);
193290075Sobrien  trueop1 = avoid_constant_pool_reference (op1);
193390075Sobrien
193490075Sobrien  /* We can't simplify MODE_CC values since we don't know what the
193590075Sobrien     actual comparison is.  */
193690075Sobrien  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC
193790075Sobrien#ifdef HAVE_cc0
193890075Sobrien      || op0 == cc0_rtx
193990075Sobrien#endif
194090075Sobrien      )
194190075Sobrien    return 0;
194290075Sobrien
194390075Sobrien  /* Make sure the constant is second.  */
194490075Sobrien  if (swap_commutative_operands_p (trueop0, trueop1))
194590075Sobrien    {
194690075Sobrien      tem = op0, op0 = op1, op1 = tem;
194790075Sobrien      tem = trueop0, trueop0 = trueop1, trueop1 = tem;
194890075Sobrien      code = swap_condition (code);
194990075Sobrien    }
195090075Sobrien
195190075Sobrien  /* For integer comparisons of A and B maybe we can simplify A - B and can
195290075Sobrien     then simplify a comparison of that with zero.  If A and B are both either
195390075Sobrien     a register or a CONST_INT, this can't help; testing for these cases will
195490075Sobrien     prevent infinite recursion here and speed things up.
195590075Sobrien
195690075Sobrien     If CODE is an unsigned comparison, then we can never do this optimization,
195790075Sobrien     because it gives an incorrect result if the subtraction wraps around zero.
195890075Sobrien     ANSI C defines unsigned operations such that they never overflow, and
195990075Sobrien     thus such cases can not be ignored.  */
196090075Sobrien
196190075Sobrien  if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
196290075Sobrien      && ! ((GET_CODE (op0) == REG || GET_CODE (trueop0) == CONST_INT)
196390075Sobrien	    && (GET_CODE (op1) == REG || GET_CODE (trueop1) == CONST_INT))
196490075Sobrien      && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
196590075Sobrien      && code != GTU && code != GEU && code != LTU && code != LEU)
196690075Sobrien    return simplify_relational_operation (signed_condition (code),
196790075Sobrien					  mode, tem, const0_rtx);
196890075Sobrien
196990075Sobrien  if (flag_unsafe_math_optimizations && code == ORDERED)
197090075Sobrien    return const_true_rtx;
197190075Sobrien
197290075Sobrien  if (flag_unsafe_math_optimizations && code == UNORDERED)
197390075Sobrien    return const0_rtx;
197490075Sobrien
1975117395Skan  /* For modes without NaNs, if the two operands are equal, we know the
1976117395Skan     result.  Nevertheless, don't discard them if they have side-effects.  */
1977117395Skan  if (!HONOR_NANS (GET_MODE (trueop0))
1978117395Skan      && rtx_equal_p (trueop0, trueop1)
1979117395Skan      && ! side_effects_p (trueop0))
198090075Sobrien    equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
198190075Sobrien
198290075Sobrien  /* If the operands are floating-point constants, see if we can fold
198390075Sobrien     the result.  */
198490075Sobrien  else if (GET_CODE (trueop0) == CONST_DOUBLE
198590075Sobrien	   && GET_CODE (trueop1) == CONST_DOUBLE
198690075Sobrien	   && GET_MODE_CLASS (GET_MODE (trueop0)) == MODE_FLOAT)
198790075Sobrien    {
1988117395Skan      REAL_VALUE_TYPE d0, d1;
198990075Sobrien
1990117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (d0, trueop0);
1991117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (d1, trueop1);
199290075Sobrien
1993117395Skan      /* Comparisons are unordered iff at least one of the values is NaN.  */
1994117395Skan      if (REAL_VALUE_ISNAN (d0) || REAL_VALUE_ISNAN (d1))
199590075Sobrien	switch (code)
199690075Sobrien	  {
199790075Sobrien	  case UNEQ:
199890075Sobrien	  case UNLT:
199990075Sobrien	  case UNGT:
200090075Sobrien	  case UNLE:
200190075Sobrien	  case UNGE:
200290075Sobrien	  case NE:
200390075Sobrien	  case UNORDERED:
200490075Sobrien	    return const_true_rtx;
200590075Sobrien	  case EQ:
200690075Sobrien	  case LT:
200790075Sobrien	  case GT:
200890075Sobrien	  case LE:
200990075Sobrien	  case GE:
201090075Sobrien	  case LTGT:
201190075Sobrien	  case ORDERED:
201290075Sobrien	    return const0_rtx;
201390075Sobrien	  default:
201490075Sobrien	    return 0;
201590075Sobrien	  }
201690075Sobrien
2017117395Skan      equal = REAL_VALUES_EQUAL (d0, d1);
2018117395Skan      op0lt = op0ltu = REAL_VALUES_LESS (d0, d1);
2019117395Skan      op1lt = op1ltu = REAL_VALUES_LESS (d1, d0);
202090075Sobrien    }
202190075Sobrien
202290075Sobrien  /* Otherwise, see if the operands are both integers.  */
202390075Sobrien  else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
202490075Sobrien	   && (GET_CODE (trueop0) == CONST_DOUBLE
202590075Sobrien	       || GET_CODE (trueop0) == CONST_INT)
202690075Sobrien	   && (GET_CODE (trueop1) == CONST_DOUBLE
202790075Sobrien	       || GET_CODE (trueop1) == CONST_INT))
202890075Sobrien    {
202990075Sobrien      int width = GET_MODE_BITSIZE (mode);
203090075Sobrien      HOST_WIDE_INT l0s, h0s, l1s, h1s;
203190075Sobrien      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
203290075Sobrien
203390075Sobrien      /* Get the two words comprising each integer constant.  */
203490075Sobrien      if (GET_CODE (trueop0) == CONST_DOUBLE)
203590075Sobrien	{
203690075Sobrien	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
203790075Sobrien	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
203890075Sobrien	}
203990075Sobrien      else
204090075Sobrien	{
204190075Sobrien	  l0u = l0s = INTVAL (trueop0);
204290075Sobrien	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
204390075Sobrien	}
2044117395Skan
204590075Sobrien      if (GET_CODE (trueop1) == CONST_DOUBLE)
204690075Sobrien	{
204790075Sobrien	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
204890075Sobrien	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
204990075Sobrien	}
205090075Sobrien      else
205190075Sobrien	{
205290075Sobrien	  l1u = l1s = INTVAL (trueop1);
205390075Sobrien	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
205490075Sobrien	}
205590075Sobrien
205690075Sobrien      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
205790075Sobrien	 we have to sign or zero-extend the values.  */
205890075Sobrien      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
205990075Sobrien	{
206090075Sobrien	  l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
206190075Sobrien	  l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
206290075Sobrien
206390075Sobrien	  if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
206490075Sobrien	    l0s |= ((HOST_WIDE_INT) (-1) << width);
206590075Sobrien
206690075Sobrien	  if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
206790075Sobrien	    l1s |= ((HOST_WIDE_INT) (-1) << width);
206890075Sobrien	}
206990075Sobrien      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
207090075Sobrien	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
207190075Sobrien
207290075Sobrien      equal = (h0u == h1u && l0u == l1u);
207390075Sobrien      op0lt = (h0s < h1s || (h0s == h1s && l0u < l1u));
207490075Sobrien      op1lt = (h1s < h0s || (h1s == h0s && l1u < l0u));
207590075Sobrien      op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
207690075Sobrien      op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
207790075Sobrien    }
207890075Sobrien
207990075Sobrien  /* Otherwise, there are some code-specific tests we can make.  */
208090075Sobrien  else
208190075Sobrien    {
208290075Sobrien      switch (code)
208390075Sobrien	{
208490075Sobrien	case EQ:
208590075Sobrien	  /* References to the frame plus a constant or labels cannot
208690075Sobrien	     be zero, but a SYMBOL_REF can due to #pragma weak.  */
208790075Sobrien	  if (((NONZERO_BASE_PLUS_P (op0) && trueop1 == const0_rtx)
208890075Sobrien	       || GET_CODE (trueop0) == LABEL_REF)
208990075Sobrien#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
209090075Sobrien	      /* On some machines, the ap reg can be 0 sometimes.  */
209190075Sobrien	      && op0 != arg_pointer_rtx
209290075Sobrien#endif
209390075Sobrien		)
209490075Sobrien	    return const0_rtx;
209590075Sobrien	  break;
209690075Sobrien
209790075Sobrien	case NE:
209890075Sobrien	  if (((NONZERO_BASE_PLUS_P (op0) && trueop1 == const0_rtx)
209990075Sobrien	       || GET_CODE (trueop0) == LABEL_REF)
210090075Sobrien#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
210190075Sobrien	      && op0 != arg_pointer_rtx
210290075Sobrien#endif
210390075Sobrien	      )
210490075Sobrien	    return const_true_rtx;
210590075Sobrien	  break;
210690075Sobrien
210790075Sobrien	case GEU:
210890075Sobrien	  /* Unsigned values are never negative.  */
210990075Sobrien	  if (trueop1 == const0_rtx)
211090075Sobrien	    return const_true_rtx;
211190075Sobrien	  break;
211290075Sobrien
211390075Sobrien	case LTU:
211490075Sobrien	  if (trueop1 == const0_rtx)
211590075Sobrien	    return const0_rtx;
211690075Sobrien	  break;
211790075Sobrien
211890075Sobrien	case LEU:
211990075Sobrien	  /* Unsigned values are never greater than the largest
212090075Sobrien	     unsigned value.  */
212190075Sobrien	  if (GET_CODE (trueop1) == CONST_INT
212290075Sobrien	      && (unsigned HOST_WIDE_INT) INTVAL (trueop1) == GET_MODE_MASK (mode)
212390075Sobrien	    && INTEGRAL_MODE_P (mode))
212490075Sobrien	  return const_true_rtx;
212590075Sobrien	  break;
212690075Sobrien
212790075Sobrien	case GTU:
212890075Sobrien	  if (GET_CODE (trueop1) == CONST_INT
212990075Sobrien	      && (unsigned HOST_WIDE_INT) INTVAL (trueop1) == GET_MODE_MASK (mode)
213090075Sobrien	      && INTEGRAL_MODE_P (mode))
213190075Sobrien	    return const0_rtx;
213290075Sobrien	  break;
2133117395Skan
2134117395Skan	case LT:
2135117395Skan	  /* Optimize abs(x) < 0.0.  */
2136117395Skan	  if (trueop1 == CONST0_RTX (mode) && !HONOR_SNANS (mode))
2137117395Skan	    {
2138117395Skan	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
2139117395Skan						       : trueop0;
2140117395Skan	      if (GET_CODE (tem) == ABS)
2141117395Skan		return const0_rtx;
2142117395Skan	    }
2143117395Skan	  break;
2144117395Skan
2145117395Skan	case GE:
2146117395Skan	  /* Optimize abs(x) >= 0.0.  */
2147117395Skan	  if (trueop1 == CONST0_RTX (mode) && !HONOR_NANS (mode))
2148117395Skan	    {
2149117395Skan	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
2150117395Skan						       : trueop0;
2151117395Skan	      if (GET_CODE (tem) == ABS)
2152117395Skan		return const1_rtx;
2153117395Skan	    }
2154117395Skan	  break;
2155117395Skan
215690075Sobrien	default:
215790075Sobrien	  break;
215890075Sobrien	}
215990075Sobrien
216090075Sobrien      return 0;
216190075Sobrien    }
216290075Sobrien
216390075Sobrien  /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
216490075Sobrien     as appropriate.  */
216590075Sobrien  switch (code)
216690075Sobrien    {
216790075Sobrien    case EQ:
216890075Sobrien    case UNEQ:
216990075Sobrien      return equal ? const_true_rtx : const0_rtx;
217090075Sobrien    case NE:
217190075Sobrien    case LTGT:
217290075Sobrien      return ! equal ? const_true_rtx : const0_rtx;
217390075Sobrien    case LT:
217490075Sobrien    case UNLT:
217590075Sobrien      return op0lt ? const_true_rtx : const0_rtx;
217690075Sobrien    case GT:
217790075Sobrien    case UNGT:
217890075Sobrien      return op1lt ? const_true_rtx : const0_rtx;
217990075Sobrien    case LTU:
218090075Sobrien      return op0ltu ? const_true_rtx : const0_rtx;
218190075Sobrien    case GTU:
218290075Sobrien      return op1ltu ? const_true_rtx : const0_rtx;
218390075Sobrien    case LE:
218490075Sobrien    case UNLE:
218590075Sobrien      return equal || op0lt ? const_true_rtx : const0_rtx;
218690075Sobrien    case GE:
218790075Sobrien    case UNGE:
218890075Sobrien      return equal || op1lt ? const_true_rtx : const0_rtx;
218990075Sobrien    case LEU:
219090075Sobrien      return equal || op0ltu ? const_true_rtx : const0_rtx;
219190075Sobrien    case GEU:
219290075Sobrien      return equal || op1ltu ? const_true_rtx : const0_rtx;
219390075Sobrien    case ORDERED:
219490075Sobrien      return const_true_rtx;
219590075Sobrien    case UNORDERED:
219690075Sobrien      return const0_rtx;
219790075Sobrien    default:
219890075Sobrien      abort ();
219990075Sobrien    }
220090075Sobrien}
220190075Sobrien
220290075Sobrien/* Simplify CODE, an operation with result mode MODE and three operands,
220390075Sobrien   OP0, OP1, and OP2.  OP0_MODE was the mode of OP0 before it became
220490075Sobrien   a constant.  Return 0 if no simplifications is possible.  */
220590075Sobrien
220690075Sobrienrtx
220790075Sobriensimplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
220890075Sobrien     enum rtx_code code;
220990075Sobrien     enum machine_mode mode, op0_mode;
221090075Sobrien     rtx op0, op1, op2;
221190075Sobrien{
221290075Sobrien  unsigned int width = GET_MODE_BITSIZE (mode);
221390075Sobrien
221490075Sobrien  /* VOIDmode means "infinite" precision.  */
221590075Sobrien  if (width == 0)
221690075Sobrien    width = HOST_BITS_PER_WIDE_INT;
221790075Sobrien
221890075Sobrien  switch (code)
221990075Sobrien    {
222090075Sobrien    case SIGN_EXTRACT:
222190075Sobrien    case ZERO_EXTRACT:
222290075Sobrien      if (GET_CODE (op0) == CONST_INT
222390075Sobrien	  && GET_CODE (op1) == CONST_INT
222490075Sobrien	  && GET_CODE (op2) == CONST_INT
222590075Sobrien	  && ((unsigned) INTVAL (op1) + (unsigned) INTVAL (op2) <= width)
222690075Sobrien	  && width <= (unsigned) HOST_BITS_PER_WIDE_INT)
222790075Sobrien	{
222890075Sobrien	  /* Extracting a bit-field from a constant */
222990075Sobrien	  HOST_WIDE_INT val = INTVAL (op0);
223090075Sobrien
223190075Sobrien	  if (BITS_BIG_ENDIAN)
223290075Sobrien	    val >>= (GET_MODE_BITSIZE (op0_mode)
223390075Sobrien		     - INTVAL (op2) - INTVAL (op1));
223490075Sobrien	  else
223590075Sobrien	    val >>= INTVAL (op2);
223690075Sobrien
223790075Sobrien	  if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
223890075Sobrien	    {
223990075Sobrien	      /* First zero-extend.  */
224090075Sobrien	      val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
224190075Sobrien	      /* If desired, propagate sign bit.  */
224290075Sobrien	      if (code == SIGN_EXTRACT
224390075Sobrien		  && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1))))
224490075Sobrien		val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
224590075Sobrien	    }
224690075Sobrien
224790075Sobrien	  /* Clear the bits that don't belong in our mode,
224890075Sobrien	     unless they and our sign bit are all one.
224990075Sobrien	     So we get either a reasonable negative value or a reasonable
225090075Sobrien	     unsigned value for this mode.  */
225190075Sobrien	  if (width < HOST_BITS_PER_WIDE_INT
225290075Sobrien	      && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
225390075Sobrien		  != ((HOST_WIDE_INT) (-1) << (width - 1))))
225490075Sobrien	    val &= ((HOST_WIDE_INT) 1 << width) - 1;
225590075Sobrien
225690075Sobrien	  return GEN_INT (val);
225790075Sobrien	}
225890075Sobrien      break;
225990075Sobrien
226090075Sobrien    case IF_THEN_ELSE:
226190075Sobrien      if (GET_CODE (op0) == CONST_INT)
226290075Sobrien	return op0 != const0_rtx ? op1 : op2;
226390075Sobrien
226490075Sobrien      /* Convert a == b ? b : a to "a".  */
226590075Sobrien      if (GET_CODE (op0) == NE && ! side_effects_p (op0)
2266117395Skan	  && !HONOR_NANS (mode)
226790075Sobrien	  && rtx_equal_p (XEXP (op0, 0), op1)
226890075Sobrien	  && rtx_equal_p (XEXP (op0, 1), op2))
226990075Sobrien	return op1;
227090075Sobrien      else if (GET_CODE (op0) == EQ && ! side_effects_p (op0)
2271117395Skan	  && !HONOR_NANS (mode)
227290075Sobrien	  && rtx_equal_p (XEXP (op0, 1), op1)
227390075Sobrien	  && rtx_equal_p (XEXP (op0, 0), op2))
227490075Sobrien	return op2;
227590075Sobrien      else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
227690075Sobrien	{
227790075Sobrien	  enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
227890075Sobrien					? GET_MODE (XEXP (op0, 1))
227990075Sobrien					: GET_MODE (XEXP (op0, 0)));
228090075Sobrien	  rtx temp;
228190075Sobrien	  if (cmp_mode == VOIDmode)
228290075Sobrien	    cmp_mode = op0_mode;
228390075Sobrien	  temp = simplify_relational_operation (GET_CODE (op0), cmp_mode,
228490075Sobrien					        XEXP (op0, 0), XEXP (op0, 1));
228590075Sobrien
228690075Sobrien	  /* See if any simplifications were possible.  */
228790075Sobrien	  if (temp == const0_rtx)
228890075Sobrien	    return op2;
228990075Sobrien	  else if (temp == const1_rtx)
229090075Sobrien	    return op1;
229190075Sobrien	  else if (temp)
229290075Sobrien	    op0 = temp;
229390075Sobrien
229490075Sobrien	  /* Look for happy constants in op1 and op2.  */
229590075Sobrien	  if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
229690075Sobrien	    {
229790075Sobrien	      HOST_WIDE_INT t = INTVAL (op1);
229890075Sobrien	      HOST_WIDE_INT f = INTVAL (op2);
2299117395Skan
230090075Sobrien	      if (t == STORE_FLAG_VALUE && f == 0)
230190075Sobrien	        code = GET_CODE (op0);
230290075Sobrien	      else if (t == 0 && f == STORE_FLAG_VALUE)
230390075Sobrien		{
230490075Sobrien		  enum rtx_code tmp;
230590075Sobrien		  tmp = reversed_comparison_code (op0, NULL_RTX);
230690075Sobrien		  if (tmp == UNKNOWN)
230790075Sobrien		    break;
230890075Sobrien		  code = tmp;
230990075Sobrien		}
231090075Sobrien	      else
231190075Sobrien		break;
231290075Sobrien
231390075Sobrien	      return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1));
231490075Sobrien	    }
231590075Sobrien	}
231690075Sobrien      break;
2317117395Skan    case VEC_MERGE:
2318117395Skan      if (GET_MODE (op0) != mode
2319117395Skan	  || GET_MODE (op1) != mode
2320117395Skan	  || !VECTOR_MODE_P (mode))
2321117395Skan	abort ();
2322117395Skan      op0 = avoid_constant_pool_reference (op0);
2323117395Skan      op1 = avoid_constant_pool_reference (op1);
2324117395Skan      op2 = avoid_constant_pool_reference (op2);
2325117395Skan      if (GET_CODE (op0) == CONST_VECTOR
2326117395Skan	  && GET_CODE (op1) == CONST_VECTOR
2327117395Skan	  && GET_CODE (op2) == CONST_INT)
2328117395Skan	{
2329117395Skan          int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
2330117395Skan	  unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
2331117395Skan	  rtvec v = rtvec_alloc (n_elts);
2332117395Skan	  unsigned int i;
233390075Sobrien
2334117395Skan	  for (i = 0; i < n_elts; i++)
2335117395Skan	    RTVEC_ELT (v, i) = (INTVAL (op2) & (1 << i)
2336117395Skan				? CONST_VECTOR_ELT (op0, i)
2337117395Skan				: CONST_VECTOR_ELT (op1, i));
2338117395Skan	  return gen_rtx_CONST_VECTOR (mode, v);
2339117395Skan	}
2340117395Skan      break;
2341117395Skan
234290075Sobrien    default:
234390075Sobrien      abort ();
234490075Sobrien    }
234590075Sobrien
234690075Sobrien  return 0;
234790075Sobrien}
234890075Sobrien
234990075Sobrien/* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
235090075Sobrien   Return 0 if no simplifications is possible.  */
235190075Sobrienrtx
235290075Sobriensimplify_subreg (outermode, op, innermode, byte)
235390075Sobrien     rtx op;
235490075Sobrien     unsigned int byte;
235590075Sobrien     enum machine_mode outermode, innermode;
235690075Sobrien{
235790075Sobrien  /* Little bit of sanity checking.  */
235890075Sobrien  if (innermode == VOIDmode || outermode == VOIDmode
235990075Sobrien      || innermode == BLKmode || outermode == BLKmode)
236090075Sobrien    abort ();
236190075Sobrien
236290075Sobrien  if (GET_MODE (op) != innermode
236390075Sobrien      && GET_MODE (op) != VOIDmode)
236490075Sobrien    abort ();
236590075Sobrien
236690075Sobrien  if (byte % GET_MODE_SIZE (outermode)
236790075Sobrien      || byte >= GET_MODE_SIZE (innermode))
236890075Sobrien    abort ();
236990075Sobrien
237090075Sobrien  if (outermode == innermode && !byte)
237190075Sobrien    return op;
237290075Sobrien
2373117395Skan  /* Simplify subregs of vector constants.  */
2374117395Skan  if (GET_CODE (op) == CONST_VECTOR)
2375117395Skan    {
2376117395Skan      int elt_size = GET_MODE_SIZE (GET_MODE_INNER (innermode));
2377117395Skan      const unsigned int offset = byte / elt_size;
2378117395Skan      rtx elt;
2379117395Skan
2380117395Skan      if (GET_MODE_INNER (innermode) == outermode)
2381117395Skan	{
2382117395Skan	  elt = CONST_VECTOR_ELT (op, offset);
2383117395Skan
2384117395Skan	  /* ?? We probably don't need this copy_rtx because constants
2385117395Skan	     can be shared.  ?? */
2386117395Skan
2387117395Skan	  return copy_rtx (elt);
2388117395Skan	}
2389117395Skan      else if (GET_MODE_INNER (innermode) == GET_MODE_INNER (outermode)
2390117395Skan	       && GET_MODE_SIZE (innermode) > GET_MODE_SIZE (outermode))
2391117395Skan	{
2392117395Skan	  return (gen_rtx_CONST_VECTOR
2393117395Skan		  (outermode,
2394117395Skan		   gen_rtvec_v (GET_MODE_NUNITS (outermode),
2395117395Skan				&CONST_VECTOR_ELT (op, offset))));
2396117395Skan	}
2397117395Skan      else if (GET_MODE_CLASS (outermode) == MODE_INT
2398117395Skan	       && (GET_MODE_SIZE (outermode) % elt_size == 0))
2399117395Skan	{
2400117395Skan	  /* This happens when the target register size is smaller then
2401117395Skan	     the vector mode, and we synthesize operations with vectors
2402117395Skan	     of elements that are smaller than the register size.  */
2403117395Skan	  HOST_WIDE_INT sum = 0, high = 0;
2404117395Skan	  unsigned n_elts = (GET_MODE_SIZE (outermode) / elt_size);
2405117395Skan	  unsigned i = BYTES_BIG_ENDIAN ? offset : offset + n_elts - 1;
2406117395Skan	  unsigned step = BYTES_BIG_ENDIAN ? 1 : -1;
2407117395Skan	  int shift = BITS_PER_UNIT * elt_size;
2408117395Skan
2409117395Skan	  for (; n_elts--; i += step)
2410117395Skan	    {
2411117395Skan	      elt = CONST_VECTOR_ELT (op, i);
2412117395Skan	      if (GET_CODE (elt) == CONST_DOUBLE
2413117395Skan		  && GET_MODE_CLASS (GET_MODE (elt)) == MODE_FLOAT)
2414117395Skan		{
2415117395Skan		  elt = gen_lowpart_common (int_mode_for_mode (GET_MODE (elt)),
2416117395Skan					    elt);
2417117395Skan		  if (! elt)
2418117395Skan		    return NULL_RTX;
2419117395Skan		}
2420117395Skan	      if (GET_CODE (elt) != CONST_INT)
2421117395Skan		return NULL_RTX;
2422117395Skan	      /* Avoid overflow.  */
2423117395Skan	      if (high >> (HOST_BITS_PER_WIDE_INT - shift))
2424117395Skan		return NULL_RTX;
2425117395Skan	      high = high << shift | sum >> (HOST_BITS_PER_WIDE_INT - shift);
2426117395Skan	      sum = (sum << shift) + INTVAL (elt);
2427117395Skan	    }
2428117395Skan	  if (GET_MODE_BITSIZE (outermode) <= HOST_BITS_PER_WIDE_INT)
2429117395Skan	    return GEN_INT (trunc_int_for_mode (sum, outermode));
2430117395Skan	  else if (GET_MODE_BITSIZE (outermode) == 2* HOST_BITS_PER_WIDE_INT)
2431117395Skan	    return immed_double_const (sum, high, outermode);
2432117395Skan	  else
2433117395Skan	    return NULL_RTX;
2434117395Skan	}
2435117395Skan      else if (GET_MODE_CLASS (outermode) == MODE_INT
2436117395Skan	       && (elt_size % GET_MODE_SIZE (outermode) == 0))
2437117395Skan	{
2438117395Skan	  enum machine_mode new_mode
2439117395Skan	    = int_mode_for_mode (GET_MODE_INNER (innermode));
2440117395Skan	  int subbyte = byte % elt_size;
2441117395Skan
2442117395Skan	  op = simplify_subreg (new_mode, op, innermode, byte - subbyte);
2443117395Skan	    if (! op)
2444117395Skan	      return NULL_RTX;
2445117395Skan	  return simplify_subreg (outermode, op, new_mode, subbyte);
2446117395Skan	}
2447117395Skan      else if (GET_MODE_CLASS (outermode) == MODE_INT)
2448117395Skan        /* This shouldn't happen, but let's not do anything stupid.  */
2449117395Skan	return NULL_RTX;
2450117395Skan    }
2451117395Skan
245290075Sobrien  /* Attempt to simplify constant to non-SUBREG expression.  */
245390075Sobrien  if (CONSTANT_P (op))
245490075Sobrien    {
245590075Sobrien      int offset, part;
245690075Sobrien      unsigned HOST_WIDE_INT val = 0;
245790075Sobrien
2458117395Skan      if (GET_MODE_CLASS (outermode) == MODE_VECTOR_INT
2459117395Skan	  || GET_MODE_CLASS (outermode) == MODE_VECTOR_FLOAT)
2460117395Skan	{
2461117395Skan	  /* Construct a CONST_VECTOR from individual subregs.  */
2462117395Skan	  enum machine_mode submode = GET_MODE_INNER (outermode);
2463117395Skan	  int subsize = GET_MODE_UNIT_SIZE (outermode);
2464117395Skan	  int i, elts = GET_MODE_NUNITS (outermode);
2465117395Skan	  rtvec v = rtvec_alloc (elts);
2466117395Skan	  rtx elt;
2467117395Skan
2468117395Skan	  for (i = 0; i < elts; i++, byte += subsize)
2469117395Skan	    {
2470117395Skan	      /* This might fail, e.g. if taking a subreg from a SYMBOL_REF.  */
2471117395Skan	      /* ??? It would be nice if we could actually make such subregs
2472117395Skan		 on targets that allow such relocations.  */
2473117395Skan	      if (byte >= GET_MODE_UNIT_SIZE (innermode))
2474117395Skan		elt = CONST0_RTX (submode);
2475117395Skan	      else
2476117395Skan	        elt = simplify_subreg (submode, op, innermode, byte);
2477117395Skan	      if (! elt)
2478117395Skan		return NULL_RTX;
2479117395Skan	      RTVEC_ELT (v, i) = elt;
2480117395Skan	    }
2481117395Skan	  return gen_rtx_CONST_VECTOR (outermode, v);
2482117395Skan	}
2483117395Skan
248490075Sobrien      /* ??? This code is partly redundant with code below, but can handle
248590075Sobrien	 the subregs of floats and similar corner cases.
248690075Sobrien	 Later it we should move all simplification code here and rewrite
248790075Sobrien	 GEN_LOWPART_IF_POSSIBLE, GEN_HIGHPART, OPERAND_SUBWORD and friends
248890075Sobrien	 using SIMPLIFY_SUBREG.  */
2489117395Skan      if (subreg_lowpart_offset (outermode, innermode) == byte
2490117395Skan	  && GET_CODE (op) != CONST_VECTOR)
249190075Sobrien	{
249290075Sobrien	  rtx new = gen_lowpart_if_possible (outermode, op);
249390075Sobrien	  if (new)
249490075Sobrien	    return new;
249590075Sobrien	}
249690075Sobrien
249790075Sobrien      /* Similar comment as above apply here.  */
249890075Sobrien      if (GET_MODE_SIZE (outermode) == UNITS_PER_WORD
249990075Sobrien	  && GET_MODE_SIZE (innermode) > UNITS_PER_WORD
250090075Sobrien	  && GET_MODE_CLASS (outermode) == MODE_INT)
250190075Sobrien	{
250290075Sobrien	  rtx new = constant_subword (op,
250390075Sobrien				      (byte / UNITS_PER_WORD),
250490075Sobrien				      innermode);
250590075Sobrien	  if (new)
250690075Sobrien	    return new;
250790075Sobrien	}
250890075Sobrien
2509117395Skan      if (GET_MODE_CLASS (outermode) != MODE_INT
2510117395Skan	  && GET_MODE_CLASS (outermode) != MODE_CC)
2511117395Skan	{
2512117395Skan	  enum machine_mode new_mode = int_mode_for_mode (outermode);
2513117395Skan
2514117395Skan	  if (new_mode != innermode || byte != 0)
2515117395Skan	    {
2516117395Skan	      op = simplify_subreg (new_mode, op, innermode, byte);
2517117395Skan	      if (! op)
2518117395Skan		return NULL_RTX;
2519117395Skan	      return simplify_subreg (outermode, op, new_mode, 0);
2520117395Skan	    }
2521117395Skan	}
2522117395Skan
252390075Sobrien      offset = byte * BITS_PER_UNIT;
252490075Sobrien      switch (GET_CODE (op))
252590075Sobrien	{
252690075Sobrien	case CONST_DOUBLE:
252790075Sobrien	  if (GET_MODE (op) != VOIDmode)
252890075Sobrien	    break;
252990075Sobrien
253090075Sobrien	  /* We can't handle this case yet.  */
253190075Sobrien	  if (GET_MODE_BITSIZE (outermode) >= HOST_BITS_PER_WIDE_INT)
253290075Sobrien	    return NULL_RTX;
253390075Sobrien
253490075Sobrien	  part = offset >= HOST_BITS_PER_WIDE_INT;
253590075Sobrien	  if ((BITS_PER_WORD > HOST_BITS_PER_WIDE_INT
253690075Sobrien	       && BYTES_BIG_ENDIAN)
253790075Sobrien	      || (BITS_PER_WORD <= HOST_BITS_PER_WIDE_INT
253890075Sobrien		  && WORDS_BIG_ENDIAN))
253990075Sobrien	    part = !part;
254090075Sobrien	  val = part ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op);
254190075Sobrien	  offset %= HOST_BITS_PER_WIDE_INT;
254290075Sobrien
2543117395Skan	  /* We've already picked the word we want from a double, so
254490075Sobrien	     pretend this is actually an integer.  */
254590075Sobrien	  innermode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
254690075Sobrien
254790075Sobrien	  /* FALLTHROUGH */
254890075Sobrien	case CONST_INT:
254990075Sobrien	  if (GET_CODE (op) == CONST_INT)
255090075Sobrien	    val = INTVAL (op);
255190075Sobrien
255290075Sobrien	  /* We don't handle synthetizing of non-integral constants yet.  */
255390075Sobrien	  if (GET_MODE_CLASS (outermode) != MODE_INT)
255490075Sobrien	    return NULL_RTX;
255590075Sobrien
255690075Sobrien	  if (BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN)
255790075Sobrien	    {
255890075Sobrien	      if (WORDS_BIG_ENDIAN)
255990075Sobrien		offset = (GET_MODE_BITSIZE (innermode)
256090075Sobrien			  - GET_MODE_BITSIZE (outermode) - offset);
256190075Sobrien	      if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
256290075Sobrien		  && GET_MODE_SIZE (outermode) < UNITS_PER_WORD)
256390075Sobrien		offset = (offset + BITS_PER_WORD - GET_MODE_BITSIZE (outermode)
256490075Sobrien			  - 2 * (offset % BITS_PER_WORD));
256590075Sobrien	    }
256690075Sobrien
256790075Sobrien	  if (offset >= HOST_BITS_PER_WIDE_INT)
256890075Sobrien	    return ((HOST_WIDE_INT) val < 0) ? constm1_rtx : const0_rtx;
256990075Sobrien	  else
257090075Sobrien	    {
257190075Sobrien	      val >>= offset;
257290075Sobrien	      if (GET_MODE_BITSIZE (outermode) < HOST_BITS_PER_WIDE_INT)
257390075Sobrien		val = trunc_int_for_mode (val, outermode);
257490075Sobrien	      return GEN_INT (val);
257590075Sobrien	    }
257690075Sobrien	default:
257790075Sobrien	  break;
257890075Sobrien	}
257990075Sobrien    }
258090075Sobrien
258190075Sobrien  /* Changing mode twice with SUBREG => just change it once,
258290075Sobrien     or not at all if changing back op starting mode.  */
258390075Sobrien  if (GET_CODE (op) == SUBREG)
258490075Sobrien    {
258590075Sobrien      enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
258690075Sobrien      int final_offset = byte + SUBREG_BYTE (op);
258790075Sobrien      rtx new;
258890075Sobrien
258990075Sobrien      if (outermode == innermostmode
259090075Sobrien	  && byte == 0 && SUBREG_BYTE (op) == 0)
259190075Sobrien	return SUBREG_REG (op);
259290075Sobrien
259390075Sobrien      /* The SUBREG_BYTE represents offset, as if the value were stored
259490075Sobrien	 in memory.  Irritating exception is paradoxical subreg, where
259590075Sobrien	 we define SUBREG_BYTE to be 0.  On big endian machines, this
259690075Sobrien	 value should be negative.  For a moment, undo this exception.  */
259790075Sobrien      if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
259890075Sobrien	{
259990075Sobrien	  int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
260090075Sobrien	  if (WORDS_BIG_ENDIAN)
260190075Sobrien	    final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
260290075Sobrien	  if (BYTES_BIG_ENDIAN)
260390075Sobrien	    final_offset += difference % UNITS_PER_WORD;
260490075Sobrien	}
260590075Sobrien      if (SUBREG_BYTE (op) == 0
260690075Sobrien	  && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
260790075Sobrien	{
260890075Sobrien	  int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
260990075Sobrien	  if (WORDS_BIG_ENDIAN)
261090075Sobrien	    final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
261190075Sobrien	  if (BYTES_BIG_ENDIAN)
261290075Sobrien	    final_offset += difference % UNITS_PER_WORD;
261390075Sobrien	}
261490075Sobrien
261590075Sobrien      /* See whether resulting subreg will be paradoxical.  */
261690075Sobrien      if (GET_MODE_SIZE (innermostmode) > GET_MODE_SIZE (outermode))
261790075Sobrien	{
261890075Sobrien	  /* In nonparadoxical subregs we can't handle negative offsets.  */
261990075Sobrien	  if (final_offset < 0)
262090075Sobrien	    return NULL_RTX;
262190075Sobrien	  /* Bail out in case resulting subreg would be incorrect.  */
262290075Sobrien	  if (final_offset % GET_MODE_SIZE (outermode)
262390075Sobrien	      || (unsigned) final_offset >= GET_MODE_SIZE (innermostmode))
262490075Sobrien	    return NULL_RTX;
262590075Sobrien	}
262690075Sobrien      else
262790075Sobrien	{
262890075Sobrien	  int offset = 0;
262990075Sobrien	  int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode));
263090075Sobrien
263190075Sobrien	  /* In paradoxical subreg, see if we are still looking on lower part.
263290075Sobrien	     If so, our SUBREG_BYTE will be 0.  */
263390075Sobrien	  if (WORDS_BIG_ENDIAN)
263490075Sobrien	    offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
263590075Sobrien	  if (BYTES_BIG_ENDIAN)
263690075Sobrien	    offset += difference % UNITS_PER_WORD;
263790075Sobrien	  if (offset == final_offset)
263890075Sobrien	    final_offset = 0;
263990075Sobrien	  else
264090075Sobrien	    return NULL_RTX;
264190075Sobrien	}
264290075Sobrien
264390075Sobrien      /* Recurse for futher possible simplifications.  */
264490075Sobrien      new = simplify_subreg (outermode, SUBREG_REG (op),
264590075Sobrien			     GET_MODE (SUBREG_REG (op)),
264690075Sobrien			     final_offset);
264790075Sobrien      if (new)
264890075Sobrien	return new;
264990075Sobrien      return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
265090075Sobrien    }
265190075Sobrien
265290075Sobrien  /* SUBREG of a hard register => just change the register number
265390075Sobrien     and/or mode.  If the hard register is not valid in that mode,
265490075Sobrien     suppress this simplification.  If the hard register is the stack,
265590075Sobrien     frame, or argument pointer, leave this as a SUBREG.  */
265690075Sobrien
265790075Sobrien  if (REG_P (op)
265890075Sobrien      && (! REG_FUNCTION_VALUE_P (op)
265990075Sobrien	  || ! rtx_equal_function_value_matters)
2660117395Skan      && REGNO (op) < FIRST_PSEUDO_REGISTER
2661117395Skan#ifdef CANNOT_CHANGE_MODE_CLASS
2662117395Skan      && ! (REG_CANNOT_CHANGE_MODE_P (REGNO (op), innermode, outermode)
266390075Sobrien	    && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT
2664117395Skan	    && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT)
266590075Sobrien#endif
266690075Sobrien      && ((reload_completed && !frame_pointer_needed)
266790075Sobrien	  || (REGNO (op) != FRAME_POINTER_REGNUM
266890075Sobrien#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
266990075Sobrien	      && REGNO (op) != HARD_FRAME_POINTER_REGNUM
267090075Sobrien#endif
267190075Sobrien	     ))
267290075Sobrien#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
267390075Sobrien      && REGNO (op) != ARG_POINTER_REGNUM
267490075Sobrien#endif
267590075Sobrien      && REGNO (op) != STACK_POINTER_REGNUM)
267690075Sobrien    {
267790075Sobrien      int final_regno = subreg_hard_regno (gen_rtx_SUBREG (outermode, op, byte),
267890075Sobrien					   0);
267990075Sobrien
268090075Sobrien      /* ??? We do allow it if the current REG is not valid for
268190075Sobrien	 its mode.  This is a kludge to work around how float/complex
2682117395Skan	 arguments are passed on 32-bit SPARC and should be fixed.  */
268390075Sobrien      if (HARD_REGNO_MODE_OK (final_regno, outermode)
268490075Sobrien	  || ! HARD_REGNO_MODE_OK (REGNO (op), innermode))
268590075Sobrien	{
268690075Sobrien	  rtx x = gen_rtx_REG (outermode, final_regno);
268790075Sobrien
268890075Sobrien	  /* Propagate original regno.  We don't have any way to specify
268990075Sobrien	     the offset inside orignal regno, so do so only for lowpart.
269090075Sobrien	     The information is used only by alias analysis that can not
269190075Sobrien	     grog partial register anyway.  */
269290075Sobrien
269390075Sobrien	  if (subreg_lowpart_offset (outermode, innermode) == byte)
269490075Sobrien	    ORIGINAL_REGNO (x) = ORIGINAL_REGNO (op);
269590075Sobrien	  return x;
269690075Sobrien	}
269790075Sobrien    }
269890075Sobrien
269990075Sobrien  /* If we have a SUBREG of a register that we are replacing and we are
270090075Sobrien     replacing it with a MEM, make a new MEM and try replacing the
270190075Sobrien     SUBREG with it.  Don't do this if the MEM has a mode-dependent address
270290075Sobrien     or if we would be widening it.  */
270390075Sobrien
270490075Sobrien  if (GET_CODE (op) == MEM
270590075Sobrien      && ! mode_dependent_address_p (XEXP (op, 0))
270690075Sobrien      /* Allow splitting of volatile memory references in case we don't
270790075Sobrien         have instruction to move the whole thing.  */
270890075Sobrien      && (! MEM_VOLATILE_P (op)
270990075Sobrien	  || ! have_insn_for (SET, innermode))
271090075Sobrien      && GET_MODE_SIZE (outermode) <= GET_MODE_SIZE (GET_MODE (op)))
271190075Sobrien    return adjust_address_nv (op, outermode, byte);
271290075Sobrien
271390075Sobrien  /* Handle complex values represented as CONCAT
271490075Sobrien     of real and imaginary part.  */
271590075Sobrien  if (GET_CODE (op) == CONCAT)
271690075Sobrien    {
271790075Sobrien      int is_realpart = byte < GET_MODE_UNIT_SIZE (innermode);
271890075Sobrien      rtx part = is_realpart ? XEXP (op, 0) : XEXP (op, 1);
271990075Sobrien      unsigned int final_offset;
272090075Sobrien      rtx res;
272190075Sobrien
272290075Sobrien      final_offset = byte % (GET_MODE_UNIT_SIZE (innermode));
272390075Sobrien      res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
272490075Sobrien      if (res)
272590075Sobrien	return res;
272690075Sobrien      /* We can at least simplify it by referring directly to the relevant part.  */
272790075Sobrien      return gen_rtx_SUBREG (outermode, part, final_offset);
272890075Sobrien    }
272990075Sobrien
273090075Sobrien  return NULL_RTX;
273190075Sobrien}
273290075Sobrien/* Make a SUBREG operation or equivalent if it folds.  */
273390075Sobrien
273490075Sobrienrtx
273590075Sobriensimplify_gen_subreg (outermode, op, innermode, byte)
273690075Sobrien     rtx op;
273790075Sobrien     unsigned int byte;
273890075Sobrien     enum machine_mode outermode, innermode;
273990075Sobrien{
274090075Sobrien  rtx new;
274190075Sobrien  /* Little bit of sanity checking.  */
274290075Sobrien  if (innermode == VOIDmode || outermode == VOIDmode
274390075Sobrien      || innermode == BLKmode || outermode == BLKmode)
274490075Sobrien    abort ();
274590075Sobrien
274690075Sobrien  if (GET_MODE (op) != innermode
274790075Sobrien      && GET_MODE (op) != VOIDmode)
274890075Sobrien    abort ();
274990075Sobrien
275090075Sobrien  if (byte % GET_MODE_SIZE (outermode)
275190075Sobrien      || byte >= GET_MODE_SIZE (innermode))
275290075Sobrien    abort ();
275390075Sobrien
275490075Sobrien  if (GET_CODE (op) == QUEUED)
275590075Sobrien    return NULL_RTX;
275690075Sobrien
275790075Sobrien  new = simplify_subreg (outermode, op, innermode, byte);
275890075Sobrien  if (new)
275990075Sobrien    return new;
276090075Sobrien
276190075Sobrien  if (GET_CODE (op) == SUBREG || GET_MODE (op) == VOIDmode)
276290075Sobrien    return NULL_RTX;
276390075Sobrien
276490075Sobrien  return gen_rtx_SUBREG (outermode, op, byte);
276590075Sobrien}
276690075Sobrien/* Simplify X, an rtx expression.
276790075Sobrien
276890075Sobrien   Return the simplified expression or NULL if no simplifications
276990075Sobrien   were possible.
277090075Sobrien
277190075Sobrien   This is the preferred entry point into the simplification routines;
277290075Sobrien   however, we still allow passes to call the more specific routines.
277390075Sobrien
277490075Sobrien   Right now GCC has three (yes, three) major bodies of RTL simplficiation
277590075Sobrien   code that need to be unified.
277690075Sobrien
277790075Sobrien	1. fold_rtx in cse.c.  This code uses various CSE specific
277890075Sobrien	   information to aid in RTL simplification.
277990075Sobrien
278090075Sobrien	2. simplify_rtx in combine.c.  Similar to fold_rtx, except that
278190075Sobrien	   it uses combine specific information to aid in RTL
278290075Sobrien	   simplification.
278390075Sobrien
278490075Sobrien	3. The routines in this file.
278590075Sobrien
278690075Sobrien
278790075Sobrien   Long term we want to only have one body of simplification code; to
278890075Sobrien   get to that state I recommend the following steps:
278990075Sobrien
279090075Sobrien	1. Pour over fold_rtx & simplify_rtx and move any simplifications
279190075Sobrien	   which are not pass dependent state into these routines.
279290075Sobrien
279390075Sobrien	2. As code is moved by #1, change fold_rtx & simplify_rtx to
279490075Sobrien	   use this routine whenever possible.
279590075Sobrien
279690075Sobrien	3. Allow for pass dependent state to be provided to these
279790075Sobrien	   routines and add simplifications based on the pass dependent
279890075Sobrien	   state.  Remove code from cse.c & combine.c that becomes
279990075Sobrien	   redundant/dead.
280090075Sobrien
280190075Sobrien    It will take time, but ultimately the compiler will be easier to
280290075Sobrien    maintain and improve.  It's totally silly that when we add a
280390075Sobrien    simplification that it needs to be added to 4 places (3 for RTL
280490075Sobrien    simplification and 1 for tree simplification.  */
2805117395Skan
280690075Sobrienrtx
280790075Sobriensimplify_rtx (x)
280890075Sobrien     rtx x;
280990075Sobrien{
281090075Sobrien  enum rtx_code code = GET_CODE (x);
281190075Sobrien  enum machine_mode mode = GET_MODE (x);
281290075Sobrien
281390075Sobrien  switch (GET_RTX_CLASS (code))
281490075Sobrien    {
281590075Sobrien    case '1':
281690075Sobrien      return simplify_unary_operation (code, mode,
281790075Sobrien				       XEXP (x, 0), GET_MODE (XEXP (x, 0)));
281890075Sobrien    case 'c':
281990075Sobrien      if (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
282090075Sobrien	{
282190075Sobrien	  rtx tem;
282290075Sobrien
282390075Sobrien	  tem = XEXP (x, 0);
282490075Sobrien	  XEXP (x, 0) = XEXP (x, 1);
282590075Sobrien	  XEXP (x, 1) = tem;
282690075Sobrien	  return simplify_binary_operation (code, mode,
282790075Sobrien					    XEXP (x, 0), XEXP (x, 1));
282890075Sobrien	}
282990075Sobrien
283090075Sobrien    case '2':
283190075Sobrien      return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
283290075Sobrien
283390075Sobrien    case '3':
283490075Sobrien    case 'b':
283590075Sobrien      return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)),
283690075Sobrien					 XEXP (x, 0), XEXP (x, 1),
283790075Sobrien					 XEXP (x, 2));
283890075Sobrien
283990075Sobrien    case '<':
284090075Sobrien      return simplify_relational_operation (code,
284190075Sobrien					    ((GET_MODE (XEXP (x, 0))
284290075Sobrien					      != VOIDmode)
284390075Sobrien					     ? GET_MODE (XEXP (x, 0))
284490075Sobrien					     : GET_MODE (XEXP (x, 1))),
284590075Sobrien					    XEXP (x, 0), XEXP (x, 1));
284690075Sobrien    case 'x':
284790075Sobrien      /* The only case we try to handle is a SUBREG.  */
284890075Sobrien      if (code == SUBREG)
2849117395Skan	return simplify_gen_subreg (mode, SUBREG_REG (x),
285090075Sobrien				    GET_MODE (SUBREG_REG (x)),
285190075Sobrien				    SUBREG_BYTE (x));
285290075Sobrien      return NULL;
285390075Sobrien    default:
285490075Sobrien      return NULL;
285590075Sobrien    }
285690075Sobrien}
2857