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>
* 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 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);

View File

@ -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

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