summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/cse.c71
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20060904-1.c27
4 files changed, 109 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d16697ee748..c690c09f6ae 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2006-09-04 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ 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.
+
2006-09-02 Geoffrey Keating <geoffk@apple.com>
Revert this change:
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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d2ca50ee831..df6d0f9b6ac 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2006-09-04 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ * gcc.c-torture/compile/20060904-1.c: New test.
+
2006-09-04 Nathan Sidwell <nathan@codesourcery.com>
PR c++/23287 Revert my 2006-09-01 patch
diff --git a/gcc/testsuite/gcc.c-torture/compile/20060904-1.c b/gcc/testsuite/gcc.c-torture/compile/20060904-1.c
new file mode 100644
index 00000000000..f9f76866485
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/20060904-1.c
@@ -0,0 +1,27 @@
+/* PR rtl-optimization/27616 */
+/* Reported by Lee Ji Hwan <moonz@kaist.ac.kr> */
+/* Testcase by Andrew Pinski <pinskia@gcc.gnu.org> */
+
+struct chunk_s
+{
+ unsigned int size;
+ int offset_next;
+};
+
+typedef struct chunk_s chunk_t;
+
+void foo(chunk_t *first)
+{
+ chunk_t *cur;
+ char *first0;
+
+ do {
+ first0 = (char *) first;
+ cur = (chunk_t *) (first0 + first->offset_next);
+ if ((chunk_t *) (first0 + cur->offset_next) != first)
+ return ;
+
+ first->offset_next = 0;
+
+ } while (cur->size != 0);
+}