aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernd Edlinger <bernd.edlinger@hotmail.de>2015-07-01 16:10:30 +0000
committerBernd Edlinger <edlinger@gcc.gnu.org>2015-07-01 16:10:30 +0000
commit1e67793833846d12abe78f4291a07773d2f13a04 (patch)
treead11a1fdf4189e71a1e3553b55648b9be30389dc
parent2ee05f1e9be5f02d4c874262d27e1eff96a301f0 (diff)
downloadgcc-1e67793833846d12abe78f4291a07773d2f13a04.zip
gcc-1e67793833846d12abe78f4291a07773d2f13a04.tar.gz
gcc-1e67793833846d12abe78f4291a07773d2f13a04.tar.bz2
re PR rtl-optimization/61047 (wrong code at -O1 on x86_64-linux)
gcc/ChangeLog: 2015-07-01 Bernd Edlinger <bernd.edlinger@hotmail.de> PR rtl-optimization/61047 * rtlanal.c (get_initial_register_offset): New function. (rtx_addr_can_trap_p_1): Check offsets of stack references. testsuite/ChangeLog: 2015-07-01 Bernd Edlinger <bernd.edlinger@hotmail.de> PR rtl-optimization/61047 * gcc.c-torture/execute/20150611-1.c: New testcase. From-SVN: r225260
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/rtlanal.c247
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20150611-1.c18
4 files changed, 262 insertions, 14 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f53f378..48e9159 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2015-07-01 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR rtl-optimization/61047
+ * rtlanal.c (get_initial_register_offset): New function.
+ (rtx_addr_can_trap_p_1): Check offsets of stack references.
+
2015-07-01 Richard Biener <rguenther@suse.de>
* fold-const.c (fold_comparison): Move X - Y CMP 0 -> X CMP Y,
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 86b3b62..65962e8 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -345,6 +345,145 @@ rtx_varies_p (const_rtx x, bool for_alias)
return 0;
}
+/* Compute an approximation for the offset between the register
+ FROM and TO for the current function, as it was at the start
+ of the routine. */
+
+static HOST_WIDE_INT
+get_initial_register_offset (int from, int to)
+{
+#ifdef ELIMINABLE_REGS
+ static const struct elim_table_t
+ {
+ const int from;
+ const int to;
+ } table[] = ELIMINABLE_REGS;
+ HOST_WIDE_INT offset1, offset2;
+ unsigned int i, j;
+
+ if (to == from)
+ return 0;
+
+ /* It is not safe to call INITIAL_ELIMINATION_OFFSET
+ before the reload pass. We need to give at least
+ an estimation for the resulting frame size. */
+ if (! reload_completed)
+ {
+ offset1 = crtl->outgoing_args_size + get_frame_size ();
+#if !STACK_GROWS_DOWNWARD
+ offset1 = - offset1;
+#endif
+ if (to == STACK_POINTER_REGNUM)
+ return offset1;
+ else if (from == STACK_POINTER_REGNUM)
+ return - offset1;
+ else
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE (table); i++)
+ if (table[i].from == from)
+ {
+ if (table[i].to == to)
+ {
+ INITIAL_ELIMINATION_OFFSET (table[i].from, table[i].to,
+ offset1);
+ return offset1;
+ }
+ for (j = 0; j < ARRAY_SIZE (table); j++)
+ {
+ if (table[j].to == to
+ && table[j].from == table[i].to)
+ {
+ INITIAL_ELIMINATION_OFFSET (table[i].from, table[i].to,
+ offset1);
+ INITIAL_ELIMINATION_OFFSET (table[j].from, table[j].to,
+ offset2);
+ return offset1 + offset2;
+ }
+ if (table[j].from == to
+ && table[j].to == table[i].to)
+ {
+ INITIAL_ELIMINATION_OFFSET (table[i].from, table[i].to,
+ offset1);
+ INITIAL_ELIMINATION_OFFSET (table[j].from, table[j].to,
+ offset2);
+ return offset1 - offset2;
+ }
+ }
+ }
+ else if (table[i].to == from)
+ {
+ if (table[i].from == to)
+ {
+ INITIAL_ELIMINATION_OFFSET (table[i].from, table[i].to,
+ offset1);
+ return - offset1;
+ }
+ for (j = 0; j < ARRAY_SIZE (table); j++)
+ {
+ if (table[j].to == to
+ && table[j].from == table[i].from)
+ {
+ INITIAL_ELIMINATION_OFFSET (table[i].from, table[i].to,
+ offset1);
+ INITIAL_ELIMINATION_OFFSET (table[j].from, table[j].to,
+ offset2);
+ return - offset1 + offset2;
+ }
+ if (table[j].from == to
+ && table[j].to == table[i].from)
+ {
+ INITIAL_ELIMINATION_OFFSET (table[i].from, table[i].to,
+ offset1);
+ INITIAL_ELIMINATION_OFFSET (table[j].from, table[j].to,
+ offset2);
+ return - offset1 - offset2;
+ }
+ }
+ }
+
+ /* If the requested register combination was not found,
+ try a different more simple combination. */
+ if (from == ARG_POINTER_REGNUM)
+ return get_initial_register_offset (HARD_FRAME_POINTER_REGNUM, to);
+ else if (to == ARG_POINTER_REGNUM)
+ return get_initial_register_offset (from, HARD_FRAME_POINTER_REGNUM);
+ else if (from == HARD_FRAME_POINTER_REGNUM)
+ return get_initial_register_offset (FRAME_POINTER_REGNUM, to);
+ else if (to == HARD_FRAME_POINTER_REGNUM)
+ return get_initial_register_offset (from, FRAME_POINTER_REGNUM);
+ else
+ return 0;
+
+#else
+ HOST_WIDE_INT offset;
+
+ if (to == from)
+ return 0;
+
+ if (reload_completed)
+ {
+ INITIAL_FRAME_POINTER_OFFSET (offset);
+ }
+ else
+ {
+ offset = crtl->outgoing_args_size + get_frame_size ();
+#if !STACK_GROWS_DOWNWARD
+ offset = - offset;
+#endif
+ }
+
+ if (to == STACK_POINTER_REGNUM)
+ return offset;
+ else if (from == STACK_POINTER_REGNUM)
+ return - offset;
+ else
+ return 0;
+
+#endif
+}
+
/* Return nonzero if the use of X+OFFSET as an address in a MEM with SIZE
bytes can cause a trap. MODE is the mode of the MEM (not that of X) and
UNALIGNED_MEMS controls whether nonzero is returned for unaligned memory
@@ -422,29 +561,109 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
case REG:
/* Stack references are assumed not to trap, but we need to deal with
nonsensical offsets. */
- if (x == frame_pointer_rtx)
+ if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+ || x == stack_pointer_rtx
+ /* The arg pointer varies if it is not a fixed register. */
+ || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
{
- HOST_WIDE_INT adj_offset = offset - STARTING_FRAME_OFFSET;
+#ifdef RED_ZONE_SIZE
+ HOST_WIDE_INT red_zone_size = RED_ZONE_SIZE;
+#else
+ HOST_WIDE_INT red_zone_size = 0;
+#endif
+ HOST_WIDE_INT stack_boundary = PREFERRED_STACK_BOUNDARY
+ / BITS_PER_UNIT;
+ HOST_WIDE_INT low_bound, high_bound;
+
if (size == 0)
size = GET_MODE_SIZE (mode);
- if (FRAME_GROWS_DOWNWARD)
+
+ if (x == frame_pointer_rtx)
{
- if (adj_offset < frame_offset || adj_offset + size - 1 >= 0)
- return 1;
+ if (FRAME_GROWS_DOWNWARD)
+ {
+ high_bound = STARTING_FRAME_OFFSET;
+ low_bound = high_bound - get_frame_size ();
+ }
+ else
+ {
+ low_bound = STARTING_FRAME_OFFSET;
+ high_bound = low_bound + get_frame_size ();
+ }
+ }
+ else if (x == hard_frame_pointer_rtx)
+ {
+ HOST_WIDE_INT sp_offset
+ = get_initial_register_offset (STACK_POINTER_REGNUM,
+ HARD_FRAME_POINTER_REGNUM);
+ HOST_WIDE_INT ap_offset
+ = get_initial_register_offset (ARG_POINTER_REGNUM,
+ HARD_FRAME_POINTER_REGNUM);
+
+#if STACK_GROWS_DOWNWARD
+ low_bound = sp_offset - red_zone_size - stack_boundary;
+ high_bound = ap_offset
+ + FIRST_PARM_OFFSET (current_function_decl)
+#if !ARGS_GROW_DOWNWARD
+ + crtl->args.size
+#endif
+ + stack_boundary;
+#else
+ high_bound = sp_offset + red_zone_size + stack_boundary;
+ low_bound = ap_offset
+ + FIRST_PARM_OFFSET (current_function_decl)
+#if ARGS_GROW_DOWNWARD
+ - crtl->args.size
+#endif
+ - stack_boundary;
+#endif
+ }
+ else if (x == stack_pointer_rtx)
+ {
+ HOST_WIDE_INT ap_offset
+ = get_initial_register_offset (ARG_POINTER_REGNUM,
+ STACK_POINTER_REGNUM);
+
+#if STACK_GROWS_DOWNWARD
+ low_bound = - red_zone_size - stack_boundary;
+ high_bound = ap_offset
+ + FIRST_PARM_OFFSET (current_function_decl)
+#if !ARGS_GROW_DOWNWARD
+ + crtl->args.size
+#endif
+ + stack_boundary;
+#else
+ high_bound = red_zone_size + stack_boundary;
+ low_bound = ap_offset
+ + FIRST_PARM_OFFSET (current_function_decl)
+#if ARGS_GROW_DOWNWARD
+ - crtl->args.size
+#endif
+ - stack_boundary;
+#endif
}
else
{
- if (adj_offset < 0 || adj_offset + size - 1 >= frame_offset)
- return 1;
+ /* We assume that accesses are safe to at least the
+ next stack boundary.
+ Examples are varargs and __builtin_return_address. */
+#if ARGS_GROW_DOWNWARD
+ high_bound = FIRST_PARM_OFFSET (current_function_decl)
+ + stack_boundary;
+ low_bound = FIRST_PARM_OFFSET (current_function_decl)
+ - crtl->args.size - stack_boundary;
+#else
+ low_bound = FIRST_PARM_OFFSET (current_function_decl)
+ - stack_boundary;
+ high_bound = FIRST_PARM_OFFSET (current_function_decl)
+ + crtl->args.size + stack_boundary;
+#endif
}
- return 0;
+
+ if (offset >= low_bound && offset <= high_bound - size)
+ return 0;
+ return 1;
}
- /* ??? Need to add a similar guard for nonsensical offsets. */
- if (x == hard_frame_pointer_rtx
- || x == stack_pointer_rtx
- /* The arg pointer varies if it is not a fixed register. */
- || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
- return 0;
/* All of the virtual frame registers are stack references. */
if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
&& REGNO (x) <= LAST_VIRTUAL_REGISTER)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1ff34ca..4dff233 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2015-07-01 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR rtl-optimization/61047
+ * gcc.c-torture/execute/20150611-1.c: New testcase.
+
2015-07-01 David Malcolm <dmalcolm@redhat.com>
PR jit/66700
diff --git a/gcc/testsuite/gcc.c-torture/execute/20150611-1.c b/gcc/testsuite/gcc.c-torture/execute/20150611-1.c
new file mode 100644
index 0000000..ba34fa2
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20150611-1.c
@@ -0,0 +1,18 @@
+int a, c, d;
+short b;
+
+int
+main ()
+{
+ int e[1];
+ for (; b < 2; b++)
+ {
+ a = 0;
+ if (b == 28378)
+ a = e[b];
+ if (!(d || b))
+ for (; c;)
+ ;
+ }
+ return 0;
+}