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:
Tom de Vries 2014-08-14 16:13:59 +00:00 committed by Tom de Vries
parent 821fce246e
commit df5d402aba
7 changed files with 193 additions and 3 deletions

View File

@ -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> 2014-08-14 Roman Gareev <gareevroman@gmail.com>
* graphite-scop-detection.c: * graphite-scop-detection.c:

View File

@ -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 set_reg_attrs_for_decl_rtl (tree t, rtx x);
extern void adjust_reg_mode (rtx, enum machine_mode); extern void adjust_reg_mode (rtx, enum machine_mode);
extern int mem_expr_equal_p (const_tree, const_tree); 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); extern bool need_atomic_barrier_p (enum memmodel, bool);

View File

@ -305,6 +305,28 @@ block_fallthru (basic_block bb)
return (e) ? e->dest : NULL_BLOCK; 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 /* Go through a bunch of insns, converting them to conditional
execution format if possible. Return TRUE if all of the non-note 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->a, XEXP (cond, 1))
&& rtx_equal_p (if_info->b, XEXP (cond, 0)))) && 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; y = (code == EQ) ? if_info->a : if_info->b;
/* Avoid generating the move if the source is the destination. */ /* 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 if (! insn_b
|| insn_b != last_active_insn (else_bb, FALSE) || insn_b != last_active_insn (else_bb, FALSE)
|| (set_b = single_set (insn_b)) == NULL_RTX || (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; return FALSE;
} }
else 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) || BLOCK_FOR_INSN (insn_b) != BLOCK_FOR_INSN (if_info->cond_earliest)
|| !NONJUMP_INSN_P (insn_b) || !NONJUMP_INSN_P (insn_b)
|| (set_b = single_set (insn_b)) == NULL_RTX || (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)) || ! noce_operand_ok (SET_SRC (set_b))
|| reg_overlap_mentioned_p (x, SET_SRC (set_b)) || reg_overlap_mentioned_p (x, SET_SRC (set_b))
|| modified_between_p (SET_SRC (set_b), insn_b, jump) || 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 /* Look and see if A and B are really the same. Avoid creating silly
cmove constructs that no one will fix up later. */ 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 /* 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 move the instruction that we already have. If we don't have an

View File

@ -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> 2014-08-14 Paolo Carlini <paolo.carlini@oracle.com>
* g++.dg/cpp0x/alias-decl-4.C: Adjust for parser change. * g++.dg/cpp0x/alias-decl-4.C: Adjust for parser change.

View 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);
}

View 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;
}

View 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;
}