gcc/gcc/simplify-rtx.c
Jan Hubicka 261efdefd0 jump.c (jump_optimize_1): Use reversed_comparison_code instead of can_reverse_comparison_p.
* jump.c (jump_optimize_1): Use reversed_comparison_code
	instead of can_reverse_comparison_p.
	(jump_back_p): Likewise.
	(invert_exp_1): Likewise.
	(thread_jumps): Likewise.
	* simplify-rtx.c (simplify_unary_operation): Likewise.
	(simplify_ternary_operation): Likewise.
	* cse.c (find_comparison_args): Convert to use
	can_reverse_comparison_p.
	(record_jump_equiv): Likewise.

From-SVN: r38802
2001-01-08 15:16:40 +00:00

3420 lines
90 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* RTL simplification functions for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
#include <setjmp.h>
#include "rtl.h"
#include "tm_p.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "real.h"
#include "insn-config.h"
#include "recog.h"
#include "function.h"
#include "expr.h"
#include "toplev.h"
#include "output.h"
#include "ggc.h"
#include "obstack.h"
#include "hashtab.h"
#include "cselib.h"
/* Simplification and canonicalization of RTL. */
/* Nonzero if X has the form (PLUS frame-pointer integer). We check for
virtual regs here because the simplify_*_operation routines are called
by integrate.c, which is called before virtual register instantiation.
?!? FIXED_BASE_PLUS_P and NONZERO_BASE_PLUS_P need to move into
a header file so that their definitions can be shared with the
simplification routines in simplify-rtx.c. Until then, do not
change these macros without also changing the copy in simplify-rtx.c. */
#define FIXED_BASE_PLUS_P(X) \
((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \
|| ((X) == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])\
|| (X) == virtual_stack_vars_rtx \
|| (X) == virtual_incoming_args_rtx \
|| (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (XEXP (X, 0) == frame_pointer_rtx \
|| XEXP (X, 0) == hard_frame_pointer_rtx \
|| ((X) == arg_pointer_rtx \
&& fixed_regs[ARG_POINTER_REGNUM]) \
|| XEXP (X, 0) == virtual_stack_vars_rtx \
|| XEXP (X, 0) == virtual_incoming_args_rtx)) \
|| GET_CODE (X) == ADDRESSOF)
/* Similar, but also allows reference to the stack pointer.
This used to include FIXED_BASE_PLUS_P, however, we can't assume that
arg_pointer_rtx by itself is nonzero, because on at least one machine,
the i960, the arg pointer is zero when it is unused. */
#define NONZERO_BASE_PLUS_P(X) \
((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \
|| (X) == virtual_stack_vars_rtx \
|| (X) == virtual_incoming_args_rtx \
|| (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (XEXP (X, 0) == frame_pointer_rtx \
|| XEXP (X, 0) == hard_frame_pointer_rtx \
|| ((X) == arg_pointer_rtx \
&& fixed_regs[ARG_POINTER_REGNUM]) \
|| XEXP (X, 0) == virtual_stack_vars_rtx \
|| XEXP (X, 0) == virtual_incoming_args_rtx)) \
|| (X) == stack_pointer_rtx \
|| (X) == virtual_stack_dynamic_rtx \
|| (X) == virtual_outgoing_args_rtx \
|| (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (XEXP (X, 0) == stack_pointer_rtx \
|| XEXP (X, 0) == virtual_stack_dynamic_rtx \
|| XEXP (X, 0) == virtual_outgoing_args_rtx)) \
|| GET_CODE (X) == ADDRESSOF)
/* Much code operates on (low, high) pairs; the low value is an
unsigned wide int, the high value a signed wide int. We
occasionally need to sign extend from low to high as if low were a
signed wide int. */
#define HWI_SIGN_EXTEND(low) \
((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
static rtx simplify_plus_minus PARAMS ((enum rtx_code,
enum machine_mode, rtx, rtx));
static void check_fold_consts PARAMS ((PTR));
static int entry_and_rtx_equal_p PARAMS ((const void *, const void *));
static unsigned int get_value_hash PARAMS ((const void *));
static struct elt_list *new_elt_list PARAMS ((struct elt_list *,
cselib_val *));
static struct elt_loc_list *new_elt_loc_list PARAMS ((struct elt_loc_list *,
rtx));
static void unchain_one_value PARAMS ((cselib_val *));
static void unchain_one_elt_list PARAMS ((struct elt_list **));
static void unchain_one_elt_loc_list PARAMS ((struct elt_loc_list **));
static void clear_table PARAMS ((int));
static int discard_useless_locs PARAMS ((void **, void *));
static int discard_useless_values PARAMS ((void **, void *));
static void remove_useless_values PARAMS ((void));
static rtx wrap_constant PARAMS ((enum machine_mode, rtx));
static unsigned int hash_rtx PARAMS ((rtx, enum machine_mode, int));
static cselib_val *new_cselib_val PARAMS ((unsigned int,
enum machine_mode));
static void add_mem_for_addr PARAMS ((cselib_val *, cselib_val *,
rtx));
static cselib_val *cselib_lookup_mem PARAMS ((rtx, int));
static rtx cselib_subst_to_values PARAMS ((rtx));
static void cselib_invalidate_regno PARAMS ((unsigned int,
enum machine_mode));
static int cselib_mem_conflict_p PARAMS ((rtx, rtx));
static int cselib_invalidate_mem_1 PARAMS ((void **, void *));
static void cselib_invalidate_mem PARAMS ((rtx));
static void cselib_invalidate_rtx PARAMS ((rtx, rtx, void *));
static void cselib_record_set PARAMS ((rtx, cselib_val *,
cselib_val *));
static void cselib_record_sets PARAMS ((rtx));
/* There are three ways in which cselib can look up an rtx:
- for a REG, the reg_values table (which is indexed by regno) is used
- for a MEM, we recursively look up its address and then follow the
addr_list of that value
- for everything else, we compute a hash value and go through the hash
table. Since different rtx's can still have the same hash value,
this involves walking the table entries for a given value and comparing
the locations of the entries with the rtx we are looking up. */
/* A table that enables us to look up elts by their value. */
static htab_t hash_table;
/* This is a global so we don't have to pass this through every function.
It is used in new_elt_loc_list to set SETTING_INSN. */
static rtx cselib_current_insn;
/* Every new unknown value gets a unique number. */
static unsigned int next_unknown_value;
/* The number of registers we had when the varrays were last resized. */
static unsigned int cselib_nregs;
/* Count values without known locations. Whenever this grows too big, we
remove these useless values from the table. */
static int n_useless_values;
/* Number of useless values before we remove them from the hash table. */
#define MAX_USELESS_VALUES 32
/* This table maps from register number to values. It does not contain
pointers to cselib_val structures, but rather elt_lists. The purpose is
to be able to refer to the same register in different modes. */
static varray_type reg_values;
#define REG_VALUES(I) VARRAY_ELT_LIST (reg_values, (I))
/* Here the set of indices I with REG_VALUES(I) != 0 is saved. This is used
in clear_table() for fast emptying. */
static varray_type used_regs;
/* We pass this to cselib_invalidate_mem to invalidate all of
memory for a non-const call instruction. */
static rtx callmem;
/* Memory for our structures is allocated from this obstack. */
static struct obstack cselib_obstack;
/* Used to quickly free all memory. */
static char *cselib_startobj;
/* Caches for unused structures. */
static cselib_val *empty_vals;
static struct elt_list *empty_elt_lists;
static struct elt_loc_list *empty_elt_loc_lists;
/* Set by discard_useless_locs if it deleted the last location of any
value. */
static int values_became_useless;
/* Make a binary operation by properly ordering the operands and
seeing if the expression folds. */
rtx
simplify_gen_binary (code, mode, op0, op1)
enum rtx_code code;
enum machine_mode mode;
rtx op0, op1;
{
rtx tem;
/* Put complex operands first and constants second if commutative. */
if (GET_RTX_CLASS (code) == 'c'
&& ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
|| (GET_RTX_CLASS (GET_CODE (op0)) == 'o'
&& GET_RTX_CLASS (GET_CODE (op1)) != 'o')
|| (GET_CODE (op0) == SUBREG
&& GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o'
&& GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
tem = op0, op0 = op1, op1 = tem;
/* If this simplifies, do it. */
tem = simplify_binary_operation (code, mode, op0, op1);
if (tem)
return tem;
/* Handle addition and subtraction of CONST_INT specially. Otherwise,
just form the operation. */
if (code == PLUS && GET_CODE (op1) == CONST_INT
&& GET_MODE (op0) != VOIDmode)
return plus_constant (op0, INTVAL (op1));
else if (code == MINUS && GET_CODE (op1) == CONST_INT
&& GET_MODE (op0) != VOIDmode)
return plus_constant (op0, - INTVAL (op1));
else
return gen_rtx_fmt_ee (code, mode, op0, op1);
}
/* Try to simplify a unary operation CODE whose output mode is to be
MODE with input operand OP whose mode was originally OP_MODE.
Return zero if no simplification can be made. */
rtx
simplify_unary_operation (code, mode, op, op_mode)
enum rtx_code code;
enum machine_mode mode;
rtx op;
enum machine_mode op_mode;
{
unsigned int width = GET_MODE_BITSIZE (mode);
/* The order of these tests is critical so that, for example, we don't
check the wrong mode (input vs. output) for a conversion operation,
such as FIX. At some point, this should be simplified. */
#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
if (code == FLOAT && GET_MODE (op) == VOIDmode
&& (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
{
HOST_WIDE_INT hv, lv;
REAL_VALUE_TYPE d;
if (GET_CODE (op) == CONST_INT)
lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
else
lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
#ifdef REAL_ARITHMETIC
REAL_VALUE_FROM_INT (d, lv, hv, mode);
#else
if (hv < 0)
{
d = (double) (~ hv);
d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
* (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
d += (double) (unsigned HOST_WIDE_INT) (~ lv);
d = (- d - 1.0);
}
else
{
d = (double) hv;
d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
* (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
d += (double) (unsigned HOST_WIDE_INT) lv;
}
#endif /* REAL_ARITHMETIC */
d = real_value_truncate (mode, d);
return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
}
else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode
&& (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
{
HOST_WIDE_INT hv, lv;
REAL_VALUE_TYPE d;
if (GET_CODE (op) == CONST_INT)
lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
else
lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
if (op_mode == VOIDmode)
{
/* We don't know how to interpret negative-looking numbers in
this case, so don't try to fold those. */
if (hv < 0)
return 0;
}
else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
;
else
hv = 0, lv &= GET_MODE_MASK (op_mode);
#ifdef REAL_ARITHMETIC
REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
#else
d = (double) (unsigned HOST_WIDE_INT) hv;
d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
* (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
d += (double) (unsigned HOST_WIDE_INT) lv;
#endif /* REAL_ARITHMETIC */
d = real_value_truncate (mode, d);
return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
}
#endif
if (GET_CODE (op) == CONST_INT
&& width <= HOST_BITS_PER_WIDE_INT && width > 0)
{
register HOST_WIDE_INT arg0 = INTVAL (op);
register HOST_WIDE_INT val;
switch (code)
{
case NOT:
val = ~ arg0;
break;
case NEG:
val = - arg0;
break;
case ABS:
val = (arg0 >= 0 ? arg0 : - arg0);
break;
case FFS:
/* Don't use ffs here. Instead, get low order bit and then its
number. If arg0 is zero, this will return 0, as desired. */
arg0 &= GET_MODE_MASK (mode);
val = exact_log2 (arg0 & (- arg0)) + 1;
break;
case TRUNCATE:
val = arg0;
break;
case ZERO_EXTEND:
if (op_mode == VOIDmode)
op_mode = mode;
if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
{
/* If we were really extending the mode,
we would have to distinguish between zero-extension
and sign-extension. */
if (width != GET_MODE_BITSIZE (op_mode))
abort ();
val = arg0;
}
else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
else
return 0;
break;
case SIGN_EXTEND:
if (op_mode == VOIDmode)
op_mode = mode;
if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
{
/* If we were really extending the mode,
we would have to distinguish between zero-extension
and sign-extension. */
if (width != GET_MODE_BITSIZE (op_mode))
abort ();
val = arg0;
}
else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
{
val
= arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
if (val
& ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1)))
val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
}
else
return 0;
break;
case SQRT:
case FLOAT_EXTEND:
case FLOAT_TRUNCATE:
return 0;
default:
abort ();
}
val = trunc_int_for_mode (val, mode);
return GEN_INT (val);
}
/* We can do some operations on integer CONST_DOUBLEs. Also allow
for a DImode operation on a CONST_INT. */
else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
&& (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
{
unsigned HOST_WIDE_INT l1, lv;
HOST_WIDE_INT h1, hv;
if (GET_CODE (op) == CONST_DOUBLE)
l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
else
l1 = INTVAL (op), h1 = HWI_SIGN_EXTEND (l1);
switch (code)
{
case NOT:
lv = ~ l1;
hv = ~ h1;
break;
case NEG:
neg_double (l1, h1, &lv, &hv);
break;
case ABS:
if (h1 < 0)
neg_double (l1, h1, &lv, &hv);
else
lv = l1, hv = h1;
break;
case FFS:
hv = 0;
if (l1 == 0)
lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & (-h1)) + 1;
else
lv = exact_log2 (l1 & (-l1)) + 1;
break;
case TRUNCATE:
/* This is just a change-of-mode, so do nothing. */
lv = l1, hv = h1;
break;
case ZERO_EXTEND:
if (op_mode == VOIDmode
|| GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
return 0;
hv = 0;
lv = l1 & GET_MODE_MASK (op_mode);
break;
case SIGN_EXTEND:
if (op_mode == VOIDmode
|| GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
return 0;
else
{
lv = l1 & GET_MODE_MASK (op_mode);
if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
&& (lv & ((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
hv = HWI_SIGN_EXTEND (lv);
}
break;
case SQRT:
return 0;
default:
return 0;
}
return immed_double_const (lv, hv, mode);
}
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
else if (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE_CLASS (mode) == MODE_FLOAT)
{
REAL_VALUE_TYPE d;
jmp_buf handler;
rtx x;
if (setjmp (handler))
/* There used to be a warning here, but that is inadvisable.
People may want to cause traps, and the natural way
to do it should not get a warning. */
return 0;
set_float_handler (handler);
REAL_VALUE_FROM_CONST_DOUBLE (d, op);
switch (code)
{
case NEG:
d = REAL_VALUE_NEGATE (d);
break;
case ABS:
if (REAL_VALUE_NEGATIVE (d))
d = REAL_VALUE_NEGATE (d);
break;
case FLOAT_TRUNCATE:
d = real_value_truncate (mode, d);
break;
case FLOAT_EXTEND:
/* All this does is change the mode. */
break;
case FIX:
d = REAL_VALUE_RNDZINT (d);
break;
case UNSIGNED_FIX:
d = REAL_VALUE_UNSIGNED_RNDZINT (d);
break;
case SQRT:
return 0;
default:
abort ();
}
x = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
set_float_handler (NULL_PTR);
return x;
}
else if (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
&& GET_MODE_CLASS (mode) == MODE_INT
&& width <= HOST_BITS_PER_WIDE_INT && width > 0)
{
REAL_VALUE_TYPE d;
jmp_buf handler;
HOST_WIDE_INT val;
if (setjmp (handler))
return 0;
set_float_handler (handler);
REAL_VALUE_FROM_CONST_DOUBLE (d, op);
switch (code)
{
case FIX:
val = REAL_VALUE_FIX (d);
break;
case UNSIGNED_FIX:
val = REAL_VALUE_UNSIGNED_FIX (d);
break;
default:
abort ();
}
set_float_handler (NULL_PTR);
val = trunc_int_for_mode (val, mode);
return GEN_INT (val);
}
#endif
/* This was formerly used only for non-IEEE float.
eggert@twinsun.com says it is safe for IEEE also. */
else
{
enum rtx_code reversed;
/* There are some simplifications we can do even if the operands
aren't constant. */
switch (code)
{
case NOT:
/* (not (not X)) == X. */
if (GET_CODE (op) == NOT)
return XEXP (op, 0);
/* (not (eq X Y)) == (ne X Y), etc. */
if (mode == BImode && GET_RTX_CLASS (GET_CODE (op)) == '<'
&& ((reversed = reversed_comparison_code (op, NULL_RTX))
!= UNKNOWN))
return gen_rtx_fmt_ee (reversed,
op_mode, XEXP (op, 0), XEXP (op, 1));
break;
case NEG:
/* (neg (neg X)) == X. */
if (GET_CODE (op) == NEG)
return XEXP (op, 0);
break;
case SIGN_EXTEND:
/* (sign_extend (truncate (minus (label_ref L1) (label_ref L2))))
becomes just the MINUS if its mode is MODE. This allows
folding switch statements on machines using casesi (such as
the Vax). */
if (GET_CODE (op) == TRUNCATE
&& GET_MODE (XEXP (op, 0)) == mode
&& GET_CODE (XEXP (op, 0)) == MINUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
return XEXP (op, 0);
#ifdef POINTERS_EXTEND_UNSIGNED
if (! POINTERS_EXTEND_UNSIGNED
&& mode == Pmode && GET_MODE (op) == ptr_mode
&& CONSTANT_P (op))
return convert_memory_address (Pmode, op);
#endif
break;
#ifdef POINTERS_EXTEND_UNSIGNED
case ZERO_EXTEND:
if (POINTERS_EXTEND_UNSIGNED
&& mode == Pmode && GET_MODE (op) == ptr_mode
&& CONSTANT_P (op))
return convert_memory_address (Pmode, op);
break;
#endif
default:
break;
}
return 0;
}
}
/* Simplify a binary operation CODE with result mode MODE, operating on OP0
and OP1. Return 0 if no simplification is possible.
Don't use this for relational operations such as EQ or LT.
Use simplify_relational_operation instead. */
rtx
simplify_binary_operation (code, mode, op0, op1)
enum rtx_code code;
enum machine_mode mode;
rtx op0, op1;
{
register HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
HOST_WIDE_INT val;
unsigned int width = GET_MODE_BITSIZE (mode);
rtx tem;
/* Relational operations don't work here. We must know the mode
of the operands in order to do the comparison correctly.
Assuming a full word can give incorrect results.
Consider comparing 128 with -128 in QImode. */
if (GET_RTX_CLASS (code) == '<')
abort ();
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
if (GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
&& mode == GET_MODE (op0) && mode == GET_MODE (op1))
{
REAL_VALUE_TYPE f0, f1, value;
jmp_buf handler;
if (setjmp (handler))
return 0;
set_float_handler (handler);
REAL_VALUE_FROM_CONST_DOUBLE (f0, op0);
REAL_VALUE_FROM_CONST_DOUBLE (f1, op1);
f0 = real_value_truncate (mode, f0);
f1 = real_value_truncate (mode, f1);
#ifdef REAL_ARITHMETIC
#ifndef REAL_INFINITY
if (code == DIV && REAL_VALUES_EQUAL (f1, dconst0))
return 0;
#endif
REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
#else
switch (code)
{
case PLUS:
value = f0 + f1;
break;
case MINUS:
value = f0 - f1;
break;
case MULT:
value = f0 * f1;
break;
case DIV:
#ifndef REAL_INFINITY
if (f1 == 0)
return 0;
#endif
value = f0 / f1;
break;
case SMIN:
value = MIN (f0, f1);
break;
case SMAX:
value = MAX (f0, f1);
break;
default:
abort ();
}
#endif
value = real_value_truncate (mode, value);
set_float_handler (NULL_PTR);
return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
}
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
/* We can fold some multi-word operations. */
if (GET_MODE_CLASS (mode) == MODE_INT
&& width == HOST_BITS_PER_WIDE_INT * 2
&& (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
&& (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
{
unsigned HOST_WIDE_INT l1, l2, lv;
HOST_WIDE_INT h1, h2, hv;
if (GET_CODE (op0) == CONST_DOUBLE)
l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
else
l1 = INTVAL (op0), h1 = HWI_SIGN_EXTEND (l1);
if (GET_CODE (op1) == CONST_DOUBLE)
l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1);
else
l2 = INTVAL (op1), h2 = HWI_SIGN_EXTEND (l2);
switch (code)
{
case MINUS:
/* A - B == A + (-B). */
neg_double (l2, h2, &lv, &hv);
l2 = lv, h2 = hv;
/* .. fall through ... */
case PLUS:
add_double (l1, h1, l2, h2, &lv, &hv);
break;
case MULT:
mul_double (l1, h1, l2, h2, &lv, &hv);
break;
case DIV: case MOD: case UDIV: case UMOD:
/* We'd need to include tree.h to do this and it doesn't seem worth
it. */
return 0;
case AND:
lv = l1 & l2, hv = h1 & h2;
break;
case IOR:
lv = l1 | l2, hv = h1 | h2;
break;
case XOR:
lv = l1 ^ l2, hv = h1 ^ h2;
break;
case SMIN:
if (h1 < h2
|| (h1 == h2
&& ((unsigned HOST_WIDE_INT) l1
< (unsigned HOST_WIDE_INT) l2)))
lv = l1, hv = h1;
else
lv = l2, hv = h2;
break;
case SMAX:
if (h1 > h2
|| (h1 == h2
&& ((unsigned HOST_WIDE_INT) l1
> (unsigned HOST_WIDE_INT) l2)))
lv = l1, hv = h1;
else
lv = l2, hv = h2;
break;
case UMIN:
if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2
|| (h1 == h2
&& ((unsigned HOST_WIDE_INT) l1
< (unsigned HOST_WIDE_INT) l2)))
lv = l1, hv = h1;
else
lv = l2, hv = h2;
break;
case UMAX:
if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2
|| (h1 == h2
&& ((unsigned HOST_WIDE_INT) l1
> (unsigned HOST_WIDE_INT) l2)))
lv = l1, hv = h1;
else
lv = l2, hv = h2;
break;
case LSHIFTRT: case ASHIFTRT:
case ASHIFT:
case ROTATE: case ROTATERT:
#ifdef SHIFT_COUNT_TRUNCATED
if (SHIFT_COUNT_TRUNCATED)
l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
#endif
if (h2 != 0 || l2 >= GET_MODE_BITSIZE (mode))
return 0;
if (code == LSHIFTRT || code == ASHIFTRT)
rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
code == ASHIFTRT);
else if (code == ASHIFT)
lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
else if (code == ROTATE)
lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
else /* code == ROTATERT */
rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
break;
default:
return 0;
}
return immed_double_const (lv, hv, mode);
}
if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
|| width > HOST_BITS_PER_WIDE_INT || width == 0)
{
/* Even if we can't compute a constant result,
there are some cases worth simplifying. */
switch (code)
{
case PLUS:
/* In IEEE floating point, x+0 is not the same as x. Similarly
for the other optimizations below. */
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
&& FLOAT_MODE_P (mode) && ! flag_fast_math)
break;
if (op1 == CONST0_RTX (mode))
return op0;
/* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */
if (GET_CODE (op0) == NEG)
return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
else if (GET_CODE (op1) == NEG)
return simplify_gen_binary (MINUS, mode, op0, XEXP (op1, 0));
/* Handle both-operands-constant cases. We can only add
CONST_INTs to constants since the sum of relocatable symbols
can't be handled by most assemblers. Don't add CONST_INT
to CONST_INT since overflow won't be computed properly if wider
than HOST_BITS_PER_WIDE_INT. */
if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode
&& GET_CODE (op1) == CONST_INT)
return plus_constant (op0, INTVAL (op1));
else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode
&& GET_CODE (op0) == CONST_INT)
return plus_constant (op1, INTVAL (op0));
/* See if this is something like X * C - X or vice versa or
if the multiplication is written as a shift. If so, we can
distribute and make a new multiply, shift, or maybe just
have X (if C is 2 in the example above). But don't make
real multiply if we didn't have one before. */
if (! FLOAT_MODE_P (mode))
{
HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
rtx lhs = op0, rhs = op1;
int had_mult = 0;
if (GET_CODE (lhs) == NEG)
coeff0 = -1, lhs = XEXP (lhs, 0);
else if (GET_CODE (lhs) == MULT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT)
{
coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
had_mult = 1;
}
else if (GET_CODE (lhs) == ASHIFT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT
&& INTVAL (XEXP (lhs, 1)) >= 0
&& INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
{
coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
lhs = XEXP (lhs, 0);
}
if (GET_CODE (rhs) == NEG)
coeff1 = -1, rhs = XEXP (rhs, 0);
else if (GET_CODE (rhs) == MULT
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT)
{
coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
had_mult = 1;
}
else if (GET_CODE (rhs) == ASHIFT
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT
&& INTVAL (XEXP (rhs, 1)) >= 0
&& INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
{
coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
rhs = XEXP (rhs, 0);
}
if (rtx_equal_p (lhs, rhs))
{
tem = simplify_gen_binary (MULT, mode, lhs,
GEN_INT (coeff0 + coeff1));
return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
}
}
/* If one of the operands is a PLUS or a MINUS, see if we can
simplify this by the associative law.
Don't use the associative law for floating point.
The inaccuracy makes it nonassociative,
and subtle programs can break if operations are associated. */
if (INTEGRAL_MODE_P (mode)
&& (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
|| GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS)
&& (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
return tem;
break;
case COMPARE:
#ifdef HAVE_cc0
/* Convert (compare FOO (const_int 0)) to FOO unless we aren't
using cc0, in which case we want to leave it as a COMPARE
so we can distinguish it from a register-register-copy.
In IEEE floating point, x-0 is not the same as x. */
if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| ! FLOAT_MODE_P (mode) || flag_fast_math)
&& op1 == CONST0_RTX (mode))
return op0;
#endif
/* Convert (compare (gt (flags) 0) (lt (flags) 0)) to (flags). */
if (((GET_CODE (op0) == GT && GET_CODE (op1) == LT)
|| (GET_CODE (op0) == GTU && GET_CODE (op1) == LTU))
&& XEXP (op0, 1) == const0_rtx && XEXP (op1, 1) == const0_rtx)
{
rtx xop00 = XEXP (op0, 0);
rtx xop10 = XEXP (op1, 0);
#ifdef HAVE_cc0
if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
#else
if (GET_CODE (xop00) == REG && GET_CODE (xop10) == REG
&& GET_MODE (xop00) == GET_MODE (xop10)
&& REGNO (xop00) == REGNO (xop10)
&& GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
&& GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
#endif
return xop00;
}
break;
case MINUS:
/* None of these optimizations can be done for IEEE
floating point. */
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
&& FLOAT_MODE_P (mode) && ! flag_fast_math)
break;
/* We can't assume x-x is 0 even with non-IEEE floating point,
but since it is zero except in very strange circumstances, we
will treat it as zero with -ffast-math. */
if (rtx_equal_p (op0, op1)
&& ! side_effects_p (op0)
&& (! FLOAT_MODE_P (mode) || flag_fast_math))
return CONST0_RTX (mode);
/* Change subtraction from zero into negation. */
if (op0 == CONST0_RTX (mode))
return gen_rtx_NEG (mode, op1);
/* (-1 - a) is ~a. */
if (op0 == constm1_rtx)
return gen_rtx_NOT (mode, op1);
/* Subtracting 0 has no effect. */
if (op1 == CONST0_RTX (mode))
return op0;
/* See if this is something like X * C - X or vice versa or
if the multiplication is written as a shift. If so, we can
distribute and make a new multiply, shift, or maybe just
have X (if C is 2 in the example above). But don't make
real multiply if we didn't have one before. */
if (! FLOAT_MODE_P (mode))
{
HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
rtx lhs = op0, rhs = op1;
int had_mult = 0;
if (GET_CODE (lhs) == NEG)
coeff0 = -1, lhs = XEXP (lhs, 0);
else if (GET_CODE (lhs) == MULT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT)
{
coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
had_mult = 1;
}
else if (GET_CODE (lhs) == ASHIFT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT
&& INTVAL (XEXP (lhs, 1)) >= 0
&& INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
{
coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
lhs = XEXP (lhs, 0);
}
if (GET_CODE (rhs) == NEG)
coeff1 = - 1, rhs = XEXP (rhs, 0);
else if (GET_CODE (rhs) == MULT
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT)
{
coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
had_mult = 1;
}
else if (GET_CODE (rhs) == ASHIFT
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT
&& INTVAL (XEXP (rhs, 1)) >= 0
&& INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
{
coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
rhs = XEXP (rhs, 0);
}
if (rtx_equal_p (lhs, rhs))
{
tem = simplify_gen_binary (MULT, mode, lhs,
GEN_INT (coeff0 - coeff1));
return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
}
}
/* (a - (-b)) -> (a + b). */
if (GET_CODE (op1) == NEG)
return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
/* If one of the operands is a PLUS or a MINUS, see if we can
simplify this by the associative law.
Don't use the associative law for floating point.
The inaccuracy makes it nonassociative,
and subtle programs can break if operations are associated. */
if (INTEGRAL_MODE_P (mode)
&& (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
|| GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS)
&& (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
return tem;
/* Don't let a relocatable value get a negative coeff. */
if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode)
return plus_constant (op0, - INTVAL (op1));
/* (x - (x & y)) -> (x & ~y) */
if (GET_CODE (op1) == AND)
{
if (rtx_equal_p (op0, XEXP (op1, 0)))
return simplify_gen_binary (AND, mode, op0,
gen_rtx_NOT (mode, XEXP (op1, 1)));
if (rtx_equal_p (op0, XEXP (op1, 1)))
return simplify_gen_binary (AND, mode, op0,
gen_rtx_NOT (mode, XEXP (op1, 0)));
}
break;
case MULT:
if (op1 == constm1_rtx)
{
tem = simplify_unary_operation (NEG, mode, op0, mode);
return tem ? tem : gen_rtx_NEG (mode, op0);
}
/* In IEEE floating point, x*0 is not always 0. */
if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| ! FLOAT_MODE_P (mode) || flag_fast_math)
&& op1 == CONST0_RTX (mode)
&& ! side_effects_p (op0))
return op1;
/* In IEEE floating point, x*1 is not equivalent to x for nans.
However, ANSI says we can drop signals,
so we can do this anyway. */
if (op1 == CONST1_RTX (mode))
return op0;
/* Convert multiply by constant power of two into shift unless
we are still generating RTL. This test is a kludge. */
if (GET_CODE (op1) == CONST_INT
&& (val = exact_log2 (INTVAL (op1))) >= 0
/* If the mode is larger than the host word size, and the
uppermost bit is set, then this isn't a power of two due
to implicit sign extension. */
&& (width <= HOST_BITS_PER_WIDE_INT
|| val != HOST_BITS_PER_WIDE_INT - 1)
&& ! rtx_equal_function_value_matters)
return gen_rtx_ASHIFT (mode, op0, GEN_INT (val));
if (GET_CODE (op1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT)
{
REAL_VALUE_TYPE d;
jmp_buf handler;
int op1is2, op1ism1;
if (setjmp (handler))
return 0;
set_float_handler (handler);
REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
op1is2 = REAL_VALUES_EQUAL (d, dconst2);
op1ism1 = REAL_VALUES_EQUAL (d, dconstm1);
set_float_handler (NULL_PTR);
/* x*2 is x+x and x*(-1) is -x */
if (op1is2 && GET_MODE (op0) == mode)
return gen_rtx_PLUS (mode, op0, copy_rtx (op0));
else if (op1ism1 && GET_MODE (op0) == mode)
return gen_rtx_NEG (mode, op0);
}
break;
case IOR:
if (op1 == const0_rtx)
return op0;
if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
return op1;
if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
return op0;
/* A | (~A) -> -1 */
if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
|| (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
&& ! side_effects_p (op0)
&& GET_MODE_CLASS (mode) != MODE_CC)
return constm1_rtx;
break;
case XOR:
if (op1 == const0_rtx)
return op0;
if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
return gen_rtx_NOT (mode, op0);
if (op0 == op1 && ! side_effects_p (op0)
&& GET_MODE_CLASS (mode) != MODE_CC)
return const0_rtx;
break;
case AND:
if (op1 == const0_rtx && ! side_effects_p (op0))
return const0_rtx;
if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
return op0;
if (op0 == op1 && ! side_effects_p (op0)
&& GET_MODE_CLASS (mode) != MODE_CC)
return op0;
/* A & (~A) -> 0 */
if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
|| (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
&& ! side_effects_p (op0)
&& GET_MODE_CLASS (mode) != MODE_CC)
return const0_rtx;
break;
case UDIV:
/* Convert divide by power of two into shift (divide by 1 handled
below). */
if (GET_CODE (op1) == CONST_INT
&& (arg1 = exact_log2 (INTVAL (op1))) > 0)
return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1));
/* ... fall through ... */
case DIV:
if (op1 == CONST1_RTX (mode))
return op0;
/* In IEEE floating point, 0/x is not always 0. */
if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| ! FLOAT_MODE_P (mode) || flag_fast_math)
&& op0 == CONST0_RTX (mode)
&& ! side_effects_p (op1))
return op0;
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
/* Change division by a constant into multiplication. Only do
this with -ffast-math until an expert says it is safe in
general. */
else if (GET_CODE (op1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT
&& op1 != CONST0_RTX (mode)
&& flag_fast_math)
{
REAL_VALUE_TYPE d;
REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
if (! REAL_VALUES_EQUAL (d, dconst0))
{
#if defined (REAL_ARITHMETIC)
REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
return gen_rtx_MULT (mode, op0,
CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
#else
return
gen_rtx_MULT (mode, op0,
CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
#endif
}
}
#endif
break;
case UMOD:
/* Handle modulus by power of two (mod with 1 handled below). */
if (GET_CODE (op1) == CONST_INT
&& exact_log2 (INTVAL (op1)) > 0)
return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1));
/* ... fall through ... */
case MOD:
if ((op0 == const0_rtx || op1 == const1_rtx)
&& ! side_effects_p (op0) && ! side_effects_p (op1))
return const0_rtx;
break;
case ROTATERT:
case ROTATE:
/* Rotating ~0 always results in ~0. */
if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op0) == GET_MODE_MASK (mode)
&& ! side_effects_p (op1))
return op0;
/* ... fall through ... */
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
if (op1 == const0_rtx)
return op0;
if (op0 == const0_rtx && ! side_effects_p (op1))
return op0;
break;
case SMIN:
if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
&& INTVAL (op1) == (HOST_WIDE_INT) 1 << (width -1)
&& ! side_effects_p (op0))
return op1;
else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
return op0;
break;
case SMAX:
if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
&& ((unsigned HOST_WIDE_INT) INTVAL (op1)
== (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
&& ! side_effects_p (op0))
return op1;
else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
return op0;
break;
case UMIN:
if (op1 == const0_rtx && ! side_effects_p (op0))
return op1;
else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
return op0;
break;
case UMAX:
if (op1 == constm1_rtx && ! side_effects_p (op0))
return op1;
else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
return op0;
break;
default:
abort ();
}
return 0;
}
/* Get the integer argument values in two forms:
zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S. */
arg0 = INTVAL (op0);
arg1 = INTVAL (op1);
if (width < HOST_BITS_PER_WIDE_INT)
{
arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
arg0s = arg0;
if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
arg0s |= ((HOST_WIDE_INT) (-1) << width);
arg1s = arg1;
if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
arg1s |= ((HOST_WIDE_INT) (-1) << width);
}
else
{
arg0s = arg0;
arg1s = arg1;
}
/* Compute the value of the arithmetic. */
switch (code)
{
case PLUS:
val = arg0s + arg1s;
break;
case MINUS:
val = arg0s - arg1s;
break;
case MULT:
val = arg0s * arg1s;
break;
case DIV:
if (arg1s == 0)
return 0;
val = arg0s / arg1s;
break;
case MOD:
if (arg1s == 0)
return 0;
val = arg0s % arg1s;
break;
case UDIV:
if (arg1 == 0)
return 0;
val = (unsigned HOST_WIDE_INT) arg0 / arg1;
break;
case UMOD:
if (arg1 == 0)
return 0;
val = (unsigned HOST_WIDE_INT) arg0 % arg1;
break;
case AND:
val = arg0 & arg1;
break;
case IOR:
val = arg0 | arg1;
break;
case XOR:
val = arg0 ^ arg1;
break;
case LSHIFTRT:
/* If shift count is undefined, don't fold it; let the machine do
what it wants. But truncate it if the machine will do that. */
if (arg1 < 0)
return 0;
#ifdef SHIFT_COUNT_TRUNCATED
if (SHIFT_COUNT_TRUNCATED)
arg1 %= width;
#endif
val = ((unsigned HOST_WIDE_INT) arg0) >> arg1;
break;
case ASHIFT:
if (arg1 < 0)
return 0;
#ifdef SHIFT_COUNT_TRUNCATED
if (SHIFT_COUNT_TRUNCATED)
arg1 %= width;
#endif
val = ((unsigned HOST_WIDE_INT) arg0) << arg1;
break;
case ASHIFTRT:
if (arg1 < 0)
return 0;
#ifdef SHIFT_COUNT_TRUNCATED
if (SHIFT_COUNT_TRUNCATED)
arg1 %= width;
#endif
val = arg0s >> arg1;
/* Bootstrap compiler may not have sign extended the right shift.
Manually extend the sign to insure bootstrap cc matches gcc. */
if (arg0s < 0 && arg1 > 0)
val |= ((HOST_WIDE_INT) -1) << (HOST_BITS_PER_WIDE_INT - arg1);
break;
case ROTATERT:
if (arg1 < 0)
return 0;
arg1 %= width;
val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
| (((unsigned HOST_WIDE_INT) arg0) >> arg1));
break;
case ROTATE:
if (arg1 < 0)
return 0;
arg1 %= width;
val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
| (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
break;
case COMPARE:
/* Do nothing here. */
return 0;
case SMIN:
val = arg0s <= arg1s ? arg0s : arg1s;
break;
case UMIN:
val = ((unsigned HOST_WIDE_INT) arg0
<= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
break;
case SMAX:
val = arg0s > arg1s ? arg0s : arg1s;
break;
case UMAX:
val = ((unsigned HOST_WIDE_INT) arg0
> (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
break;
default:
abort ();
}
val = trunc_int_for_mode (val, mode);
return GEN_INT (val);
}
/* Simplify a PLUS or MINUS, at least one of whose operands may be another
PLUS or MINUS.
Rather than test for specific case, we do this by a brute-force method
and do all possible simplifications until no more changes occur. Then
we rebuild the operation. */
static rtx
simplify_plus_minus (code, mode, op0, op1)
enum rtx_code code;
enum machine_mode mode;
rtx op0, op1;
{
rtx ops[8];
int negs[8];
rtx result, tem;
int n_ops = 2, input_ops = 2, input_consts = 0, n_consts = 0;
int first = 1, negate = 0, changed;
int i, j;
memset ((char *) ops, 0, sizeof ops);
/* Set up the two operands and then expand them until nothing has been
changed. If we run out of room in our array, give up; this should
almost never happen. */
ops[0] = op0, ops[1] = op1, negs[0] = 0, negs[1] = (code == MINUS);
changed = 1;
while (changed)
{
changed = 0;
for (i = 0; i < n_ops; i++)
switch (GET_CODE (ops[i]))
{
case PLUS:
case MINUS:
if (n_ops == 7)
return 0;
ops[n_ops] = XEXP (ops[i], 1);
negs[n_ops++] = GET_CODE (ops[i]) == MINUS ? !negs[i] : negs[i];
ops[i] = XEXP (ops[i], 0);
input_ops++;
changed = 1;
break;
case NEG:
ops[i] = XEXP (ops[i], 0);
negs[i] = ! negs[i];
changed = 1;
break;
case CONST:
ops[i] = XEXP (ops[i], 0);
input_consts++;
changed = 1;
break;
case NOT:
/* ~a -> (-a - 1) */
if (n_ops != 7)
{
ops[n_ops] = constm1_rtx;
negs[n_ops++] = negs[i];
ops[i] = XEXP (ops[i], 0);
negs[i] = ! negs[i];
changed = 1;
}
break;
case CONST_INT:
if (negs[i])
ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0, changed = 1;
break;
default:
break;
}
}
/* If we only have two operands, we can't do anything. */
if (n_ops <= 2)
return 0;
/* Now simplify each pair of operands until nothing changes. The first
time through just simplify constants against each other. */
changed = 1;
while (changed)
{
changed = first;
for (i = 0; i < n_ops - 1; i++)
for (j = i + 1; j < n_ops; j++)
if (ops[i] != 0 && ops[j] != 0
&& (! first || (CONSTANT_P (ops[i]) && CONSTANT_P (ops[j]))))
{
rtx lhs = ops[i], rhs = ops[j];
enum rtx_code ncode = PLUS;
if (negs[i] && ! negs[j])
lhs = ops[j], rhs = ops[i], ncode = MINUS;
else if (! negs[i] && negs[j])
ncode = MINUS;
tem = simplify_binary_operation (ncode, mode, lhs, rhs);
if (tem)
{
ops[i] = tem, ops[j] = 0;
negs[i] = negs[i] && negs[j];
if (GET_CODE (tem) == NEG)
ops[i] = XEXP (tem, 0), negs[i] = ! negs[i];
if (GET_CODE (ops[i]) == CONST_INT && negs[i])
ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0;
changed = 1;
}
}
first = 0;
}
/* Pack all the operands to the lower-numbered entries and give up if
we didn't reduce the number of operands we had. Make sure we
count a CONST as two operands. If we have the same number of
operands, but have made more CONSTs than we had, this is also
an improvement, so accept it. */
for (i = 0, j = 0; j < n_ops; j++)
if (ops[j] != 0)
{
ops[i] = ops[j], negs[i++] = negs[j];
if (GET_CODE (ops[j]) == CONST)
n_consts++;
}
if (i + n_consts > input_ops
|| (i + n_consts == input_ops && n_consts <= input_consts))
return 0;
n_ops = i;
/* If we have a CONST_INT, put it last. */
for (i = 0; i < n_ops - 1; i++)
if (GET_CODE (ops[i]) == CONST_INT)
{
tem = ops[n_ops - 1], ops[n_ops - 1] = ops[i] , ops[i] = tem;
j = negs[n_ops - 1], negs[n_ops - 1] = negs[i], negs[i] = j;
}
/* Put a non-negated operand first. If there aren't any, make all
operands positive and negate the whole thing later. */
for (i = 0; i < n_ops && negs[i]; i++)
;
if (i == n_ops)
{
for (i = 0; i < n_ops; i++)
negs[i] = 0;
negate = 1;
}
else if (i != 0)
{
tem = ops[0], ops[0] = ops[i], ops[i] = tem;
j = negs[0], negs[0] = negs[i], negs[i] = j;
}
/* Now make the result by performing the requested operations. */
result = ops[0];
for (i = 1; i < n_ops; i++)
result = simplify_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]);
return negate ? gen_rtx_NEG (mode, result) : result;
}
struct cfc_args
{
rtx op0, op1; /* Input */
int equal, op0lt, op1lt; /* Output */
int unordered;
};
static void
check_fold_consts (data)
PTR data;
{
struct cfc_args *args = (struct cfc_args *) data;
REAL_VALUE_TYPE d0, d1;
/* We may possibly raise an exception while reading the value. */
args->unordered = 1;
REAL_VALUE_FROM_CONST_DOUBLE (d0, args->op0);
REAL_VALUE_FROM_CONST_DOUBLE (d1, args->op1);
/* Comparisons of Inf versus Inf are ordered. */
if (REAL_VALUE_ISNAN (d0)
|| REAL_VALUE_ISNAN (d1))
return;
args->equal = REAL_VALUES_EQUAL (d0, d1);
args->op0lt = REAL_VALUES_LESS (d0, d1);
args->op1lt = REAL_VALUES_LESS (d1, d0);
args->unordered = 0;
}
/* Like simplify_binary_operation except used for relational operators.
MODE is the mode of the operands, not that of the result. If MODE
is VOIDmode, both operands must also be VOIDmode and we compare the
operands in "infinite precision".
If no simplification is possible, this function returns zero. Otherwise,
it returns either const_true_rtx or const0_rtx. */
rtx
simplify_relational_operation (code, mode, op0, op1)
enum rtx_code code;
enum machine_mode mode;
rtx op0, op1;
{
int equal, op0lt, op0ltu, op1lt, op1ltu;
rtx tem;
if (mode == VOIDmode
&& (GET_MODE (op0) != VOIDmode
|| GET_MODE (op1) != VOIDmode))
abort ();
/* If op0 is a compare, extract the comparison arguments from it. */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
/* We can't simplify MODE_CC values since we don't know what the
actual comparison is. */
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC
#ifdef HAVE_cc0
|| op0 == cc0_rtx
#endif
)
return 0;
/* Make sure the constant is second. */
if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
|| (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
{
tem = op0, op0 = op1, op1 = tem;
code = swap_condition (code);
}
/* For integer comparisons of A and B maybe we can simplify A - B and can
then simplify a comparison of that with zero. If A and B are both either
a register or a CONST_INT, this can't help; testing for these cases will
prevent infinite recursion here and speed things up.
If CODE is an unsigned comparison, then we can never do this optimization,
because it gives an incorrect result if the subtraction wraps around zero.
ANSI C defines unsigned operations such that they never overflow, and
thus such cases can not be ignored. */
if (INTEGRAL_MODE_P (mode) && op1 != const0_rtx
&& ! ((GET_CODE (op0) == REG || GET_CODE (op0) == CONST_INT)
&& (GET_CODE (op1) == REG || GET_CODE (op1) == CONST_INT))
&& 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
&& code != GTU && code != GEU && code != LTU && code != LEU)
return simplify_relational_operation (signed_condition (code),
mode, tem, const0_rtx);
if (flag_fast_math && code == ORDERED)
return const_true_rtx;
if (flag_fast_math && code == UNORDERED)
return const0_rtx;
/* For non-IEEE floating-point, if the two operands are equal, we know the
result. */
if (rtx_equal_p (op0, op1)
&& (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math))
equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
/* If the operands are floating-point constants, see if we can fold
the result. */
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
else if (GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
{
struct cfc_args args;
/* Setup input for check_fold_consts() */
args.op0 = op0;
args.op1 = op1;
if (!do_float_handler(check_fold_consts, (PTR) &args))
args.unordered = 1;
if (args.unordered)
switch (code)
{
case UNEQ:
case UNLT:
case UNGT:
case UNLE:
case UNGE:
case NE:
case UNORDERED:
return const_true_rtx;
case EQ:
case LT:
case GT:
case LE:
case GE:
case LTGT:
case ORDERED:
return const0_rtx;
default:
return 0;
}
/* Receive output from check_fold_consts() */
equal = args.equal;
op0lt = op0ltu = args.op0lt;
op1lt = op1ltu = args.op1lt;
}
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
/* Otherwise, see if the operands are both integers. */
else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
&& (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
&& (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
{
int width = GET_MODE_BITSIZE (mode);
HOST_WIDE_INT l0s, h0s, l1s, h1s;
unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
/* Get the two words comprising each integer constant. */
if (GET_CODE (op0) == CONST_DOUBLE)
{
l0u = l0s = CONST_DOUBLE_LOW (op0);
h0u = h0s = CONST_DOUBLE_HIGH (op0);
}
else
{
l0u = l0s = INTVAL (op0);
h0u = h0s = HWI_SIGN_EXTEND (l0s);
}
if (GET_CODE (op1) == CONST_DOUBLE)
{
l1u = l1s = CONST_DOUBLE_LOW (op1);
h1u = h1s = CONST_DOUBLE_HIGH (op1);
}
else
{
l1u = l1s = INTVAL (op1);
h1u = h1s = HWI_SIGN_EXTEND (l1s);
}
/* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
we have to sign or zero-extend the values. */
if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
{
l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
l0s |= ((HOST_WIDE_INT) (-1) << width);
if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
l1s |= ((HOST_WIDE_INT) (-1) << width);
}
if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
equal = (h0u == h1u && l0u == l1u);
op0lt = (h0s < h1s || (h0s == h1s && l0u < l1u));
op1lt = (h1s < h0s || (h1s == h0s && l1u < l0u));
op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
}
/* Otherwise, there are some code-specific tests we can make. */
else
{
switch (code)
{
case EQ:
/* References to the frame plus a constant or labels cannot
be zero, but a SYMBOL_REF can due to #pragma weak. */
if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
|| GET_CODE (op0) == LABEL_REF)
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
/* On some machines, the ap reg can be 0 sometimes. */
&& op0 != arg_pointer_rtx
#endif
)
return const0_rtx;
break;
case NE:
if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
|| GET_CODE (op0) == LABEL_REF)
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
&& op0 != arg_pointer_rtx
#endif
)
return const_true_rtx;
break;
case GEU:
/* Unsigned values are never negative. */
if (op1 == const0_rtx)
return const_true_rtx;
break;
case LTU:
if (op1 == const0_rtx)
return const0_rtx;
break;
case LEU:
/* Unsigned values are never greater than the largest
unsigned value. */
if (GET_CODE (op1) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
&& INTEGRAL_MODE_P (mode))
return const_true_rtx;
break;
case GTU:
if (GET_CODE (op1) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
&& INTEGRAL_MODE_P (mode))
return const0_rtx;
break;
default:
break;
}
return 0;
}
/* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
as appropriate. */
switch (code)
{
case EQ:
case UNEQ:
return equal ? const_true_rtx : const0_rtx;
case NE:
case LTGT:
return ! equal ? const_true_rtx : const0_rtx;
case LT:
case UNLT:
return op0lt ? const_true_rtx : const0_rtx;
case GT:
case UNGT:
return op1lt ? const_true_rtx : const0_rtx;
case LTU:
return op0ltu ? const_true_rtx : const0_rtx;
case GTU:
return op1ltu ? const_true_rtx : const0_rtx;
case LE:
case UNLE:
return equal || op0lt ? const_true_rtx : const0_rtx;
case GE:
case UNGE:
return equal || op1lt ? const_true_rtx : const0_rtx;
case LEU:
return equal || op0ltu ? const_true_rtx : const0_rtx;
case GEU:
return equal || op1ltu ? const_true_rtx : const0_rtx;
case ORDERED:
return const_true_rtx;
case UNORDERED:
return const0_rtx;
default:
abort ();
}
}
/* Simplify CODE, an operation with result mode MODE and three operands,
OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became
a constant. Return 0 if no simplifications is possible. */
rtx
simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
enum rtx_code code;
enum machine_mode mode, op0_mode;
rtx op0, op1, op2;
{
unsigned int width = GET_MODE_BITSIZE (mode);
/* VOIDmode means "infinite" precision. */
if (width == 0)
width = HOST_BITS_PER_WIDE_INT;
switch (code)
{
case SIGN_EXTRACT:
case ZERO_EXTRACT:
if (GET_CODE (op0) == CONST_INT
&& GET_CODE (op1) == CONST_INT
&& GET_CODE (op2) == CONST_INT
&& ((unsigned) INTVAL (op1) + (unsigned) INTVAL (op2) <= width)
&& width <= (unsigned) HOST_BITS_PER_WIDE_INT)
{
/* Extracting a bit-field from a constant */
HOST_WIDE_INT val = INTVAL (op0);
if (BITS_BIG_ENDIAN)
val >>= (GET_MODE_BITSIZE (op0_mode)
- INTVAL (op2) - INTVAL (op1));
else
val >>= INTVAL (op2);
if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
{
/* First zero-extend. */
val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
/* If desired, propagate sign bit. */
if (code == SIGN_EXTRACT
&& (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1))))
val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
}
/* Clear the bits that don't belong in our mode,
unless they and our sign bit are all one.
So we get either a reasonable negative value or a reasonable
unsigned value for this mode. */
if (width < HOST_BITS_PER_WIDE_INT
&& ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
!= ((HOST_WIDE_INT) (-1) << (width - 1))))
val &= ((HOST_WIDE_INT) 1 << width) - 1;
return GEN_INT (val);
}
break;
case IF_THEN_ELSE:
if (GET_CODE (op0) == CONST_INT)
return op0 != const0_rtx ? op1 : op2;
/* Convert a == b ? b : a to "a". */
if (GET_CODE (op0) == NE && ! side_effects_p (op0)
&& (! FLOAT_MODE_P (mode) || flag_fast_math)
&& rtx_equal_p (XEXP (op0, 0), op1)
&& rtx_equal_p (XEXP (op0, 1), op2))
return op1;
else if (GET_CODE (op0) == EQ && ! side_effects_p (op0)
&& (! FLOAT_MODE_P (mode) || flag_fast_math)
&& rtx_equal_p (XEXP (op0, 1), op1)
&& rtx_equal_p (XEXP (op0, 0), op2))
return op2;
else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
{
enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
? GET_MODE (XEXP (op0, 1))
: GET_MODE (XEXP (op0, 0)));
rtx temp
= simplify_relational_operation (GET_CODE (op0), cmp_mode,
XEXP (op0, 0), XEXP (op0, 1));
/* See if any simplifications were possible. */
if (temp == const0_rtx)
return op2;
else if (temp == const1_rtx)
return op1;
else if (temp)
op0 = temp;
/* Look for happy constants in op1 and op2. */
if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
{
HOST_WIDE_INT t = INTVAL (op1);
HOST_WIDE_INT f = INTVAL (op2);
if (t == STORE_FLAG_VALUE && f == 0)
code = GET_CODE (op0);
else if (t == 0 && f == STORE_FLAG_VALUE)
{
enum rtx_code tmp;
tmp = reversed_comparison_code (op0, NULL_RTX);
if (tmp == UNKNOWN)
break;
code = tmp;
}
else
break;
return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1));
}
}
break;
default:
abort ();
}
return 0;
}
/* Simplify X, an rtx expression.
Return the simplified expression or NULL if no simplifications
were possible.
This is the preferred entry point into the simplification routines;
however, we still allow passes to call the more specific routines.
Right now GCC has three (yes, three) major bodies of RTL simplficiation
code that need to be unified.
1. fold_rtx in cse.c. This code uses various CSE specific
information to aid in RTL simplification.
2. simplify_rtx in combine.c. Similar to fold_rtx, except that
it uses combine specific information to aid in RTL
simplification.
3. The routines in this file.
Long term we want to only have one body of simplification code; to
get to that state I recommend the following steps:
1. Pour over fold_rtx & simplify_rtx and move any simplifications
which are not pass dependent state into these routines.
2. As code is moved by #1, change fold_rtx & simplify_rtx to
use this routine whenever possible.
3. Allow for pass dependent state to be provided to these
routines and add simplifications based on the pass dependent
state. Remove code from cse.c & combine.c that becomes
redundant/dead.
It will take time, but ultimately the compiler will be easier to
maintain and improve. It's totally silly that when we add a
simplification that it needs to be added to 4 places (3 for RTL
simplification and 1 for tree simplification. */
rtx
simplify_rtx (x)
rtx x;
{
enum rtx_code code;
enum machine_mode mode;
mode = GET_MODE (x);
code = GET_CODE (x);
switch (GET_RTX_CLASS (code))
{
case '1':
return simplify_unary_operation (code, mode,
XEXP (x, 0), GET_MODE (XEXP (x, 0)));
case '2':
case 'c':
return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
case '3':
case 'b':
return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)),
XEXP (x, 0), XEXP (x, 1), XEXP (x, 2));
case '<':
return simplify_relational_operation (code,
(GET_MODE (XEXP (x, 0)) != VOIDmode
? GET_MODE (XEXP (x, 0))
: GET_MODE (XEXP (x, 1))),
XEXP (x, 0), XEXP (x, 1));
default:
return NULL;
}
}
/* Allocate a struct elt_list and fill in its two elements with the
arguments. */
static struct elt_list *
new_elt_list (next, elt)
struct elt_list *next;
cselib_val *elt;
{
struct elt_list *el = empty_elt_lists;
if (el)
empty_elt_lists = el->next;
else
el = (struct elt_list *) obstack_alloc (&cselib_obstack,
sizeof (struct elt_list));
el->next = next;
el->elt = elt;
return el;
}
/* Allocate a struct elt_loc_list and fill in its two elements with the
arguments. */
static struct elt_loc_list *
new_elt_loc_list (next, loc)
struct elt_loc_list *next;
rtx loc;
{
struct elt_loc_list *el = empty_elt_loc_lists;
if (el)
empty_elt_loc_lists = el->next;
else
el = (struct elt_loc_list *) obstack_alloc (&cselib_obstack,
sizeof (struct elt_loc_list));
el->next = next;
el->loc = loc;
el->setting_insn = cselib_current_insn;
return el;
}
/* The elt_list at *PL is no longer needed. Unchain it and free its
storage. */
static void
unchain_one_elt_list (pl)
struct elt_list **pl;
{
struct elt_list *l = *pl;
*pl = l->next;
l->next = empty_elt_lists;
empty_elt_lists = l;
}
/* Likewise for elt_loc_lists. */
static void
unchain_one_elt_loc_list (pl)
struct elt_loc_list **pl;
{
struct elt_loc_list *l = *pl;
*pl = l->next;
l->next = empty_elt_loc_lists;
empty_elt_loc_lists = l;
}
/* Likewise for cselib_vals. This also frees the addr_list associated with
V. */
static void
unchain_one_value (v)
cselib_val *v;
{
while (v->addr_list)
unchain_one_elt_list (&v->addr_list);
v->u.next_free = empty_vals;
empty_vals = v;
}
/* Remove all entries from the hash table. Also used during
initialization. If CLEAR_ALL isn't set, then only clear the entries
which are known to have been used. */
static void
clear_table (clear_all)
int clear_all;
{
unsigned int i;
if (clear_all)
for (i = 0; i < cselib_nregs; i++)
REG_VALUES (i) = 0;
else
for (i = 0; i < VARRAY_ACTIVE_SIZE (used_regs); i++)
REG_VALUES (VARRAY_UINT (used_regs, i)) = 0;
VARRAY_POP_ALL (used_regs);
htab_empty (hash_table);
obstack_free (&cselib_obstack, cselib_startobj);
empty_vals = 0;
empty_elt_lists = 0;
empty_elt_loc_lists = 0;
n_useless_values = 0;
next_unknown_value = 0;
}
/* The equality test for our hash table. The first argument ENTRY is a table
element (i.e. a cselib_val), while the second arg X is an rtx. We know
that all callers of htab_find_slot_with_hash will wrap CONST_INTs into a
CONST of an appropriate mode. */
static int
entry_and_rtx_equal_p (entry, x_arg)
const void *entry, *x_arg;
{
struct elt_loc_list *l;
const cselib_val *v = (const cselib_val *) entry;
rtx x = (rtx) x_arg;
enum machine_mode mode = GET_MODE (x);
if (GET_CODE (x) == CONST_INT
|| (mode == VOIDmode && GET_CODE (x) == CONST_DOUBLE))
abort ();
if (mode != GET_MODE (v->u.val_rtx))
return 0;
/* Unwrap X if necessary. */
if (GET_CODE (x) == CONST
&& (GET_CODE (XEXP (x, 0)) == CONST_INT
|| GET_CODE (XEXP (x, 0)) == CONST_DOUBLE))
x = XEXP (x, 0);
/* We don't guarantee that distinct rtx's have different hash values,
so we need to do a comparison. */
for (l = v->locs; l; l = l->next)
if (rtx_equal_for_cselib_p (l->loc, x))
return 1;
return 0;
}
/* The hash function for our hash table. The value is always computed with
hash_rtx when adding an element; this function just extracts the hash
value from a cselib_val structure. */
static unsigned int
get_value_hash (entry)
const void *entry;
{
const cselib_val *v = (const cselib_val *) entry;
return v->value;
}
/* Return true if X contains a VALUE rtx. If ONLY_USELESS is set, we
only return true for values which point to a cselib_val whose value
element has been set to zero, which implies the cselib_val will be
removed. */
int
references_value_p (x, only_useless)
rtx x;
int only_useless;
{
enum rtx_code code = GET_CODE (x);
const char *fmt = GET_RTX_FORMAT (code);
int i, j;
if (GET_CODE (x) == VALUE
&& (! only_useless || CSELIB_VAL_PTR (x)->locs == 0))
return 1;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e' && references_value_p (XEXP (x, i), only_useless))
return 1;
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
if (references_value_p (XVECEXP (x, i, j), only_useless))
return 1;
}
return 0;
}
/* For all locations found in X, delete locations that reference useless
values (i.e. values without any location). Called through
htab_traverse. */
static int
discard_useless_locs (x, info)
void **x;
void *info ATTRIBUTE_UNUSED;
{
cselib_val *v = (cselib_val *)*x;
struct elt_loc_list **p = &v->locs;
int had_locs = v->locs != 0;
while (*p)
{
if (references_value_p ((*p)->loc, 1))
unchain_one_elt_loc_list (p);
else
p = &(*p)->next;
}
if (had_locs && v->locs == 0)
{
n_useless_values++;
values_became_useless = 1;
}
return 1;
}
/* If X is a value with no locations, remove it from the hashtable. */
static int
discard_useless_values (x, info)
void **x;
void *info ATTRIBUTE_UNUSED;
{
cselib_val *v = (cselib_val *)*x;
if (v->locs == 0)
{
htab_clear_slot (hash_table, x);
unchain_one_value (v);
n_useless_values--;
}
return 1;
}
/* Clean out useless values (i.e. those which no longer have locations
associated with them) from the hash table. */
static void
remove_useless_values ()
{
/* First pass: eliminate locations that reference the value. That in
turn can make more values useless. */
do
{
values_became_useless = 0;
htab_traverse (hash_table, discard_useless_locs, 0);
}
while (values_became_useless);
/* Second pass: actually remove the values. */
htab_traverse (hash_table, discard_useless_values, 0);
if (n_useless_values != 0)
abort ();
}
/* Return nonzero if we can prove that X and Y contain the same value, taking
our gathered information into account. */
int
rtx_equal_for_cselib_p (x, y)
rtx x, y;
{
enum rtx_code code;
const char *fmt;
int i;
if (GET_CODE (x) == REG || GET_CODE (x) == MEM)
{
cselib_val *e = cselib_lookup (x, GET_MODE (x), 0);
if (e)
x = e->u.val_rtx;
}
if (GET_CODE (y) == REG || GET_CODE (y) == MEM)
{
cselib_val *e = cselib_lookup (y, GET_MODE (y), 0);
if (e)
y = e->u.val_rtx;
}
if (x == y)
return 1;
if (GET_CODE (x) == VALUE && GET_CODE (y) == VALUE)
return CSELIB_VAL_PTR (x) == CSELIB_VAL_PTR (y);
if (GET_CODE (x) == VALUE)
{
cselib_val *e = CSELIB_VAL_PTR (x);
struct elt_loc_list *l;
for (l = e->locs; l; l = l->next)
{
rtx t = l->loc;
/* Avoid infinite recursion. */
if (GET_CODE (t) == REG || GET_CODE (t) == MEM)
continue;
else if (rtx_equal_for_cselib_p (t, y))
return 1;
}
return 0;
}
if (GET_CODE (y) == VALUE)
{
cselib_val *e = CSELIB_VAL_PTR (y);
struct elt_loc_list *l;
for (l = e->locs; l; l = l->next)
{
rtx t = l->loc;
if (GET_CODE (t) == REG || GET_CODE (t) == MEM)
continue;
else if (rtx_equal_for_cselib_p (x, t))
return 1;
}
return 0;
}
if (GET_CODE (x) != GET_CODE (y) || GET_MODE (x) != GET_MODE (y))
return 0;
/* This won't be handled correctly by the code below. */
if (GET_CODE (x) == LABEL_REF)
return XEXP (x, 0) == XEXP (y, 0);
code = GET_CODE (x);
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
int j;
switch (fmt[i])
{
case 'w':
if (XWINT (x, i) != XWINT (y, i))
return 0;
break;
case 'n':
case 'i':
if (XINT (x, i) != XINT (y, i))
return 0;
break;
case 'V':
case 'E':
/* Two vectors must have the same length. */
if (XVECLEN (x, i) != XVECLEN (y, i))
return 0;
/* And the corresponding elements must match. */
for (j = 0; j < XVECLEN (x, i); j++)
if (! rtx_equal_for_cselib_p (XVECEXP (x, i, j),
XVECEXP (y, i, j)))
return 0;
break;
case 'e':
if (! rtx_equal_for_cselib_p (XEXP (x, i), XEXP (y, i)))
return 0;
break;
case 'S':
case 's':
if (strcmp (XSTR (x, i), XSTR (y, i)))
return 0;
break;
case 'u':
/* These are just backpointers, so they don't matter. */
break;
case '0':
case 't':
break;
/* It is believed that rtx's at this level will never
contain anything but integers and other rtx's,
except for within LABEL_REFs and SYMBOL_REFs. */
default:
abort ();
}
}
return 1;
}
/* We need to pass down the mode of constants through the hash table
functions. For that purpose, wrap them in a CONST of the appropriate
mode. */
static rtx
wrap_constant (mode, x)
enum machine_mode mode;
rtx x;
{
if (GET_CODE (x) != CONST_INT
&& (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode))
return x;
if (mode == VOIDmode)
abort ();
return gen_rtx_CONST (mode, x);
}
/* Hash an rtx. Return 0 if we couldn't hash the rtx.
For registers and memory locations, we look up their cselib_val structure
and return its VALUE element.
Possible reasons for return 0 are: the object is volatile, or we couldn't
find a register or memory location in the table and CREATE is zero. If
CREATE is nonzero, table elts are created for regs and mem.
MODE is used in hashing for CONST_INTs only;
otherwise the mode of X is used. */
static unsigned int
hash_rtx (x, mode, create)
rtx x;
enum machine_mode mode;
int create;
{
cselib_val *e;
int i, j;
enum rtx_code code;
const char *fmt;
unsigned int hash = 0;
/* repeat is used to turn tail-recursion into iteration. */
repeat:
code = GET_CODE (x);
hash += (unsigned) code + (unsigned) GET_MODE (x);
switch (code)
{
case MEM:
case REG:
e = cselib_lookup (x, GET_MODE (x), create);
if (! e)
return 0;
hash += e->value;
return hash;
case CONST_INT:
hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + INTVAL (x);
return hash ? hash : CONST_INT;
case CONST_DOUBLE:
/* This is like the general case, except that it only counts
the integers representing the constant. */
hash += (unsigned) code + (unsigned) GET_MODE (x);
if (GET_MODE (x) != VOIDmode)
for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++)
hash += XWINT (x, i);
else
hash += ((unsigned) CONST_DOUBLE_LOW (x)
+ (unsigned) CONST_DOUBLE_HIGH (x));
return hash ? hash : CONST_DOUBLE;
/* Assume there is only one rtx object for any given label. */
case LABEL_REF:
hash
+= ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0);
return hash ? hash : LABEL_REF;
case SYMBOL_REF:
hash
+= ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0);
return hash ? hash : SYMBOL_REF;
case PRE_DEC:
case PRE_INC:
case POST_DEC:
case POST_INC:
case POST_MODIFY:
case PRE_MODIFY:
case PC:
case CC0:
case CALL:
case UNSPEC_VOLATILE:
return 0;
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 0;
break;
default:
break;
}
i = GET_RTX_LENGTH (code) - 1;
fmt = GET_RTX_FORMAT (code);
for (; i >= 0; i--)
{
if (fmt[i] == 'e')
{
rtx tem = XEXP (x, i);
unsigned int tem_hash;
/* If we are about to do the last recursive call
needed at this level, change it into iteration.
This function is called enough to be worth it. */
if (i == 0)
{
x = tem;
goto repeat;
}
tem_hash = hash_rtx (tem, 0, create);
if (tem_hash == 0)
return 0;
hash += tem_hash;
}
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
{
unsigned int tem_hash = hash_rtx (XVECEXP (x, i, j), 0, create);
if (tem_hash == 0)
return 0;
hash += tem_hash;
}
else if (fmt[i] == 's')
{
const unsigned char *p = (const unsigned char *) XSTR (x, i);
if (p)
while (*p)
hash += *p++;
}
else if (fmt[i] == 'i')
hash += XINT (x, i);
else if (fmt[i] == '0' || fmt[i] == 't')
/* unused */;
else
abort ();
}
return hash ? hash : 1 + GET_CODE (x);
}
/* Create a new value structure for VALUE and initialize it. The mode of the
value is MODE. */
static cselib_val *
new_cselib_val (value, mode)
unsigned int value;
enum machine_mode mode;
{
cselib_val *e = empty_vals;
if (e)
empty_vals = e->u.next_free;
else
e = (cselib_val *) obstack_alloc (&cselib_obstack, sizeof (cselib_val));
if (value == 0)
abort ();
e->value = value;
e->u.val_rtx = gen_rtx_VALUE (mode);
CSELIB_VAL_PTR (e->u.val_rtx) = e;
e->addr_list = 0;
e->locs = 0;
return e;
}
/* ADDR_ELT is a value that is used as address. MEM_ELT is the value that
contains the data at this address. X is a MEM that represents the
value. Update the two value structures to represent this situation. */
static void
add_mem_for_addr (addr_elt, mem_elt, x)
cselib_val *addr_elt, *mem_elt;
rtx x;
{
rtx new;
struct elt_loc_list *l;
/* Avoid duplicates. */
for (l = mem_elt->locs; l; l = l->next)
if (GET_CODE (l->loc) == MEM
&& CSELIB_VAL_PTR (XEXP (l->loc, 0)) == addr_elt)
return;
new = gen_rtx_MEM (GET_MODE (x), addr_elt->u.val_rtx);
MEM_COPY_ATTRIBUTES (new, x);
addr_elt->addr_list = new_elt_list (addr_elt->addr_list, mem_elt);
mem_elt->locs = new_elt_loc_list (mem_elt->locs, new);
}
/* Subroutine of cselib_lookup. Return a value for X, which is a MEM rtx.
If CREATE, make a new one if we haven't seen it before. */
static cselib_val *
cselib_lookup_mem (x, create)
rtx x;
int create;
{
enum machine_mode mode = GET_MODE (x);
void **slot;
cselib_val *addr;
cselib_val *mem_elt;
struct elt_list *l;
if (MEM_VOLATILE_P (x) || mode == BLKmode
|| (FLOAT_MODE_P (mode) && flag_float_store))
return 0;
/* Look up the value for the address. */
addr = cselib_lookup (XEXP (x, 0), mode, create);
if (! addr)
return 0;
/* Find a value that describes a value of our mode at that address. */
for (l = addr->addr_list; l; l = l->next)
if (GET_MODE (l->elt->u.val_rtx) == mode)
return l->elt;
if (! create)
return 0;
mem_elt = new_cselib_val (++next_unknown_value, mode);
add_mem_for_addr (addr, mem_elt, x);
slot = htab_find_slot_with_hash (hash_table, wrap_constant (mode, x),
mem_elt->value, INSERT);
*slot = mem_elt;
return mem_elt;
}
/* Walk rtx X and replace all occurrences of REG and MEM subexpressions
with VALUE expressions. This way, it becomes independent of changes
to registers and memory.
X isn't actually modified; if modifications are needed, new rtl is
allocated. However, the return value can share rtl with X. */
static rtx
cselib_subst_to_values (x)
rtx x;
{
enum rtx_code code = GET_CODE (x);
const char *fmt = GET_RTX_FORMAT (code);
cselib_val *e;
struct elt_list *l;
rtx copy = x;
int i;
switch (code)
{
case REG:
for (l = REG_VALUES (REGNO (x)); l; l = l->next)
if (GET_MODE (l->elt->u.val_rtx) == GET_MODE (x))
return l->elt->u.val_rtx;
abort ();
case MEM:
e = cselib_lookup_mem (x, 0);
if (! e)
abort ();
return e->u.val_rtx;
/* CONST_DOUBLEs must be special-cased here so that we won't try to
look up the CONST_DOUBLE_MEM inside. */
case CONST_DOUBLE:
case CONST_INT:
return x;
default:
break;
}
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
rtx t = cselib_subst_to_values (XEXP (x, i));
if (t != XEXP (x, i) && x == copy)
copy = shallow_copy_rtx (x);
XEXP (copy, i) = t;
}
else if (fmt[i] == 'E')
{
int j, k;
for (j = 0; j < XVECLEN (x, i); j++)
{
rtx t = cselib_subst_to_values (XVECEXP (x, i, j));
if (t != XVECEXP (x, i, j) && XVEC (x, i) == XVEC (copy, i))
{
if (x == copy)
copy = shallow_copy_rtx (x);
XVEC (copy, i) = rtvec_alloc (XVECLEN (x, i));
for (k = 0; k < j; k++)
XVECEXP (copy, i, k) = XVECEXP (x, i, k);
}
XVECEXP (copy, i, j) = t;
}
}
}
return copy;
}
/* Look up the rtl expression X in our tables and return the value it has.
If CREATE is zero, we return NULL if we don't know the value. Otherwise,
we create a new one if possible, using mode MODE if X doesn't have a mode
(i.e. because it's a constant). */
cselib_val *
cselib_lookup (x, mode, create)
rtx x;
enum machine_mode mode;
int create;
{
void **slot;
cselib_val *e;
unsigned int hashval;
if (GET_MODE (x) != VOIDmode)
mode = GET_MODE (x);
if (GET_CODE (x) == VALUE)
return CSELIB_VAL_PTR (x);
if (GET_CODE (x) == REG)
{
struct elt_list *l;
unsigned int i = REGNO (x);
for (l = REG_VALUES (i); l; l = l->next)
if (mode == GET_MODE (l->elt->u.val_rtx))
return l->elt;
if (! create)
return 0;
e = new_cselib_val (++next_unknown_value, GET_MODE (x));
e->locs = new_elt_loc_list (e->locs, x);
if (REG_VALUES (i) == 0)
VARRAY_PUSH_UINT (used_regs, i);
REG_VALUES (i) = new_elt_list (REG_VALUES (i), e);
slot = htab_find_slot_with_hash (hash_table, x, e->value, INSERT);
*slot = e;
return e;
}
if (GET_CODE (x) == MEM)
return cselib_lookup_mem (x, create);
hashval = hash_rtx (x, mode, create);
/* Can't even create if hashing is not possible. */
if (! hashval)
return 0;
slot = htab_find_slot_with_hash (hash_table, wrap_constant (mode, x),
hashval, create ? INSERT : NO_INSERT);
if (slot == 0)
return 0;
e = (cselib_val *) *slot;
if (e)
return e;
e = new_cselib_val (hashval, mode);
/* We have to fill the slot before calling cselib_subst_to_values:
the hash table is inconsistent until we do so, and
cselib_subst_to_values will need to do lookups. */
*slot = (void *) e;
e->locs = new_elt_loc_list (e->locs, cselib_subst_to_values (x));
return e;
}
/* Invalidate any entries in reg_values that overlap REGNO. This is called
if REGNO is changing. MODE is the mode of the assignment to REGNO, which
is used to determine how many hard registers are being changed. If MODE
is VOIDmode, then only REGNO is being changed; this is used when
invalidating call clobbered registers across a call. */
static void
cselib_invalidate_regno (regno, mode)
unsigned int regno;
enum machine_mode mode;
{
unsigned int endregno;
unsigned int i;
/* If we see pseudos after reload, something is _wrong_. */
if (reload_completed && regno >= FIRST_PSEUDO_REGISTER
&& reg_renumber[regno] >= 0)
abort ();
/* Determine the range of registers that must be invalidated. For
pseudos, only REGNO is affected. For hard regs, we must take MODE
into account, and we must also invalidate lower register numbers
if they contain values that overlap REGNO. */
endregno = regno + 1;
if (regno < FIRST_PSEUDO_REGISTER && mode != VOIDmode)
endregno = regno + HARD_REGNO_NREGS (regno, mode);
for (i = 0; i < endregno; i++)
{
struct elt_list **l = &REG_VALUES (i);
/* Go through all known values for this reg; if it overlaps the range
we're invalidating, remove the value. */
while (*l)
{
cselib_val *v = (*l)->elt;
struct elt_loc_list **p;
unsigned int this_last = i;
if (i < FIRST_PSEUDO_REGISTER)
this_last += HARD_REGNO_NREGS (i, GET_MODE (v->u.val_rtx)) - 1;
if (this_last < regno)
{
l = &(*l)->next;
continue;
}
/* We have an overlap. */
unchain_one_elt_list (l);
/* Now, we clear the mapping from value to reg. It must exist, so
this code will crash intentionally if it doesn't. */
for (p = &v->locs; ; p = &(*p)->next)
{
rtx x = (*p)->loc;
if (GET_CODE (x) == REG && REGNO (x) == i)
{
unchain_one_elt_loc_list (p);
break;
}
}
if (v->locs == 0)
n_useless_values++;
}
}
}
/* The memory at address MEM_BASE is being changed.
Return whether this change will invalidate VAL. */
static int
cselib_mem_conflict_p (mem_base, val)
rtx mem_base;
rtx val;
{
enum rtx_code code;
const char *fmt;
int i, j;
code = GET_CODE (val);
switch (code)
{
/* Get rid of a few simple cases quickly. */
case REG:
case PC:
case CC0:
case SCRATCH:
case CONST:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case LABEL_REF:
return 0;
case MEM:
if (GET_MODE (mem_base) == BLKmode
|| GET_MODE (val) == BLKmode
|| anti_dependence (val, mem_base))
return 1;
/* The address may contain nested MEMs. */
break;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (cselib_mem_conflict_p (mem_base, XEXP (val, i)))
return 1;
}
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (val, i); j++)
if (cselib_mem_conflict_p (mem_base, XVECEXP (val, i, j)))
return 1;
}
return 0;
}
/* For the value found in SLOT, walk its locations to determine if any overlap
INFO (which is a MEM rtx). */
static int
cselib_invalidate_mem_1 (slot, info)
void **slot;
void *info;
{
cselib_val *v = (cselib_val *) *slot;
rtx mem_rtx = (rtx) info;
struct elt_loc_list **p = &v->locs;
int had_locs = v->locs != 0;
while (*p)
{
rtx x = (*p)->loc;
cselib_val *addr;
struct elt_list **mem_chain;
/* MEMs may occur in locations only at the top level; below
that every MEM or REG is substituted by its VALUE. */
if (GET_CODE (x) != MEM
|| ! cselib_mem_conflict_p (mem_rtx, x))
{
p = &(*p)->next;
continue;
}
/* This one overlaps. */
/* We must have a mapping from this MEM's address to the
value (E). Remove that, too. */
addr = cselib_lookup (XEXP (x, 0), VOIDmode, 0);
mem_chain = &addr->addr_list;
for (;;)
{
if ((*mem_chain)->elt == v)
{
unchain_one_elt_list (mem_chain);
break;
}
mem_chain = &(*mem_chain)->next;
}
unchain_one_elt_loc_list (p);
}
if (had_locs && v->locs == 0)
n_useless_values++;
return 1;
}
/* Invalidate any locations in the table which are changed because of a
store to MEM_RTX. If this is called because of a non-const call
instruction, MEM_RTX is (mem:BLK const0_rtx). */
static void
cselib_invalidate_mem (mem_rtx)
rtx mem_rtx;
{
htab_traverse (hash_table, cselib_invalidate_mem_1, mem_rtx);
}
/* Invalidate DEST, which is being assigned to or clobbered. The second and
the third parameter exist so that this function can be passed to
note_stores; they are ignored. */
static void
cselib_invalidate_rtx (dest, ignore, data)
rtx dest;
rtx ignore ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG)
cselib_invalidate_regno (REGNO (dest), GET_MODE (dest));
else if (GET_CODE (dest) == MEM)
cselib_invalidate_mem (dest);
/* Some machines don't define AUTO_INC_DEC, but they still use push
instructions. We need to catch that case here in order to
invalidate the stack pointer correctly. Note that invalidating
the stack pointer is different from invalidating DEST. */
if (push_operand (dest, GET_MODE (dest)))
cselib_invalidate_rtx (stack_pointer_rtx, NULL_RTX, NULL);
}
/* Record the result of a SET instruction. DEST is being set; the source
contains the value described by SRC_ELT. If DEST is a MEM, DEST_ADDR_ELT
describes its address. */
static void
cselib_record_set (dest, src_elt, dest_addr_elt)
rtx dest;
cselib_val *src_elt, *dest_addr_elt;
{
int dreg = GET_CODE (dest) == REG ? (int) REGNO (dest) : -1;
if (src_elt == 0 || side_effects_p (dest))
return;
if (dreg >= 0)
{
if (REG_VALUES (dreg) == 0)
VARRAY_PUSH_UINT (used_regs, dreg);
REG_VALUES (dreg) = new_elt_list (REG_VALUES (dreg), src_elt);
if (src_elt->locs == 0)
n_useless_values--;
src_elt->locs = new_elt_loc_list (src_elt->locs, dest);
}
else if (GET_CODE (dest) == MEM && dest_addr_elt != 0)
{
if (src_elt->locs == 0)
n_useless_values--;
add_mem_for_addr (dest_addr_elt, src_elt, dest);
}
}
/* Describe a single set that is part of an insn. */
struct set
{
rtx src;
rtx dest;
cselib_val *src_elt;
cselib_val *dest_addr_elt;
};
/* There is no good way to determine how many elements there can be
in a PARALLEL. Since it's fairly cheap, use a really large number. */
#define MAX_SETS (FIRST_PSEUDO_REGISTER * 2)
/* Record the effects of any sets in INSN. */
static void
cselib_record_sets (insn)
rtx insn;
{
int n_sets = 0;
int i;
struct set sets[MAX_SETS];
rtx body = PATTERN (insn);
body = PATTERN (insn);
/* Find all sets. */
if (GET_CODE (body) == SET)
{
sets[0].src = SET_SRC (body);
sets[0].dest = SET_DEST (body);
n_sets = 1;
}
else if (GET_CODE (body) == PARALLEL)
{
/* Look through the PARALLEL and record the values being
set, if possible. Also handle any CLOBBERs. */
for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
{
rtx x = XVECEXP (body, 0, i);
if (GET_CODE (x) == SET)
{
sets[n_sets].src = SET_SRC (x);
sets[n_sets].dest = SET_DEST (x);
n_sets++;
}
}
}
/* Look up the values that are read. Do this before invalidating the
locations that are written. */
for (i = 0; i < n_sets; i++)
{
rtx dest = sets[i].dest;
/* A STRICT_LOW_PART can be ignored; we'll record the equivalence for
the low part after invalidating any knowledge about larger modes. */
if (GET_CODE (sets[i].dest) == STRICT_LOW_PART)
sets[i].dest = dest = XEXP (dest, 0);
/* We don't know how to record anything but REG or MEM. */
if (GET_CODE (dest) == REG || GET_CODE (dest) == MEM)
{
sets[i].src_elt = cselib_lookup (sets[i].src, GET_MODE (dest), 1);
if (GET_CODE (dest) == MEM)
sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0), Pmode, 1);
else
sets[i].dest_addr_elt = 0;
}
}
/* Invalidate all locations written by this insn. Note that the elts we
looked up in the previous loop aren't affected, just some of their
locations may go away. */
note_stores (body, cselib_invalidate_rtx, NULL);
/* Now enter the equivalences in our tables. */
for (i = 0; i < n_sets; i++)
{
rtx dest = sets[i].dest;
if (GET_CODE (dest) == REG || GET_CODE (dest) == MEM)
cselib_record_set (dest, sets[i].src_elt, sets[i].dest_addr_elt);
}
}
/* Record the effects of INSN. */
void
cselib_process_insn (insn)
rtx insn;
{
int i;
rtx x;
cselib_current_insn = insn;
/* Forget everything at a CODE_LABEL, a volatile asm, or a setjmp. */
if (GET_CODE (insn) == CODE_LABEL
|| (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
|| (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == ASM_OPERANDS
&& MEM_VOLATILE_P (PATTERN (insn))))
{
clear_table (0);
return;
}
if (! INSN_P (insn))
{
cselib_current_insn = 0;
return;
}
/* If this is a call instruction, forget anything stored in a
call clobbered register, or, if this is not a const call, in
memory. */
if (GET_CODE (insn) == CALL_INSN)
{
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i])
cselib_invalidate_regno (i, VOIDmode);
if (! CONST_CALL_P (insn))
cselib_invalidate_mem (callmem);
}
cselib_record_sets (insn);
#ifdef AUTO_INC_DEC
/* Clobber any registers which appear in REG_INC notes. We
could keep track of the changes to their values, but it is
unlikely to help. */
for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
if (REG_NOTE_KIND (x) == REG_INC)
cselib_invalidate_rtx (XEXP (x, 0), NULL_RTX, NULL);
#endif
/* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
after we have processed the insn. */
if (GET_CODE (insn) == CALL_INSN)
for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
if (GET_CODE (XEXP (x, 0)) == CLOBBER)
cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX, NULL);
cselib_current_insn = 0;
if (n_useless_values > MAX_USELESS_VALUES)
remove_useless_values ();
}
/* Make sure our varrays are big enough. Not called from any cselib routines;
it must be called by the user if it allocated new registers. */
void
cselib_update_varray_sizes ()
{
unsigned int nregs = max_reg_num ();
if (nregs == cselib_nregs)
return;
cselib_nregs = nregs;
VARRAY_GROW (reg_values, nregs);
VARRAY_GROW (used_regs, nregs);
}
/* Initialize cselib for one pass. The caller must also call
init_alias_analysis. */
void
cselib_init ()
{
/* These are only created once. */
if (! callmem)
{
gcc_obstack_init (&cselib_obstack);
cselib_startobj = obstack_alloc (&cselib_obstack, 0);
callmem = gen_rtx_MEM (BLKmode, const0_rtx);
ggc_add_rtx_root (&callmem, 1);
}
cselib_nregs = max_reg_num ();
VARRAY_ELT_LIST_INIT (reg_values, cselib_nregs, "reg_values");
VARRAY_UINT_INIT (used_regs, cselib_nregs, "used_regs");
hash_table = htab_create (31, get_value_hash, entry_and_rtx_equal_p, NULL);
clear_table (1);
}
/* Called when the current user is done with cselib. */
void
cselib_finish ()
{
clear_table (0);
VARRAY_FREE (reg_values);
VARRAY_FREE (used_regs);
htab_delete (hash_table);
}