This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
ICE: Attempt to delete prologue/epilogue insn: in propagate_one_insn, at flow.c:1648
- From: "Dave Korn" <dave dot korn at artimi dot com>
- To: <gcc at gcc dot gnu dot org>
- Date: Mon, 27 Mar 2006 19:13:14 +0100
- Subject: ICE: Attempt to delete prologue/epilogue insn: in propagate_one_insn, at flow.c:1648
Hi gang,
This ICE tends to crop up in the course of converting a port from assembly
to rtl pro/epilogue generation. In my case, I find it's happening because:
- the function I'm compiling has an attribute I've defined to mean 'isr
handler' applied to it, and
- as a result, in the prologue I'm saving volatile (callee-save) registers,
even though they aren't marked in regs_ever_live[], and
- in the epilogue, I emit sets to reload those ("unexpectedly-saved")
registers, and
- flow2 later attempts to delete one of the SET insns that restores an
unexpectedly-saved GPR that is not marked in regs_ever_live[].
On looking into it a bit, I've found two techniques used to handle this:
- In the ARM port, it emits lots of what it describes as USEs in the comments
(actually, they're unspec's of the form (unspec:SI (reg:SI nn)
UNSPEC_PROLOGUE_USE), and pretty-much everything is separated off with
unspec_volatiles which it refers to as "blockage" insns, and which it says
"claim that all hard registers are used and clobbered by this point".
- In an email thread from last august, I found it suggested that it was better
to use EPILOGUE_USES instead:
http://www.nabble.com/forum/ViewTopic.jtp?topic=195757&tview=dump#a546107
On looking through resource.c to find out how EPILOGUE_USES is made use of,
I see
---------------------------------------------<snip>
/* Indicate what resources are required to be valid at the end of the
current
function. The condition code never is and memory always is. If the
frame pointer is needed, it is and so is the stack pointer unless
EXIT_IGNORE_STACK is nonzero. If the frame pointer is not needed, the
stack pointer is. Registers used to return the function value are
needed. Registers holding global variables are needed. */
---------------------------------------------<snip>
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i]
#ifdef EPILOGUE_USES
|| EPILOGUE_USES (i)
#endif
)
SET_HARD_REG_BIT (end_of_function_needs.regs, i);
/* The registers required to be live at the end of the function are
represented in the flow information as being dead just prior to
reaching the end of the function. For example, the return of a value
might be represented by a USE of the return register immediately
followed by an unconditional jump to the return label where the
return label is the end of the RTL chain. The end of the RTL chain
is then taken to mean that the return register is live.
This sequence is no longer maintained when epilogue instructions are
added to the RTL chain. To reconstruct the original meaning, the
start of the epilogue (NOTE_INSN_EPILOGUE_BEG) is regarded as the
point where these registers become live (start_of_epilogue_needs).
If epilogue instructions are present, the registers set by those
instructions won't have been processed by flow. Thus, those
registers are additionally required at the end of the RTL chain
(end_of_function_needs). */
start_of_epilogue_needs = end_of_function_needs;
---------------------------------------------<snip>
So, I have tried marking those unexpectedly-saved registers in EPILOGUE_USES
(but only after reload; doing so beforehand stops the RA from using them!),
and that's fixed my ICE, and the generated code and the rtl that leads up to
it all looks good, and I even think I understand why it works, but I'm still
left a bit puzzled:
Is there any particular advantage or disadvantage to doing it the way the
arm does, rather than the EPILOGUE_USES way? Is it just done that way because
of historical baggage? Is adding the unexpectedly-saved registers to
EPILOGUE_USES actually as correct as it seems to me that it is?
cheers,
DaveK
--
Can't think of a witty .sigline today....