/* Common subexpression elimination for GNU compiler.
- Copyright (C) 1987, 88, 89, 92-7, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-99, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "expr.h"
#include "toplev.h"
#include "output.h"
-#include "hashtab.h"
#include "ggc.h"
/* The basic idea of common subexpression elimination is to go
|| XEXP (X, 0) == virtual_outgoing_args_rtx)) \
|| GET_CODE (X) == ADDRESSOF)
-static int notreg_cost PROTO((rtx));
-static void new_basic_block PROTO((void));
-static void make_new_qty PROTO((int, enum machine_mode));
-static void make_regs_eqv PROTO((int, int));
-static void delete_reg_equiv PROTO((int));
-static int mention_regs PROTO((rtx));
-static int insert_regs PROTO((rtx, struct table_elt *, int));
-static void free_element PROTO((struct table_elt *));
-static void remove_from_table PROTO((struct table_elt *, unsigned));
-static struct table_elt *get_element PROTO((void));
-static struct table_elt *lookup PROTO((rtx, unsigned, enum machine_mode)),
- *lookup_for_remove PROTO((rtx, unsigned, enum machine_mode));
-static rtx lookup_as_function PROTO((rtx, enum rtx_code));
-static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned,
- enum machine_mode));
-static void merge_equiv_classes PROTO((struct table_elt *,
- struct table_elt *));
-static void invalidate PROTO((rtx, enum machine_mode));
-static int cse_rtx_varies_p PROTO((rtx));
-static void remove_invalid_refs PROTO((int));
-static void remove_invalid_subreg_refs PROTO((int, int, enum machine_mode));
-static void rehash_using_reg PROTO((rtx));
-static void invalidate_memory PROTO((void));
-static void invalidate_for_call PROTO((void));
-static rtx use_related_value PROTO((rtx, struct table_elt *));
-static unsigned canon_hash PROTO((rtx, enum machine_mode));
-static unsigned safe_hash PROTO((rtx, enum machine_mode));
-static int exp_equiv_p PROTO((rtx, rtx, int, int));
-static rtx canon_reg PROTO((rtx, rtx));
-static void find_best_addr PROTO((rtx, rtx *));
-static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *,
- enum machine_mode *,
- enum machine_mode *));
-static rtx fold_rtx PROTO((rtx, rtx));
-static rtx equiv_constant PROTO((rtx));
-static void record_jump_equiv PROTO((rtx, int));
-static void record_jump_cond PROTO((enum rtx_code, enum machine_mode,
- rtx, rtx, int));
-static void cse_insn PROTO((rtx, rtx));
-static int addr_affects_sp_p PROTO((rtx));
-static void invalidate_from_clobbers PROTO((rtx));
-static rtx cse_process_notes PROTO((rtx, rtx));
-static void cse_around_loop PROTO((rtx));
-static void invalidate_skipped_set PROTO((rtx, rtx, void *));
-static void invalidate_skipped_block PROTO((rtx));
-static void cse_check_loop_start PROTO((rtx, rtx, void *));
-static void cse_set_around_loop PROTO((rtx, rtx, rtx));
-static rtx cse_basic_block PROTO((rtx, rtx, struct branch_path *, int));
-static void count_reg_usage PROTO((rtx, int *, rtx, int));
-extern void dump_class PROTO((struct table_elt*));
-static struct cse_reg_info* get_cse_reg_info PROTO((int));
-static unsigned int hash_cse_reg_info PROTO((hash_table_entry_t));
-static int cse_reg_info_equal_p PROTO((hash_table_entry_t,
- hash_table_entry_t));
-
-static void flush_hash_table PROTO((void));
+static int notreg_cost PARAMS ((rtx));
+static void new_basic_block PARAMS ((void));
+static void make_new_qty PARAMS ((int, enum machine_mode));
+static void make_regs_eqv PARAMS ((int, int));
+static void delete_reg_equiv PARAMS ((int));
+static int mention_regs PARAMS ((rtx));
+static int insert_regs PARAMS ((rtx, struct table_elt *, int));
+static void remove_from_table PARAMS ((struct table_elt *, unsigned));
+static struct table_elt *lookup PARAMS ((rtx, unsigned, enum machine_mode)),
+ *lookup_for_remove PARAMS ((rtx, unsigned, enum machine_mode));
+static rtx lookup_as_function PARAMS ((rtx, enum rtx_code));
+static struct table_elt *insert PARAMS ((rtx, struct table_elt *, unsigned,
+ enum machine_mode));
+static void merge_equiv_classes PARAMS ((struct table_elt *,
+ struct table_elt *));
+static void invalidate PARAMS ((rtx, enum machine_mode));
+static int cse_rtx_varies_p PARAMS ((rtx));
+static void remove_invalid_refs PARAMS ((int));
+static void remove_invalid_subreg_refs PARAMS ((int, int, enum machine_mode));
+static void rehash_using_reg PARAMS ((rtx));
+static void invalidate_memory PARAMS ((void));
+static void invalidate_for_call PARAMS ((void));
+static rtx use_related_value PARAMS ((rtx, struct table_elt *));
+static unsigned canon_hash PARAMS ((rtx, enum machine_mode));
+static unsigned safe_hash PARAMS ((rtx, enum machine_mode));
+static int exp_equiv_p PARAMS ((rtx, rtx, int, int));
+static rtx canon_reg PARAMS ((rtx, rtx));
+static void find_best_addr PARAMS ((rtx, rtx *));
+static enum rtx_code find_comparison_args PARAMS ((enum rtx_code, rtx *, rtx *,
+ enum machine_mode *,
+ enum machine_mode *));
+static rtx fold_rtx PARAMS ((rtx, rtx));
+static rtx equiv_constant PARAMS ((rtx));
+static void record_jump_equiv PARAMS ((rtx, int));
+static void record_jump_cond PARAMS ((enum rtx_code, enum machine_mode,
+ rtx, rtx, int));
+static void cse_insn PARAMS ((rtx, rtx));
+static int addr_affects_sp_p PARAMS ((rtx));
+static void invalidate_from_clobbers PARAMS ((rtx));
+static rtx cse_process_notes PARAMS ((rtx, rtx));
+static void cse_around_loop PARAMS ((rtx));
+static void invalidate_skipped_set PARAMS ((rtx, rtx, void *));
+static void invalidate_skipped_block PARAMS ((rtx));
+static void cse_check_loop_start PARAMS ((rtx, rtx, void *));
+static void cse_set_around_loop PARAMS ((rtx, rtx, rtx));
+static rtx cse_basic_block PARAMS ((rtx, rtx, struct branch_path *, int));
+static void count_reg_usage PARAMS ((rtx, int *, rtx, int));
+extern void dump_class PARAMS ((struct table_elt*));
+static struct cse_reg_info* get_cse_reg_info PARAMS ((int));
+
+static void flush_hash_table PARAMS ((void));
\f
/* Dump the expressions in the equivalence class indicated by CLASSP.
This function is used only for debugging. */
}
}
-/* Return an estimate of the cost of computing rtx X.
- One use is in cse, to decide which expression to keep in the hash table.
- Another is in rtl generation, to pick the cheapest way to multiply.
- Other uses like the latter are expected in the future. */
-
/* Internal function, to compute cost when X is not a register; called
from COST macro to keep it simple. */
#define COSTS_N_INSNS(N) ((N) * 4 - 2)
+/* Return an estimate of the cost of computing rtx X.
+ One use is in cse, to decide which expression to keep in the hash table.
+ Another is in rtl generation, to pick the cheapest way to multiply.
+ Other uses like the latter are expected in the future. */
+
int
rtx_cost (x, outer_code)
rtx x;
&& code == LT && STORE_FLAG_VALUE == -1)
#ifdef FLOAT_STORE_FLAG_VALUE
|| (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
x = arg1;
&& code == GE && STORE_FLAG_VALUE == -1)
#ifdef FLOAT_STORE_FLAG_VALUE
|| (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
x = arg1, reverse_code = 1;
#ifdef FLOAT_STORE_FLAG_VALUE
|| (code == LT
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
&& GET_RTX_CLASS (GET_CODE (p->exp)) == '<'))
#ifdef FLOAT_STORE_FLAG_VALUE
|| (code == GE
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
&& GET_RTX_CLASS (GET_CODE (p->exp)) == '<')
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
- mode);
+ true = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
false = CONST0_RTX (mode);
}
#endif
struct qty_table_elem *ent = &qty_table[qty];
if ((comparison_dominates_p (ent->comparison_code, code)
- || (comparison_dominates_p (ent->comparison_code,
- reverse_condition (code))
- && ! FLOAT_MODE_P (mode_arg0)))
+ || (! FLOAT_MODE_P (mode_arg0)
+ && comparison_dominates_p (ent->comparison_code,
+ reverse_condition (code))))
&& (rtx_equal_p (ent->comparison_const, folded_arg1)
|| (const_arg1
&& rtx_equal_p (ent->comparison_const,
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
- mode);
+ true = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
false = CONST0_RTX (mode);
}
#endif
const_arg1 ? const_arg1 : folded_arg1);
#ifdef FLOAT_STORE_FLAG_VALUE
if (new != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
- new = ((new == const0_rtx) ? CONST0_RTX (mode)
- : CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE, mode));
+ {
+ if (new == const0_rtx)
+ new = CONST0_RTX (mode);
+ else
+ new = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
+ }
#endif
break;
{
reversed_nonequality = (code != EQ && code != NE);
code = reverse_condition (code);
+
+ /* Don't remember if we can't find the inverse. */
+ if (code == UNKNOWN)
+ return;
}
/* The mode is the mode of the non-constant. */
int src_eqv_in_memory = 0;
unsigned src_eqv_hash = 0;
- struct set *sets = NULL_PTR;
+ struct set *sets = (struct set *) NULL_PTR;
this_insn = insn;
trial = gen_rtx_LABEL_REF (Pmode, get_label_after (trial));
- SET_SRC (sets[i].rtl) = trial;
- cse_jumps_altered = 1;
+ if (trial == pc_rtx)
+ {
+ SET_SRC (sets[i].rtl) = trial;
+ cse_jumps_altered = 1;
+ break;
+ }
+
+ /* We must actually validate the change. Consider a target
+ where unconditional jumps are more complex than
+ (set (pc) (label_ref)) such as the fr30. */
+ if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
+ cse_jumps_altered = 1;
break;
}