This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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:

  On looking through resource.c to find out how EPILOGUE_USES is made use of,
I see

  /* Indicate what resources are required to be valid at the end of the
     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.  */
  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
    if (global_regs[i]
      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;

  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?

Can't think of a witty .sigline today....

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]