| /* 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) |
| || (GET_CODE (op) == SUBREG |
| && GET_CODE (SUBREG_REG (op)) == REG |
| && REG_POINTER (SUBREG_REG (op)) |
| && GET_MODE (SUBREG_REG (op)) == Pmode))) |
| 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) |
| || (GET_CODE (op) == SUBREG |
| && GET_CODE (SUBREG_REG (op)) == REG |
| && REG_POINTER (SUBREG_REG (op)) |
| && GET_MODE (SUBREG_REG (op)) == Pmode))) |
| 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 |
| || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1) |
| && arg1s == -1)) |
| return 0; |
| val = arg0s / arg1s; |
| break; |
| |
| case MOD: |
| if (arg1s == 0 |
| || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1) |
| && arg1s == -1)) |
| return 0; |
| val = arg0s % arg1s; |
| break; |
| |
| case UDIV: |
| if (arg1 == 0 |
| || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1) |
| && arg1s == -1)) |
| return 0; |
| val = (unsigned HOST_WIDE_INT) arg0 / arg1; |
| break; |
| |
| case UMOD: |
| if (arg1 == 0 |
| || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1) |
| && arg1s == -1)) |
| 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; |
| if (cmp_mode == VOIDmode) |
| cmp_mode = op0_mode; |
| 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; |
| |
| return e->value; |
| |
| case CONST_INT: |
| hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + INTVAL (x); |
| return hash ? hash : (unsigned int) 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 : (unsigned int) 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 : (unsigned int) LABEL_REF; |
| |
| case SYMBOL_REF: |
| hash |
| += ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0); |
| return hash ? hash : (unsigned int) 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 + (unsigned int) 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 = ®_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); |
| } |