/* Common subexpression elimination for GNU compiler.
- Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992. 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
static int *uid_cuid;
+/* Highest UID in UID_CUID. */
+static int max_uid;
+
/* Get the cuid of an insn. */
#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)])
#endif
/* Compute cost of X, as stored in the `cost' field of a table_elt. Fixed
- hard registers are the cheapest with a cost of 0. Next come pseudos
- with a cost of one and other hard registers with a cost of 2. Aside
- from these special cases, call `rtx_cost'. */
+ hard registers and pointers into the frame are the cheapest with a cost
+ of 0. Next come pseudos with a cost of one and other hard registers with
+ a cost of 2. Aside from these special cases, call `rtx_cost'. */
+
+#define CHEAP_REG(N) \
+ ((N) == FRAME_POINTER_REGNUM || (N) == STACK_POINTER_REGNUM \
+ || (N) == ARG_POINTER_REGNUM \
+ || ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER) \
+ || ((N) < FIRST_PSEUDO_REGISTER \
+ && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
#define COST(X) \
(GET_CODE (X) == REG \
- ? (REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1 \
- : (FIXED_REGNO_P (REGNO (X)) \
- && REGNO_REG_CLASS (REGNO (X)) != NO_REGS) ? 0 \
+ ? (CHEAP_REG (REGNO (X)) ? 0 \
+ : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1 \
: 2) \
: rtx_cost (X, SET) * 2)
int all : 1; /* Invalidate all memory refs. */
};
+/* Define maximum length of a branch path. */
+
+#define PATHLENGTH 10
+
+/* This data describes a block that will be processed by cse_basic_block. */
+
+struct cse_basic_block_data {
+ /* Lowest CUID value of insns in block. */
+ int low_cuid;
+ /* Highest CUID value of insns in block. */
+ int high_cuid;
+ /* Total number of SETs in block. */
+ int nsets;
+ /* Last insn in the block. */
+ rtx last;
+ /* Size of current branch path, if any. */
+ int path_size;
+ /* Current branch path, indicating which branches will be taken. */
+ struct branch_path {
+ /* The branch insn. */
+ rtx branch;
+ /* Whether it should be taken or not. AROUND is the same as taken
+ except that it is used when the destination label is not preceded
+ by a BARRIER. */
+ enum taken {TAKEN, NOT_TAKEN, AROUND} status;
+ } path[PATHLENGTH];
+};
+
/* 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. */
|| XEXP (X, 0) == virtual_stack_dynamic_rtx \
|| XEXP (X, 0) == virtual_outgoing_args_rtx)))
-static struct table_elt *lookup ();
-static void free_element ();
-
-static int insert_regs ();
-static void rehash_using_reg ();
-static void remove_invalid_refs ();
-static int exp_equiv_p ();
-int refers_to_p ();
-int refers_to_mem_p ();
-static void invalidate_from_clobbers ();
-static int safe_hash ();
-static int canon_hash ();
-static rtx fold_rtx ();
-static rtx equiv_constant ();
-static void record_jump_cond ();
-static void note_mem_written ();
-static int cse_rtx_addr_varies_p ();
-static enum rtx_code find_comparison_args ();
-static void cse_insn ();
-static void cse_set_around_loop ();
+static void new_basic_block PROTO((void));
+static void make_new_qty PROTO((int));
+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 *, int));
+static struct table_elt *get_element PROTO((void));
+static struct table_elt *lookup PROTO((rtx, int, enum machine_mode)),
+ *lookup_for_remove PROTO((rtx, int, enum machine_mode));
+static rtx lookup_as_function PROTO((rtx, enum rtx_code));
+static struct table_elt *insert PROTO((rtx, struct table_elt *, int,
+ enum machine_mode));
+static void merge_equiv_classes PROTO((struct table_elt *,
+ struct table_elt *));
+static void invalidate PROTO((rtx));
+static void remove_invalid_refs PROTO((int));
+static void rehash_using_reg PROTO((rtx));
+static void invalidate_memory PROTO((struct write_data *));
+static void invalidate_for_call PROTO((void));
+static rtx use_related_value PROTO((rtx, struct table_elt *));
+static int canon_hash PROTO((rtx, enum machine_mode));
+static int safe_hash PROTO((rtx, enum machine_mode));
+static int exp_equiv_p PROTO((rtx, rtx, int, int));
+static void set_nonvarying_address_components PROTO((rtx, int, rtx *,
+ HOST_WIDE_INT *,
+ HOST_WIDE_INT *));
+static int refers_to_p PROTO((rtx, rtx));
+static int refers_to_mem_p PROTO((rtx, rtx, HOST_WIDE_INT,
+ HOST_WIDE_INT));
+static int cse_rtx_addr_varies_p PROTO((rtx));
+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 cse_gen_binary PROTO((enum rtx_code, enum machine_mode,
+ rtx, rtx));
+static rtx simplify_plus_minus PROTO((enum rtx_code, enum machine_mode,
+ rtx, rtx));
+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, int));
+static void note_mem_written PROTO((rtx, struct write_data *));
+static void invalidate_from_clobbers PROTO((struct write_data *, rtx));
+static rtx cse_process_notes PROTO((rtx, rtx));
+static void cse_around_loop PROTO((rtx));
+static void invalidate_skipped_set PROTO((rtx, rtx));
+static void invalidate_skipped_block PROTO((rtx));
+static void cse_check_loop_start PROTO((rtx, rtx));
+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 *, int));
\f
/* 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.
switch (code)
{
case REG:
- return 1;
+ return ! CHEAP_REG (REGNO (x));
+
case SUBREG:
/* If we can't tie these modes, make this expensive. The larger
the mode, the more expensive it is. */
{
register int regno = REGNO (x);
- if (modified
- || ! (REGNO_QTY_VALID_P (regno)
- && qty_mode[reg_qty[regno]] == GET_MODE (x)))
+ /* If REGNO is in the equivalence table already but is of the
+ wrong mode for that equivalence, don't do anything here. */
+
+ if (REGNO_QTY_VALID_P (regno)
+ && qty_mode[reg_qty[regno]] != GET_MODE (x))
+ return 0;
+
+ if (modified || ! REGNO_QTY_VALID_P (regno))
{
if (classp)
for (classp = classp->first_same_value;
{
register int i;
register struct table_elt *p;
- register rtx base;
- register HOST_WIDE_INT start, end;
+ rtx base;
+ HOST_WIDE_INT start, end;
/* If X is a register, dependencies on its contents
are recorded through the qty number mechanism.
remove_from_table (lookup_for_remove (x, hash, GET_MODE (x)), hash);
else
{
- int in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+ HOST_WIDE_INT in_table
+ = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
int tregno, tendregno;
register struct table_elt *p, *next;
if (GET_CODE (x) != MEM)
abort ();
- base = XEXP (x, 0);
- start = 0;
- /* Registers with nonvarying addresses usually have constant equivalents;
- but the frame pointer register is also possible. */
- if (GET_CODE (base) == REG
- && REGNO_QTY_VALID_P (REGNO (base))
- && qty_mode[reg_qty[REGNO (base)]] == GET_MODE (base)
- && qty_const[reg_qty[REGNO (base)]] != 0)
- base = qty_const[reg_qty[REGNO (base)]];
- else if (GET_CODE (base) == PLUS
- && GET_CODE (XEXP (base, 1)) == CONST_INT
- && GET_CODE (XEXP (base, 0)) == REG
- && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0)))
- && (qty_mode[reg_qty[REGNO (XEXP (base, 0))]]
- == GET_MODE (XEXP (base, 0)))
- && qty_const[reg_qty[REGNO (XEXP (base, 0))]])
- {
- start = INTVAL (XEXP (base, 1));
- base = qty_const[reg_qty[REGNO (XEXP (base, 0))]];
- }
+ set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (GET_MODE (x)),
+ &base, &start, &end);
- if (GET_CODE (base) == CONST)
- base = XEXP (base, 0);
- if (GET_CODE (base) == PLUS
- && GET_CODE (XEXP (base, 1)) == CONST_INT)
- {
- start += INTVAL (XEXP (base, 1));
- base = XEXP (base, 0);
- }
-
- end = start + GET_MODE_SIZE (GET_MODE (x));
for (i = 0; i < NBUCKETS; i++)
{
register struct table_elt *next;
Here we do not require that X or Y be valid (for registers referred to)
for being in the hash table. */
-int
+static int
refers_to_p (x, y)
rtx x, y;
{
return 0;
}
\f
+/* Given ADDR and SIZE (a memory address, and the size of the memory reference),
+ set PBASE, PSTART, and PEND which correspond to the base of the address,
+ the starting offset, and ending offset respectively.
+
+ ADDR is known to be a nonvarying address.
+
+ cse_address_varies_p returns zero for nonvarying addresses. */
+
+static void
+set_nonvarying_address_components (addr, size, pbase, pstart, pend)
+ rtx addr;
+ int size;
+ rtx *pbase;
+ HOST_WIDE_INT *pstart, *pend;
+{
+ rtx base;
+ int start, end;
+
+ base = addr;
+ start = 0;
+ end = 0;
+
+ /* Registers with nonvarying addresses usually have constant equivalents;
+ but the frame pointer register is also possible. */
+ if (GET_CODE (base) == REG
+ && qty_const != 0
+ && REGNO_QTY_VALID_P (REGNO (base))
+ && qty_mode[reg_qty[REGNO (base)]] == GET_MODE (base)
+ && qty_const[reg_qty[REGNO (base)]] != 0)
+ base = qty_const[reg_qty[REGNO (base)]];
+ else if (GET_CODE (base) == PLUS
+ && GET_CODE (XEXP (base, 1)) == CONST_INT
+ && GET_CODE (XEXP (base, 0)) == REG
+ && qty_const != 0
+ && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0)))
+ && (qty_mode[reg_qty[REGNO (XEXP (base, 0))]]
+ == GET_MODE (XEXP (base, 0)))
+ && qty_const[reg_qty[REGNO (XEXP (base, 0))]])
+ {
+ start = INTVAL (XEXP (base, 1));
+ base = qty_const[reg_qty[REGNO (XEXP (base, 0))]];
+ }
+
+ /* By definition, operand1 of a LO_SUM is the associated constant
+ address. Use the associated constant address as the base instead. */
+ if (GET_CODE (base) == LO_SUM)
+ base = XEXP (base, 1);
+
+ /* Strip off CONST. */
+ if (GET_CODE (base) == CONST)
+ base = XEXP (base, 0);
+
+ if (GET_CODE (base) == PLUS
+ && GET_CODE (XEXP (base, 1)) == CONST_INT)
+ {
+ start += INTVAL (XEXP (base, 1));
+ base = XEXP (base, 0);
+ }
+
+ end = start + size;
+
+ /* Set the return values. */
+ *pbase = base;
+ *pstart = start;
+ *pend = end;
+}
+
/* Return 1 iff any subexpression of X refers to memory
at an address of BASE plus some offset
such that any of the bytes' offsets fall between START (inclusive)
and END (exclusive).
- The value is undefined if X is a varying address.
- This function is not used in such cases.
+ The value is undefined if X is a varying address (as determined by
+ cse_rtx_addr_varies_p). This function is not used in such cases.
When used in the cse pass, `qty_const' is nonzero, and it is used
to treat an address that is a register with a known constant value
as if it were that constant value.
In the loop pass, `qty_const' is zero, so this is not done. */
-int
+static int
refers_to_mem_p (x, base, start, end)
rtx x, base;
HOST_WIDE_INT start, end;
if (code == MEM)
{
register rtx addr = XEXP (x, 0); /* Get the address. */
- int myend;
-
- i = 0;
- if (GET_CODE (addr) == REG
- /* qty_const is 0 when outside the cse pass;
- at such times, this info is not available. */
- && qty_const != 0
- && REGNO_QTY_VALID_P (REGNO (addr))
- && GET_MODE (addr) == qty_mode[reg_qty[REGNO (addr)]]
- && qty_const[reg_qty[REGNO (addr)]] != 0)
- addr = qty_const[reg_qty[REGNO (addr)]];
- else if (GET_CODE (addr) == PLUS
- && GET_CODE (XEXP (addr, 1)) == CONST_INT
- && GET_CODE (XEXP (addr, 0)) == REG
- && qty_const != 0
- && REGNO_QTY_VALID_P (REGNO (XEXP (addr, 0)))
- && (GET_MODE (XEXP (addr, 0))
- == qty_mode[reg_qty[REGNO (XEXP (addr, 0))]])
- && qty_const[reg_qty[REGNO (XEXP (addr, 0))]])
- {
- i = INTVAL (XEXP (addr, 1));
- addr = qty_const[reg_qty[REGNO (XEXP (addr, 0))]];
- }
+ rtx mybase;
+ HOST_WIDE_INT mystart, myend;
- check_addr:
- if (GET_CODE (addr) == CONST)
- addr = XEXP (addr, 0);
-
- /* If ADDR is BASE, or BASE plus an integer, put
- the integer in I. */
- if (GET_CODE (addr) == PLUS
- && XEXP (addr, 0) == base
- && GET_CODE (XEXP (addr, 1)) == CONST_INT)
- i += INTVAL (XEXP (addr, 1));
- else if (GET_CODE (addr) == LO_SUM)
- {
- if (GET_CODE (base) != LO_SUM)
- return 1;
- /* The REG component of the LO_SUM is known by the
- const value in the XEXP part. */
- addr = XEXP (addr, 1);
- base = XEXP (base, 1);
- i = 0;
- if (GET_CODE (base) == CONST)
- base = XEXP (base, 0);
- if (GET_CODE (base) == PLUS
- && GET_CODE (XEXP (base, 1)) == CONST_INT)
- {
- HOST_WIDE_INT tem = INTVAL (XEXP (base, 1));
- start += tem;
- end += tem;
- base = XEXP (base, 0);
- }
- goto check_addr;
- }
- else if (GET_CODE (base) == LO_SUM)
- {
- base = XEXP (base, 1);
- if (GET_CODE (base) == CONST)
- base = XEXP (base, 0);
- if (GET_CODE (base) == PLUS
- && GET_CODE (XEXP (base, 1)) == CONST_INT)
- {
- HOST_WIDE_INT tem = INTVAL (XEXP (base, 1));
- start += tem;
- end += tem;
- base = XEXP (base, 0);
- }
- goto check_addr;
- }
- else if (GET_CODE (addr) == CONST_INT && base == const0_rtx)
- i = INTVAL (addr);
- else if (addr != base)
+ set_nonvarying_address_components (addr, GET_MODE_SIZE (GET_MODE (x)),
+ &mybase, &mystart, &myend);
+
+
+ /* refers_to_mem_p is never called with varying addresses.
+ If the base addresses are not equal, there is no chance
+ of the memory addresses conflicting. */
+ if (! rtx_equal_p (mybase, base))
return 0;
- myend = i + GET_MODE_SIZE (GET_MODE (x));
- return myend > start && i < end;
+ return myend > start && mystart < end;
}
/* X does not match, so try its subexpressions. */
with the "oldest" equivalent register.
If INSN is non-zero and we are replacing a pseudo with a hard register
- or vice versa, verify that INSN remains valid after we make our
- substitution. */
+ or vice versa, validate_change is used to ensure that INSN remains valid
+ after we make our substitution. The calls are made with IN_GROUP non-zero
+ so apply_change_group must be called upon the outermost return from this
+ function (unless INSN is zero). The result of apply_change_group can
+ generally be discarded since the changes we are making are optional. */
static rtx
canon_reg (x, insn)
/* If replacing pseudo with hard reg or vice versa, ensure the
insn remains valid. Likewise if the insn has MATCH_DUPs. */
- if (new && GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG
+ if (insn != 0 && new != 0
+ && GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG
&& (((REGNO (new) < FIRST_PSEUDO_REGISTER)
!= (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER))
- || (insn != 0 && insn_n_dups[recog_memoized (insn)] > 0)))
+ || insn_n_dups[recog_memoized (insn)] > 0))
validate_change (insn, &XEXP (x, i), new, 1);
else
XEXP (x, i) = new;
than hard registers here because we would also prefer the pseudo registers.
*/
-void
+static void
find_best_addr (insn, loc)
rtx insn;
rtx *loc;
&& (GET_CODE (p->exp) == REG
|| exp_equiv_p (p->exp, p->exp, 1, 0)))
{
- rtx new = simplify_binary_operation (GET_CODE (*loc), Pmode,
- p->exp, c);
-
- if (new == 0)
- new = gen_rtx (GET_CODE (*loc), Pmode, p->exp, c);
+ rtx new = cse_gen_binary (GET_CODE (*loc), Pmode, p->exp, c);
if ((ADDRESS_COST (new) < best_addr_cost
|| (ADDRESS_COST (new) == best_addr_cost
break;
case FLOAT_TRUNCATE:
- d = (double) real_value_truncate (mode, d);
+ d = real_value_truncate (mode, d);
break;
case FLOAT_EXTEND:
break;
case FIX:
- d = (double) REAL_VALUE_FIX_TRUNCATE (d);
+ d = REAL_VALUE_RNDZINT (d);
break;
case UNSIGNED_FIX:
- d = (double) REAL_VALUE_UNSIGNED_FIX_TRUNCATE (d);
+ d = REAL_VALUE_UNSIGNED_RNDZINT (d);
break;
case SQRT:
register HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
HOST_WIDE_INT val;
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.
f1 = real_value_truncate (mode, f1);
#ifdef REAL_ARITHMETIC
- REAL_ARITHMETIC (value, code, f0, f1);
+ REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
#else
switch (code)
{
value = real_value_truncate (mode, value);
return immed_real_const_1 (value, mode);
}
+#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
/* We can fold some multi-word operations. */
- else if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_CODE (op0) == CONST_DOUBLE
- && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_CODE (op0) == CONST_DOUBLE
+ && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
{
HOST_WIDE_INT l1, l2, h1, h2, lv, hv;
return immed_double_const (lv, hv, mode);
}
-#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
|| width > HOST_BITS_PER_WIDE_INT || width == 0)
if (op1 == CONST0_RTX (mode))
return op0;
- /* Strip off any surrounding CONSTs. They don't matter in any of
- the cases below. */
- if (GET_CODE (op0) == CONST)
- op0 = XEXP (op0, 0);
- if (GET_CODE (op1) == CONST)
- op1 = XEXP (op1, 0);
-
/* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */
if (GET_CODE (op0) == NEG)
- {
- rtx tem = simplify_binary_operation (MINUS, mode,
- op1, XEXP (op0, 0));
- return tem ? tem : gen_rtx (MINUS, mode, op1, XEXP (op0, 0));
- }
+ return cse_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
else if (GET_CODE (op1) == NEG)
- {
- rtx tem = simplify_binary_operation (MINUS, mode,
- op0, XEXP (op1, 0));
- return tem ? tem : gen_rtx (MINUS, mode, op0, XEXP (op1, 0));
- }
+ return cse_gen_binary (MINUS, mode, op0, XEXP (op1, 0));
- /* Don't use the associative law for floating point.
- The inaccuracy makes it nonassociative,
- and subtle programs can break if operations are associated. */
- if (GET_MODE_CLASS (mode) != MODE_INT)
- break;
-
- /* (a - b) + b -> a, similarly a + (b - a) -> a */
- if (GET_CODE (op0) == MINUS
- && rtx_equal_p (XEXP (op0, 1), op1) && ! side_effects_p (op1))
- return XEXP (op0, 0);
-
- if (GET_CODE (op1) == MINUS
- && rtx_equal_p (XEXP (op1, 1), op0) && ! side_effects_p (op0))
- return 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. */
- /* (c1 - a) + c2 becomes (c1 + c2) - a. */
- if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == MINUS
- && GET_CODE (XEXP (op0, 0)) == CONST_INT)
- {
- rtx tem = simplify_binary_operation (PLUS, mode, op1,
- XEXP (op0, 0));
+ if (CONSTANT_P (op0) && GET_CODE (op1) == CONST_INT)
+ return plus_constant (op0, INTVAL (op1));
+ else if (CONSTANT_P (op1) && GET_CODE (op0) == CONST_INT)
+ return plus_constant (op1, INTVAL (op0));
- return tem ? gen_rtx (MINUS, mode, tem, XEXP (op0, 1)) : 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. */
- /* Handle both-operands-constant cases. */
- if (CONSTANT_P (op0) && CONSTANT_P (op1)
- && GET_CODE (op0) != CONST_DOUBLE
- && GET_CODE (op1) != CONST_DOUBLE
- && GET_MODE_CLASS (mode) == MODE_INT)
- {
- if (GET_CODE (op1) == CONST_INT)
- return plus_constant (op0, INTVAL (op1));
- else if (GET_CODE (op0) == CONST_INT)
- return plus_constant (op1, INTVAL (op0));
- else
- break;
-#if 0 /* No good, because this can produce the sum of two relocatable
- symbols, in an assembler instruction. Most UNIX assemblers can't
- handle that. */
- else
- return gen_rtx (CONST, mode,
- gen_rtx (PLUS, mode,
- GET_CODE (op0) == CONST
- ? XEXP (op0, 0) : op0,
- GET_CODE (op1) == CONST
- ? XEXP (op1, 0) : op1));
-#endif
- }
- else if (GET_CODE (op1) == CONST_INT
- && GET_CODE (op0) == PLUS
- && (CONSTANT_P (XEXP (op0, 0))
- || CONSTANT_P (XEXP (op0, 1))))
- /* constant + (variable + constant)
- can result if an index register is made constant.
- We simplify this by adding the constants.
- If we did not, it would become an invalid address. */
- return plus_constant (op0, INTVAL (op1));
+ if ((GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+ && (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:
/* None of these optimizations can be done for IEEE
floating point. */
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && GET_MODE_CLASS (mode) != MODE_INT)
+ && GET_MODE_CLASS (mode) != MODE_INT
+ && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
break;
/* We can't assume x-x is 0 even with non-IEEE floating point. */
if (rtx_equal_p (op0, op1)
&& ! side_effects_p (op0)
- && GET_MODE_CLASS (mode) != MODE_FLOAT)
+ && GET_MODE_CLASS (mode) != MODE_FLOAT
+ && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
return const0_rtx;
/* 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;
- /* Strip off any surrounding CONSTs. They don't matter in any of
- the cases below. */
- if (GET_CODE (op0) == CONST)
- op0 = XEXP (op0, 0);
- if (GET_CODE (op1) == CONST)
- op1 = XEXP (op1, 0);
-
/* (a - (-b)) -> (a + b). */
if (GET_CODE (op1) == NEG)
- {
- rtx tem = simplify_binary_operation (PLUS, mode,
- op0, XEXP (op1, 0));
- return tem ? tem : gen_rtx (PLUS, mode, op0, XEXP (op1, 0));
- }
+ return cse_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
- /* Don't use the associative law for floating point.
+ /* 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 (GET_MODE_CLASS (mode) != MODE_INT)
- break;
-
- /* (a + b) - a -> b, and (b - (a + b)) -> -a */
- if (GET_CODE (op0) == PLUS
- && rtx_equal_p (XEXP (op0, 0), op1)
- && ! side_effects_p (op1))
- return XEXP (op0, 1);
- else if (GET_CODE (op0) == PLUS
- && rtx_equal_p (XEXP (op0, 1), op1)
- && ! side_effects_p (op1))
- return XEXP (op0, 0);
-
- if (GET_CODE (op1) == PLUS
- && rtx_equal_p (XEXP (op1, 0), op0)
- && ! side_effects_p (op0))
- {
- rtx tem = simplify_unary_operation (NEG, mode, XEXP (op1, 1),
- mode);
-
- return tem ? tem : gen_rtx (NEG, mode, XEXP (op1, 1));
- }
- else if (GET_CODE (op1) == PLUS
- && rtx_equal_p (XEXP (op1, 1), op0)
- && ! side_effects_p (op0))
- {
- rtx tem = simplify_unary_operation (NEG, mode, XEXP (op1, 0),
- mode);
-
- return tem ? tem : gen_rtx (NEG, mode, XEXP (op1, 0));
- }
-
- /* a - (a - b) -> b */
- if (GET_CODE (op1) == MINUS && rtx_equal_p (op0, XEXP (op1, 0))
- && ! side_effects_p (op0))
- return XEXP (op1, 1);
-
- /* (a +/- b) - (a +/- c) can be simplified. Do variants of
- this involving commutativity. The most common case is
- (a + C1) - (a + C2), but it's not hard to do all the cases. */
- if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS)
- && (GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS))
- {
- rtx lhs0 = XEXP (op0, 0), lhs1 = XEXP (op0, 1);
- rtx rhs0 = XEXP (op1, 0), rhs1 = XEXP (op1, 1);
- int lhs_neg = GET_CODE (op0) == MINUS;
- int rhs_neg = GET_CODE (op1) == MINUS;
- rtx lhs = 0, rhs = 0;
-
- /* Set LHS and RHS to the two different terms. */
- if (rtx_equal_p (lhs0, rhs0) && ! side_effects_p (lhs0))
- lhs = lhs1, rhs = rhs1;
- else if (! rhs_neg && rtx_equal_p (lhs0, rhs1)
- && ! side_effects_p (lhs0))
- lhs = lhs1, rhs = rhs0;
- else if (! lhs_neg && rtx_equal_p (lhs1, rhs0)
- && ! side_effects_p (lhs1))
- lhs = lhs0, rhs = rhs1;
- else if (! lhs_neg && ! rhs_neg && rtx_equal_p (lhs1, rhs1)
- && ! side_effects_p (lhs1))
- lhs = lhs0, rhs = rhs0;
-
- /* The RHS is the operand of a MINUS, so its negation
- status should be complemented. */
- rhs_neg = ! rhs_neg;
-
- /* If we found two values equal, form the sum or difference
- of the remaining two terms. */
- if (lhs)
- {
- rtx tem = simplify_binary_operation (lhs_neg == rhs_neg
- ? PLUS : MINUS,
- mode,
- lhs_neg ? rhs : lhs,
- lhs_neg ? lhs : rhs);
- if (tem == 0)
- tem = gen_rtx (lhs_neg == rhs_neg
- ? PLUS : MINUS,
- mode, lhs_neg ? rhs : lhs,
- lhs_neg ? lhs : rhs);
-
- /* If both sides negated, negate result. */
- if (lhs_neg && rhs_neg)
- {
- rtx tem1
- = simplify_unary_operation (NEG, mode, tem, mode);
- if (tem1 == 0)
- tem1 = gen_rtx (NEG, mode, tem);
- tem = tem1;
- }
-
- return tem;
- }
-
- return 0;
- }
-
- /* c1 - (a + c2) becomes (c1 - c2) - a. */
- if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == PLUS
- && GET_CODE (XEXP (op1, 1)) == CONST_INT)
- {
- rtx tem = simplify_binary_operation (MINUS, mode, op0,
- XEXP (op1, 1));
- return tem ? gen_rtx (MINUS, mode, tem, XEXP (op1, 0)) : 0;
- }
-
- /* c1 - (c2 - a) becomes (c1 - c2) + a. */
- if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == MINUS
- && GET_CODE (XEXP (op1, 0)) == CONST_INT)
- {
- rtx tem = simplify_binary_operation (MINUS, mode, op0,
- XEXP (op1, 0));
-
- return (tem && GET_CODE (tem) == CONST_INT
- ? plus_constant (XEXP (op1, 1), INTVAL (tem))
- : 0);
- }
+ if ((GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+ && (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)
case MULT:
if (op1 == constm1_rtx)
{
- rtx tem = simplify_unary_operation (NEG, mode, op0, mode);
+ tem = simplify_unary_operation (NEG, mode, op0, mode);
return tem ? tem : gen_rtx (NEG, mode, op0);
}
&& 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 (REAL_VALUES_EQUAL (d, dconst2)
- && GET_MODE (op0) == mode)
+ if (op1is2 && GET_MODE (op0) == mode)
return gen_rtx (PLUS, mode, op0, copy_rtx (op0));
- else if (REAL_VALUES_EQUAL (d, dconstm1)
- && GET_MODE (op0) == mode)
+ else if (op1ism1 && GET_MODE (op0) == mode)
return gen_rtx (NEG, mode, op0);
}
break;
/* 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))
+ && ! side_effects_p (op0)
+ && GET_MODE_CLASS (mode) != MODE_CC)
return constm1_rtx;
break;
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))
+ if (op0 == op1 && ! side_effects_p (op0)
+ && GET_MODE_CLASS (mode) != MODE_CC)
return const0_rtx;
break;
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))
+ 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))
+ && ! side_effects_p (op0)
+ && GET_MODE_CLASS (mode) != MODE_CC)
return const0_rtx;
break;
if (REAL_VALUES_EQUAL (d, dconst0))
abort();
#if defined (REAL_ARITHMETIC)
- REAL_ARITHMETIC (d, RDIV_EXPR, dconst1, d);
+ REAL_ARITHMETIC (d, (int) RDIV_EXPR, dconst1, d);
return gen_rtx (MULT, mode, op0,
CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
#else
case SMAX:
if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
- && INTVAL (op1) == GET_MODE_MASK (mode) >> 1
+ && (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 0;
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:
return GEN_INT (val);
}
\f
+/* 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;
+
+ bzero (ops, 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;
+ }
+ }
+
+ /* 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 = cse_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]);
+
+ return negate ? gen_rtx (NEG, mode, result) : result;
+}
+\f
+/* Make a binary operation by properly ordering the operands and
+ seeing if the expression folds. */
+
+static rtx
+cse_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 (code, mode, op0, op1);
+}
+\f
/* Like simplify_binary_operation except used for relational operators.
MODE is the mode of the operands, not that of the result. */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
- if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
- || width > HOST_BITS_PER_WIDE_INT || width == 0)
+ /* What to do with MODE_CC isn't clear yet.
+ Let's make sure nothing erroneous is done. */
+ if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
+ return 0;
+
+ /* Unlike the arithmetic operations, we can do the comparison whether
+ or not WIDTH is larger than HOST_BITS_PER_WIDE_INT because the
+ CONST_INTs are to be understood as being infinite precision as
+ is the comparison. So there is no question of overflow. */
+
+ if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT || width == 0)
{
/* Even if we can't compute a constant result,
there are some cases worth simplifying. */
|| GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT))
return (code == EQ || code == GE || code == LE || code == LEU
|| code == GEU) ? const_true_rtx : const0_rtx;
+
+#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)
return op1lt ? const_true_rtx : const0_rtx;
}
}
-
+#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
+
+ else if (GET_MODE_CLASS (mode) == MODE_INT
+ && width > HOST_BITS_PER_WIDE_INT
+ && (GET_CODE (op0) == CONST_DOUBLE
+ || GET_CODE (op0) == CONST_INT)
+ && (GET_CODE (op1) == CONST_DOUBLE
+ || GET_CODE (op1) == CONST_INT))
+ {
+ HOST_WIDE_INT h0, l0, h1, l1;
+ unsigned HOST_WIDE_INT uh0, ul0, uh1, ul1;
+ int op0lt, op0ltu, equal;
+
+ if (GET_CODE (op0) == CONST_DOUBLE)
+ l0 = CONST_DOUBLE_LOW (op0), h0 = CONST_DOUBLE_HIGH (op0);
+ else
+ l0 = INTVAL (op0), h0 = l0 < 0 ? -1 : 0;
+
+ if (GET_CODE (op1) == CONST_DOUBLE)
+ l1 = CONST_DOUBLE_LOW (op1), h1 = CONST_DOUBLE_HIGH (op1);
+ else
+ l1 = INTVAL (op1), h1 = l1 < 0 ? -1 : 0;
+
+ uh0 = h0, ul0 = l0, uh1 = h1, ul1 = l1;
+
+ equal = (h0 == h1 && l0 == l1);
+ op0lt = (h0 < h1 || (h0 == h1 && l0 < l1));
+ op0ltu = (uh0 < uh1 || (uh0 == uh1 && ul0 < ul1));
+
+ switch (code)
+ {
+ case EQ:
+ return equal ? const_true_rtx : const0_rtx;
+ case NE:
+ return !equal ? const_true_rtx : const0_rtx;
+ case LE:
+ return equal || op0lt ? const_true_rtx : const0_rtx;
+ case LT:
+ return op0lt ? const_true_rtx : const0_rtx;
+ case GE:
+ return !op0lt ? const_true_rtx : const0_rtx;
+ case GT:
+ return !equal && !op0lt ? const_true_rtx : const0_rtx;
+ case LEU:
+ return equal || op0ltu ? const_true_rtx : const0_rtx;
+ case LTU:
+ return op0ltu ? const_true_rtx : const0_rtx;
+ case GEU:
+ return !op0ltu ? const_true_rtx : const0_rtx;
+ case GTU:
+ return !equal && !op0ltu ? const_true_rtx : const0_rtx;
+ }
+ }
+
switch (code)
{
case EQ:
modified by recursive calls to this function.
If X is a register whose contents are known, we do NOT
- return those contents. This is because an instruction that
- uses a register is usually faster than one that uses a constant.
+ return those contents here. equiv_constant is called to
+ perform that task.
INSN is the insn that we may be modifying. If it is 0, make a copy
of X before modifying it. */
{
rtx y = lookup_as_function (XEXP (x, 0), PLUS);
if (y && GET_CODE (XEXP (y, 1)) == CONST_INT)
- return fold_rtx (plus_constant (y, -INTVAL (const_arg1)));
+ return fold_rtx (plus_constant (y, -INTVAL (const_arg1)),
+ NULL_RTX);
}
/* ... fall through ... */
if (! reg_mentioned_p (folded_arg0, y))
y = fold_rtx (y, insn);
- new = simplify_binary_operation (code, mode, y, new_const);
- if (new)
- return new;
-
- return gen_rtx (code, mode, y, new_const);
+ return cse_gen_binary (code, mode, y, new_const);
}
}
true for all smaller modes whether or not there is a SUBREG, but
is not worth testing for with no SUBREG. */
+ /* Note that GET_MODE (op0) may not equal MODE. */
if (code == EQ && GET_CODE (op0) == SUBREG
- && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))
+ && (GET_MODE_SIZE (GET_MODE (op0))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
rtx tem = gen_lowpart_if_possible (inner_mode, op1);
}
if (code == EQ && GET_CODE (op1) == SUBREG
- && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))))
+ && (GET_MODE_SIZE (GET_MODE (op1))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
rtx tem = gen_lowpart_if_possible (inner_mode, op0);
/* Similarly, if this is an NE comparison, and either is a SUBREG
making a smaller mode, we know the whole thing is also NE. */
+ /* Note that GET_MODE (op0) may not equal MODE;
+ if we test MODE instead, we can get an infinite recursion
+ alternating between two modes each wider than MODE. */
+
if (code == NE && GET_CODE (op0) == SUBREG
&& subreg_lowpart_p (op0)
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))
+ && (GET_MODE_SIZE (GET_MODE (op0))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
rtx tem = gen_lowpart_if_possible (inner_mode, op1);
if (code == NE && GET_CODE (op1) == SUBREG
&& subreg_lowpart_p (op1)
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))))
+ && (GET_MODE_SIZE (GET_MODE (op1))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
rtx tem = gen_lowpart_if_possible (inner_mode, op0);
The hard function value register is used only once, to copy to
someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)!
Ensure we invalidate the destination register. On the 80386 no
- other code would invalidate it since it is a fixed_reg. */
+ other code would invalidate it since it is a fixed_reg.
+ We need not check the return of apply_change_group; see canon_reg. */
else if (GET_CODE (SET_SRC (x)) == CALL)
{
register rtx y = XVECEXP (x, 0, i);
if (GET_CODE (y) == SET)
{
- /* As above, we ignore unconditional jumps and call-insns. */
+ /* As above, we ignore unconditional jumps and call-insns and
+ ignore the result of apply_change_group. */
if (GET_CODE (SET_SRC (y)) == CALL)
{
canon_reg (SET_SRC (y), insn);
canon_reg (y, NULL_RTX);
else if (GET_CODE (y) == CALL)
{
+ /* The result of apply_change_group can be ignored; see
+ canon_reg. */
canon_reg (y, insn);
apply_change_group ();
fold_rtx (y, insn);
canon_reg (XEXP (x, 0), NULL_RTX);
else if (GET_CODE (x) == CALL)
{
+ /* The result of apply_change_group can be ignored; see canon_reg. */
canon_reg (x, insn);
apply_change_group ();
fold_rtx (x, insn);
group and see if they all work. Note that this will cause some
canonicalizations that would have worked individually not to be applied
because some other canonicalization didn't work, but this should not
- occur often. */
+ occur often.
+
+ The result of apply_change_group can be ignored; see canon_reg. */
apply_change_group ();
/* Look for a substitution that makes a valid insn. */
else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
{
- SET_SRC (sets[i].rtl) = canon_reg (SET_SRC (sets[i].rtl), insn);
+ /* The result of apply_change_group can be ignored; see
+ canon_reg. */
+
+ validate_change (insn, &SET_SRC (sets[i].rtl),
+ canon_reg (SET_SRC (sets[i].rtl), insn),
+ 1);
+ apply_change_group ();
break;
}
delete_insn (insn);
insn = new;
}
+ else
+ /* Otherwise, force rerecognition, since it probably had
+ a different pattern before.
+ This shouldn't really be necessary, since whatever
+ changed the source value above should have done this.
+ Until the right place is found, might as well do this here. */
+ INSN_CODE (insn) = -1;
/* Now that we've converted this jump to an unconditional jump,
there is dead code after it. Delete the dead code until we
{
/* A varying address that is a sum indicates an array element,
and that's just as good as a structure element
- in implying that we need not invalidate scalar variables. */
- if (!(MEM_IN_STRUCT_P (written)
- || GET_CODE (XEXP (written, 0)) == PLUS))
+ in implying that we need not invalidate scalar variables.
+ However, we must allow QImode aliasing of scalars, because the
+ ANSI C standard allows character pointers to alias anything. */
+ if (! ((MEM_IN_STRUCT_P (written)
+ || GET_CODE (XEXP (written, 0)) == PLUS)
+ && GET_MODE (written) != QImode))
writes_ptr->all = 1;
writes_ptr->nonscalar = 1;
}
for (i = 0; i < GET_RTX_LENGTH (code); i++)
if (fmt[i] == 'e')
validate_change (object, &XEXP (x, i),
- cse_process_notes (XEXP (x, i), object), NULL_RTX);
+ cse_process_notes (XEXP (x, i), object), 0);
return x;
}
the current block. The incoming structure's branch path, if any, is used
to construct the output branch path. */
-/* Define maximum length of a branch path. */
-
-#define PATHLENGTH 10
-
-struct cse_basic_block_data {
- /* Lowest CUID value of insns in block. */
- int low_cuid;
- /* Highest CUID value of insns in block. */
- int high_cuid;
- /* Total number of SETs in block. */
- int nsets;
- /* Last insn in the block. */
- rtx last;
- /* Size of current branch path, if any. */
- int path_size;
- /* Current branch path, indicating which branches will be taken. */
- struct branch_path {
- /* The branch insn. */
- rtx branch;
- /* Whether it should be taken or not. AROUND is the same as taken
- except that it is used when the destination label is not preceded
- by a BARRIER. */
- enum taken {TAKEN, NOT_TAKEN, AROUND} status;
- } path[PATHLENGTH];
-};
-
void
cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
rtx insn;
else if (GET_CODE (p) != NOTE)
nsets += 1;
- if (INSN_CUID (p) > high_cuid)
+ /* Ignore insns made by CSE; they cannot affect the boundaries of
+ the basic block. */
+
+ if (INSN_UID (p) <= max_uid && INSN_CUID (p) > high_cuid)
high_cuid = INSN_CUID (p);
- if (INSN_CUID (p) < low_cuid)
- low_cuid = INSN_CUID(p);
+ if (INSN_UID (p) <= max_uid && INSN_CUID (p) < low_cuid)
+ low_cuid = INSN_CUID (p);
/* See if this insn is in our branch path. If it is and we are to
take it, do so. */
data->path[path_size].branch = 0;
}
\f
-static rtx cse_basic_block ();
-
/* Perform cse on the instructions of a function.
F is the first instruction.
NREGS is one plus the highest pseudo-reg number used in the instruction.
/* Find the largest uid. */
- i = get_max_uid ();
- uid_cuid = (int *) alloca ((i + 1) * sizeof (int));
- bzero (uid_cuid, (i + 1) * sizeof (int));
+ max_uid = get_max_uid ();
+ uid_cuid = (int *) alloca ((max_uid + 1) * sizeof (int));
+ bzero (uid_cuid, (max_uid + 1) * sizeof (int));
/* Compute the mapping from uids to cuids.
CUIDs are numbers assigned to insns, like uids,