diff mbox

[RFA,PR,middle-end/59285] Handle BARRIERS between blocks in rtl_merge_blocks

Message ID 52A15811.8070907@redhat.com
State New
Headers show

Commit Message

Jeff Law Dec. 6, 2013, 4:52 a.m. UTC
builtin-unreachable-6.c when compiled for armv7l has a conditional where 
the fall-thru block has no successors (due to __builtin_unreachable) and 
is immediately followed by the jump-to block.  In this situation there 
will be a BARRIER after the fall-thru block (remember, it has no 
successors).

The post register allocation if-conversion pass wants to if-convert the 
whole mess (which is valid and often profitable).   The result should be 
a single block with any insns from the THEN/ELSE blocks being suitably 
predicated.

This all works pretty much as expected, except the BARRIER is still in 
the insn chain, which causes a checking failure after if-conversion is 
complete.

The problem is the if-conversion code is calling merge_blocks, which in 
turn calls rtl_merge_blocks to merge the test block, else block and then 
block.  rtl_merge_blocks does not properly detect and eliminate any 
barriers that may be between the blocks to be merged.

Long term BARRIERS should just go away, but that's not stage3 material.

Bootstrapped and regression tested in progress on 
armv7l-unknown-linux-gnueabihf.  Fixes builtin-unreachable-6, of course :-)

OK for the trunk?

Thanks,
Jeff
* cfgrtl.c (rtl_merge_blocks): Properly search for and remove
	any BARRIER between blocks A & B.
diff mbox

Patch

diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 63f44af..99ebe85 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -878,8 +878,15 @@  rtl_merge_blocks (basic_block a, basic_block b)
 
       a_end = PREV_INSN (del_first);
     }
-  else if (BARRIER_P (NEXT_INSN (a_end)))
-    del_first = NEXT_INSN (a_end);
+
+  /* If there is a BARRIER between A & B, remove it.  This can happen
+     if a block with no successors is if-converted.  */
+  rtx end = NEXT_INSN (a_end);
+  while (end && NOTE_P (end) && !NOTE_INSN_BASIC_BLOCK_P (end))
+    end = NEXT_INSN (end);
+
+  if (BARRIER_P (end))
+    del_first = end;
 
   /* Delete everything marked above as well as crap that might be
      hanging out between the two blocks.  */