This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix ICE during RTL CFI generation pass
- From: Eric Botcazou <ebotcazou at adacore dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 13 Oct 2018 19:32:41 +0200
- Subject: Fix ICE during RTL CFI generation pass
This fixes an assertion failure compiling the Ada Web Server package (soap/
soap-message-xml.adb to be precise) at -O2 -gnatn -fPIC on x86/Linux:
+===========================GNAT BUG DETECTED==============================+
| Pro 20.0w (20181010-90) (i686-pc-linux-gnu) GCC error: |
| in connect_traces, at dwarf2cfi.c:2825 |
| Error detected around /byram.a/gnatmail/sandbox/gcc-head/x86-linux/ |
| aws_bootstrap-gcc-head/src/src/soap/soap-message-xml.adb:914:8 |
The ICE is extremely elusive and all my attempts at reducing the code failed.
The assertion is meant to check that, if a trace contains an insn that can
throw internally, then the incoming args_size values from preceding traces are
all the same. That's not the case here because cross-jumping commonalized an
insn restoring the stack pointer from the frame pointer, i.e setting args_size
to 0, and redirected a jump to just before the insn. Now, before this insn,
the args_size values need not match, for example if you have on one path a
call whose post-call stack adjustments have not been emitted (because the
stack pointer is restored just after in any case) and on another path a call
whose post-call stack adjustments have been emitted as usual.
So the attached patch relaxes the assertion by allowing the case where an insn
sets the args_size in the current trace before the first insn that can throw
internally. That's OK since DW_CFA_GNU_args_size notes are emitted only on
this first insn or after it, and not at the start of the trace.
Tested on x86/Linux and x86-64/Linux, applied on the mainline.
2018-10-13 Eric Botcazou <ebotcazou@adacore.com>
* dwarf2cfi.c (struct dw_trace_info): Add args_size_defined_for_eh.
(notice_args_size): Set it in the current trace if no insn that can
throw internally has been seen yet.
(connect_traces): When connecting args_size between traces, allow the
incoming values not to match if there is an insn setting it before the
first insn that can throw internally; in that case, force the creation
of a CFI note on this latter insn.
--
Eric Botcazou
Index: dwarf2cfi.c
===================================================================
--- dwarf2cfi.c (revision 264986)
+++ dwarf2cfi.c (working copy)
@@ -147,6 +147,9 @@ struct dw_trace_info
/* True if we've seen different values incoming to beg_true_args_size. */
bool args_size_undefined;
+
+ /* True if we've seen an insn with a REG_ARGS_SIZE note before EH_HEAD. */
+ bool args_size_defined_for_eh;
};
@@ -942,6 +945,9 @@ notice_args_size (rtx_insn *insn)
if (note == NULL)
return;
+ if (!cur_trace->eh_head)
+ cur_trace->args_size_defined_for_eh = true;
+
args_size = get_args_size (note);
delta = args_size - cur_trace->end_true_args_size;
if (known_eq (delta, 0))
@@ -2820,11 +2826,17 @@ connect_traces (void)
if (ti->switch_sections)
prev_args_size = 0;
+
if (ti->eh_head == NULL)
continue;
- gcc_assert (!ti->args_size_undefined);
- if (maybe_ne (ti->beg_delay_args_size, prev_args_size))
+ /* We require either the incoming args_size values to match or the
+ presence of an insn setting it before the first EH insn. */
+ gcc_assert (!ti->args_size_undefined || ti->args_size_defined_for_eh);
+
+ /* In the latter case, we force the creation of a CFI note. */
+ if (ti->args_size_undefined
+ || maybe_ne (ti->beg_delay_args_size, prev_args_size))
{
/* ??? Search back to previous CFI note. */
add_cfi_insn = PREV_INSN (ti->eh_head);