The jump threading changes have exposed a latent bug on machines with
conditional execution such as the ARM.
Going into the last conditional execution pass we have:
[ ... ]
(insn 16 60 17 2 (set (reg:CC 100 cc)
(compare:CC (reg:SI 1 r1 [121])
(const_int 0 [0]))) j.c:14 226 {*arm_cmpsi_insn}
(expr_list:REG_DEAD (reg:SI 1 r1 [121])
(nil)))
(jump_insn 17 16 19 2 (set (pc)
(if_then_else (ne (reg:CC 100 cc)
(const_int 0 [0]))
(label_ref 25)
(pc))) j.c:14 235 {arm_cond_branch}
(expr_list:REG_DEAD (reg:CC 100 cc)
(int_list:REG_BR_PROB 5000 (nil)))
-> 25)
;; succ: 4 [50.0%]
;; 3 [50.0%] (FALLTHRU)
; basic block 3, loop depth 0, count 0, freq 7500, maybe hot
;; Invalid sum of incoming frequencies 5000, should be 7500
;; prev block 2, next block 4, flags: (RTL)
;; pred: 2 [50.0%] (FALLTHRU)
(note 19 17 18 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
(note/s 18 19 20 3 ("lab2") NOTE_INSN_DELETED_LABEL 3)
;; succ:
(note/s 20 18 21 ("lab") NOTE_INSN_DELETED_LABEL 4)
(barrier 21 20 25)
;; basic block 4, loop depth 0, count 0, freq 0
;; Invalid sum of incoming frequencies 5000, should be 0
;; prev block 3, next block 5, flags: (RTL)
;; pred: 2 [50.0%]
(code_label 25 21 26 4 2 "" [1 uses])
(note 26 25 27 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
;; succ: 5 [100.0%] (FALLTHRU)
;; basic block 5, loop depth 0, count 0, freq 2500
;; prev block 4, next block 1, flags: (RTL)
;; pred: 4 [100.0%] (FALLTHRU)
;; 5 [100.0%] (DFS_BACK)
(code_label 27 26 28 5 5 "" [1 uses])
(note 28 27 56 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
(jump_insn 56 28 57 5 (set (pc)
(label_ref 27)) 249 {*arm_jump}
(nil)
-> 27)
;; succ: 5 [100.0%] (DFS_BACK)
(barrier 57 56 58)
(note 58 57 0 NOTE_INSN_DELETED)
Note carefully BB3 which is the result of a __builtin_unreachable in the
original source. It has no code, no successors and a trailing barrier
(all as expected).
ce3 comes along and creates this mess:
[ ... ]
(insn 16 60 18 2 (set (reg:CC 100 cc)
(compare:CC (reg:SI 1 r1 [121])
(const_int 0 [0]))) j.c:14 226 {*arm_cmpsi_insn}
(expr_list:REG_DEAD (reg:SI 1 r1 [121])
(nil)))
(note/s 18 16 20 2 ("lab2") NOTE_INSN_DELETED_LABEL 3)
;; succ: 5 [100.0%] (FALLTHRU)
(note/s 20 18 21 ("lab") NOTE_INSN_DELETED_LABEL 4)
(barrier 21 20 27)
;; basic block 5, loop depth 0, count 0, freq 2500
;; Invalid sum of incoming frequencies 12500, should be 2500
;; prev block 2, next block 1, flags: (RTL)
;; pred: 2 [100.0%] (FALLTHRU)
;; 5 [100.0%] (DFS_BACK)
(code_label 27 21 28 5 5 "" [1 uses])
(note 28 27 56 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
(jump_insn 56 28 57 5 (set (pc)
(label_ref 27)) 249 {*arm_jump}
(nil)
-> 27)
;; succ: 5 [100.0%] (DFS_BACK)
(barrier 57 56 58)
(note 58 57 0 NOTE_INSN_DELETED)
Note how it's removed the conditional jump at the end of bb2. BB2 still
has an outgoing edge, to BB5, but there's a barrier after BB2.
This, of course, trips a checking failure.
ISTM that when we merge blocks due to if-conversion of this code of
code, we're always going to have an outgoing edge from the merged block
(sanity check, right?)
Something along these lines I think. However, I'm not at all familiar
with this code, so some sanity checking would be greatly appreciated.
Thoughts?
Jeff
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index ac0276c..f7f6243 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -3154,6 +3154,17 @@ merge_if_block (struct ce_if_block * ce_info)
{
merge_blocks (combo_bb, then_bb);
num_true_changes++;
+
+ /* THEN_BB might have been created by a __builtin_unreachable and
+ thus have no outgoing edges and a barrier. We need to remove
+ the barrier. */
+ rtx end = BB_END (then_bb);
+
+ while (end && NOTE_P (end))
+ end = NEXT_INSN (end);
+
+ if (GET_CODE (end) == BARRIER)
+ delete_insn (end);
}
/* The ELSE block, if it existed, had a label. That label count
@@ -3163,6 +3174,17 @@ merge_if_block (struct ce_if_block * ce_info)
{
merge_blocks (combo_bb, else_bb);
num_true_changes++;
+
+ /* ELSE_BB might have been created by a __builtin_unreachable and
+ thus have no outgoing edges and a barrier. We need to remove
+ the barrier. */
+ rtx end = BB_END (else_bb);
+
+ while (end && NOTE_P (end))
+ end = NEXT_INSN (end);
+
+ if (GET_CODE (end) == BARRIER)
+ delete_insn (end);
}
/* If there was no join block reported, that means it was not adjacent