Fix if-conversion pass for dead type-unsafe code
2014-08-14 Tom de Vries <tom@codesourcery.com> PR rtl-optimization/62004 PR rtl-optimization/62030 * ifcvt.c (rtx_interchangeable_p): New function. (noce_try_move, noce_process_if_block): Use rtx_interchangeable_p. * emit-rtl.h (mem_attrs_eq_p): Declare. * gcc.dg/pr62004.c: New test. * gcc.dg/pr62030.c: Same. * gcc.target/mips/pr62030-octeon.c: Same. From-SVN: r213970
This commit is contained in:
parent
821fce246e
commit
df5d402aba
@ -1,3 +1,12 @@
|
||||
2014-08-14 Tom de Vries <tom@codesourcery.com>
|
||||
|
||||
PR rtl-optimization/62004
|
||||
PR rtl-optimization/62030
|
||||
* ifcvt.c (rtx_interchangeable_p): New function.
|
||||
(noce_try_move, noce_process_if_block): Use rtx_interchangeable_p.
|
||||
* emit-rtl.c (mem_attrs_eq_p): Remove static.
|
||||
* emit-rtl.h (mem_attrs_eq_p): Declare.
|
||||
|
||||
2014-08-14 Roman Gareev <gareevroman@gmail.com>
|
||||
|
||||
* graphite-scop-detection.c:
|
||||
|
@ -72,6 +72,7 @@ extern void set_reg_attrs_for_parm (rtx, rtx);
|
||||
extern void set_reg_attrs_for_decl_rtl (tree t, rtx x);
|
||||
extern void adjust_reg_mode (rtx, enum machine_mode);
|
||||
extern int mem_expr_equal_p (const_tree, const_tree);
|
||||
extern bool mem_attrs_eq_p (const struct mem_attrs *, const struct mem_attrs *);
|
||||
|
||||
extern bool need_atomic_barrier_p (enum memmodel, bool);
|
||||
|
||||
|
31
gcc/ifcvt.c
31
gcc/ifcvt.c
@ -305,6 +305,28 @@ block_fallthru (basic_block bb)
|
||||
|
||||
return (e) ? e->dest : NULL_BLOCK;
|
||||
}
|
||||
|
||||
/* Return true if RTXs A and B can be safely interchanged. */
|
||||
|
||||
static bool
|
||||
rtx_interchangeable_p (const_rtx a, const_rtx b)
|
||||
{
|
||||
if (!rtx_equal_p (a, b))
|
||||
return false;
|
||||
|
||||
if (GET_CODE (a) != MEM)
|
||||
return true;
|
||||
|
||||
/* A dead type-unsafe memory reference is legal, but a live type-unsafe memory
|
||||
reference is not. Interchanging a dead type-unsafe memory reference with
|
||||
a live type-safe one creates a live type-unsafe memory reference, in other
|
||||
words, it makes the program illegal.
|
||||
We check here conservatively whether the two memory references have equal
|
||||
memory attributes. */
|
||||
|
||||
return mem_attrs_eq_p (get_mem_attrs (a), get_mem_attrs (b));
|
||||
}
|
||||
|
||||
|
||||
/* Go through a bunch of insns, converting them to conditional
|
||||
execution format if possible. Return TRUE if all of the non-note
|
||||
@ -1033,6 +1055,9 @@ noce_try_move (struct noce_if_info *if_info)
|
||||
|| (rtx_equal_p (if_info->a, XEXP (cond, 1))
|
||||
&& rtx_equal_p (if_info->b, XEXP (cond, 0))))
|
||||
{
|
||||
if (!rtx_interchangeable_p (if_info->a, if_info->b))
|
||||
return FALSE;
|
||||
|
||||
y = (code == EQ) ? if_info->a : if_info->b;
|
||||
|
||||
/* Avoid generating the move if the source is the destination. */
|
||||
@ -2503,7 +2528,7 @@ noce_process_if_block (struct noce_if_info *if_info)
|
||||
if (! insn_b
|
||||
|| insn_b != last_active_insn (else_bb, FALSE)
|
||||
|| (set_b = single_set (insn_b)) == NULL_RTX
|
||||
|| ! rtx_equal_p (x, SET_DEST (set_b)))
|
||||
|| ! rtx_interchangeable_p (x, SET_DEST (set_b)))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
@ -2516,7 +2541,7 @@ noce_process_if_block (struct noce_if_info *if_info)
|
||||
|| BLOCK_FOR_INSN (insn_b) != BLOCK_FOR_INSN (if_info->cond_earliest)
|
||||
|| !NONJUMP_INSN_P (insn_b)
|
||||
|| (set_b = single_set (insn_b)) == NULL_RTX
|
||||
|| ! rtx_equal_p (x, SET_DEST (set_b))
|
||||
|| ! rtx_interchangeable_p (x, SET_DEST (set_b))
|
||||
|| ! noce_operand_ok (SET_SRC (set_b))
|
||||
|| reg_overlap_mentioned_p (x, SET_SRC (set_b))
|
||||
|| modified_between_p (SET_SRC (set_b), insn_b, jump)
|
||||
@ -2582,7 +2607,7 @@ noce_process_if_block (struct noce_if_info *if_info)
|
||||
|
||||
/* Look and see if A and B are really the same. Avoid creating silly
|
||||
cmove constructs that no one will fix up later. */
|
||||
if (rtx_equal_p (a, b))
|
||||
if (rtx_interchangeable_p (a, b))
|
||||
{
|
||||
/* If we have an INSN_B, we don't have to create any new rtl. Just
|
||||
move the instruction that we already have. If we don't have an
|
||||
|
@ -1,3 +1,11 @@
|
||||
2014-08-14 Tom de Vries <tom@codesourcery.com>
|
||||
|
||||
PR rtl-optimization/62004
|
||||
PR rtl-optimization/62030
|
||||
* gcc.dg/pr62004.c: New test.
|
||||
* gcc.dg/pr62030.c: Same.
|
||||
* gcc.target/mips/pr62030-octeon.c: Same.
|
||||
|
||||
2014-08-14 Paolo Carlini <paolo.carlini@oracle.com>
|
||||
|
||||
* g++.dg/cpp0x/alias-decl-4.C: Adjust for parser change.
|
||||
|
47
gcc/testsuite/gcc.dg/pr62004.c
Normal file
47
gcc/testsuite/gcc.dg/pr62004.c
Normal file
@ -0,0 +1,47 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fno-tree-tail-merge" } */
|
||||
|
||||
struct node
|
||||
{
|
||||
struct node *next;
|
||||
struct node *prev;
|
||||
};
|
||||
|
||||
struct node node;
|
||||
|
||||
struct head
|
||||
{
|
||||
struct node *first;
|
||||
};
|
||||
|
||||
struct head heads[5];
|
||||
|
||||
int k = 2;
|
||||
|
||||
struct head *head = &heads[2];
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
struct node *p;
|
||||
|
||||
node.next = (void*)0;
|
||||
|
||||
node.prev = (void *)head;
|
||||
|
||||
head->first = &node;
|
||||
|
||||
struct node *n = head->first;
|
||||
|
||||
struct head *h = &heads[k];
|
||||
|
||||
heads[2].first = n->next;
|
||||
|
||||
if ((void*)n->prev == (void *)h)
|
||||
p = h->first;
|
||||
else
|
||||
/* Dead tbaa-unsafe load from ((struct node *)&heads[2])->next. */
|
||||
p = n->prev->next;
|
||||
|
||||
return !(p == (void*)0);
|
||||
}
|
50
gcc/testsuite/gcc.dg/pr62030.c
Normal file
50
gcc/testsuite/gcc.dg/pr62030.c
Normal file
@ -0,0 +1,50 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
extern void abort (void);
|
||||
|
||||
struct node
|
||||
{
|
||||
struct node *next;
|
||||
struct node *prev;
|
||||
};
|
||||
|
||||
struct node node;
|
||||
|
||||
struct head
|
||||
{
|
||||
struct node *first;
|
||||
};
|
||||
|
||||
struct head heads[5];
|
||||
|
||||
int k = 2;
|
||||
|
||||
struct head *head = &heads[2];
|
||||
|
||||
static int __attribute__((noinline))
|
||||
foo (void)
|
||||
{
|
||||
node.prev = (void *)head;
|
||||
head->first = &node;
|
||||
|
||||
struct node *n = head->first;
|
||||
struct head *h = &heads[k];
|
||||
struct node *next = n->next;
|
||||
|
||||
if (n->prev == (void *)h)
|
||||
h->first = next;
|
||||
else
|
||||
n->prev->next = next;
|
||||
|
||||
n->next = h->first;
|
||||
return n->next == &node;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
if (foo ())
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
50
gcc/testsuite/gcc.target/mips/pr62030-octeon.c
Normal file
50
gcc/testsuite/gcc.target/mips/pr62030-octeon.c
Normal file
@ -0,0 +1,50 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-march=octeon" } */
|
||||
|
||||
extern void abort (void);
|
||||
|
||||
struct node
|
||||
{
|
||||
struct node *next;
|
||||
struct node *prev;
|
||||
};
|
||||
|
||||
struct node node;
|
||||
|
||||
struct head
|
||||
{
|
||||
struct node *first;
|
||||
};
|
||||
|
||||
struct head heads[5];
|
||||
|
||||
int k = 2;
|
||||
|
||||
struct head *head = &heads[2];
|
||||
|
||||
static int __attribute__((noinline))
|
||||
foo (void)
|
||||
{
|
||||
node.prev = (void *)head;
|
||||
head->first = &node;
|
||||
|
||||
struct node *n = head->first;
|
||||
struct head *h = &heads[k];
|
||||
struct node *next = n->next;
|
||||
|
||||
if (n->prev == (void *)h)
|
||||
h->first = next;
|
||||
else
|
||||
n->prev->next = next;
|
||||
|
||||
n->next = h->first;
|
||||
return n->next == &node;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
if (foo ())
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user