Reload (find_reloads) has code that can replace a register with a
label_ref when presented with RTL of the form:
(set (reg) (reg) (notes (rtx_equal (label_ref)))
Label references are initially counted in jump.c:mark_all_labels() and
friends. This code traverses the RTL and counts each observed label_ref.
The code inserts REG_LABEL_OPERAND or REG_LABEL_TARGET as appropriate.
Notes are not traversed therefore the (rtx_equal (label_ref)) shown
above is not treated as a reference.
Instruction deletion, in cfgrtl.c:delete_insn() does not re-traverse the
RTL, The code traverses only the notes looking for REG_LABEL_OPERAND and
REG_TARGET_OPERAND notes in order to count down the label_nuses field.
The code in reload.c:find_reloads() converts a register to a label_ref
and inserts the associated REG_LABEL_OPERAND but does not adjust
label_nuses, this may result in the inappropriate deletion of a live label.
This issue was discovered during the development of the ARM aarch64 gcc
backend and results in an ICE due to deletion of a live jump table.
The issue has not been re-created on another target. The proposed patch
has been regressed on x86 (and aarch64).
Proposed ChangeLog entry below, patch attached:
2012-01-04 Marcus Shawcroft <marcus.shawcr...@arm.com>
* reload.c (find_reloads): Adjust LABEL_NUSES on
REG_LABEL_OPERAND insertion.
/Marcus
diff --git a/gcc/reload.c b/gcc/reload.c
index 53dcd2d..206fb36 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -4212,7 +4212,12 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
&& (!JUMP_P (insn)
|| !label_is_jump_target_p (XEXP (substitution, 0),
insn)))
- add_reg_note (insn, REG_LABEL_OPERAND, XEXP (substitution, 0));
+ {
+ add_reg_note (insn, REG_LABEL_OPERAND, XEXP (substitution, 0));
+ if (LABEL_P (XEXP (substitution, 0)))
+ ++ LABEL_NUSES(XEXP (substitution, 0));
+ }
+
}
else
retval |= (substed_operand[i] != *recog_data.operand_loc[i]);