diff options
author | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-09-04 19:33:24 +0000 |
---|---|---|
committer | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-09-04 19:33:24 +0000 |
commit | 8f353ea893836fad10df5e0d9ce69e816ed0e722 (patch) | |
tree | ce136ce4de60baf3887aab1aea174d9a6a8969d1 /gcc/cse.c | |
parent | 51ab7e353a3119ea190108e82857bdb7008b4eac (diff) | |
download | gcc-8f353ea893836fad10df5e0d9ce69e816ed0e722.tar.gz |
PR rtl-optimization/27616
* cse.c (table_size): New static variable.
(new_basic_block): Initialize it to 0.
(remove_from_table): Decrement it.
(insert): Increment it.
(fold_rtx_mem_1): New function, renamed from fold_rtx_mem.
(fold_rtx_mem): Enforce a cap on the recursion depth. Call
fold_rtx_mem_1 if under the cap.
(fold_rtx) <RTX_COMM_ARITH>: In the associative case, delay a little
the lookup of the equivalent expression and test for equality of the
first operand of the equivalent expression before in turn looking up
an equivalent constant for the second operand.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@116683 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cse.c')
-rw-r--r-- | gcc/cse.c | 71 |
1 files changed, 63 insertions, 8 deletions
diff --git a/gcc/cse.c b/gcc/cse.c index fc15511dbc8..0304d6f763f 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -528,6 +528,10 @@ struct table_elt static struct table_elt *table[HASH_SIZE]; +/* Number of elements in the hash table. */ + +static unsigned int table_size; + /* Chain of `struct table_elt's made so far for this function but currently removed from the table. */ @@ -961,6 +965,8 @@ new_basic_block (void) } } + table_size = 0; + #ifdef HAVE_cc0 prev_insn = 0; prev_insn_cc0 = 0; @@ -1371,6 +1377,8 @@ remove_from_table (struct table_elt *elt, unsigned int hash) /* Now add it to the free element chain. */ elt->next_same_hash = free_element_chain; free_element_chain = elt; + + table_size--; } /* Look up X in the hash table and return its table element, @@ -1648,6 +1656,8 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo } } + table_size++; + return elt; } @@ -3432,10 +3442,10 @@ fold_rtx_subreg (rtx x, rtx insn) return x; } -/* Fold MEM. */ +/* Fold MEM. Not to be called directly, see fold_rtx_mem instead. */ static rtx -fold_rtx_mem (rtx x, rtx insn) +fold_rtx_mem_1 (rtx x, rtx insn) { enum machine_mode mode = GET_MODE (x); rtx new; @@ -3598,6 +3608,51 @@ fold_rtx_mem (rtx x, rtx insn) } } +/* Fold MEM. */ + +static rtx +fold_rtx_mem (rtx x, rtx insn) +{ + /* To avoid infinite oscillations between fold_rtx and fold_rtx_mem, + refuse to allow recursion of the latter past n levels. This can + happen because fold_rtx_mem will try to fold the address of the + memory reference it is passed, i.e. conceptually throwing away + the MEM and reinjecting the bare address into fold_rtx. As a + result, patterns like + + set (reg1) + (plus (reg) + (mem (plus (reg2) (const_int)))) + + set (reg2) + (plus (reg) + (mem (plus (reg1) (const_int)))) + + will defeat any "first-order" short-circuit put in either + function to prevent these infinite oscillations. + + The heuristics for determining n is as follows: since each time + it is invoked fold_rtx_mem throws away a MEM, and since MEMs + are generically not nested, we assume that each invocation of + fold_rtx_mem corresponds to a new "top-level" operand, i.e. + the source or the destination of a SET. So fold_rtx_mem is + bound to stop or cycle before n recursions, n being the number + of expressions recorded in the hash table. We also leave some + play to account for the initial steps. */ + + static unsigned int depth; + rtx ret; + + if (depth > 3 + table_size) + return x; + + depth++; + ret = fold_rtx_mem_1 (x, insn); + depth--; + + return ret; +} + /* If X is a nontrivial arithmetic operation on an argument for which a constant value can be determined, return the result of operating on that value, as a constant. @@ -4262,10 +4317,8 @@ fold_rtx (rtx x, rtx insn) { int is_shift = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT); - rtx y = lookup_as_function (folded_arg0, code); - rtx inner_const; + rtx y, inner_const, new_const; enum rtx_code associate_code; - rtx new_const; if (is_shift && (INTVAL (const_arg1) >= GET_MODE_BITSIZE (mode) @@ -4278,11 +4331,9 @@ fold_rtx (rtx x, rtx insn) break; } + y = lookup_as_function (folded_arg0, code); if (y == 0) break; - inner_const = equiv_constant (fold_rtx (XEXP (y, 1), 0)); - if (!inner_const || GET_CODE (inner_const) != CONST_INT) - break; /* If we have compiled a statement like "if (x == (x & mask1))", and now are looking at @@ -4292,6 +4343,10 @@ fold_rtx (rtx x, rtx insn) if (XEXP (y, 0) == folded_arg0) break; + inner_const = equiv_constant (fold_rtx (XEXP (y, 1), 0)); + if (!inner_const || GET_CODE (inner_const) != CONST_INT) + break; + /* Don't associate these operations if they are a PLUS with the same constant and it is a power of two. These might be doable with a pre- or post-increment. Similarly for two subtracts of |