On 03/23/2011 09:48 AM, Bernd Schmidt wrote:
>> With no more code than this, I cannot believe you're generating correct
>> unwind info anymore.
> 
> Why not? Are you worried about the code at the destination of the jump?
> That should be preceded by another block falling through into it which
> also has a NOTE_INSN_EPILOGUE_BEG.
> 
> If that isn't the problem you have in mind, what is and how can we test
> for it?

        body
        body
        restore r1      XXX
        restore r2      XXX
        jmp L2          XXX

L1:     body            YYY
        body            YYY
        restore r2

L2:     restore r3
        return

Assume for the moment that "restore" on this target is something that
can't be delayed or repeated.  E.g. a pop, rather than a move which
leaves the saved value in memory at a unknown offset from the CFA.

This means we have to emit unwind directives immediately after the 
restore insn and cannot delay the epilogue unwind until we deallocate
the entire stack frame.

This means that your patch either gets the unwind info wrong for
the XXX sequence or the YYY sequence.

Correct unwind info would look like

        body
        body
        .cfi_remember_state
        restore r1
        .cfi_restore r1
        restore r2
        .cfi_restore r2
        jmp L2
        .cfi_restore_state

L1:     body
        body
        restore r2
        .cfi_restore r2

L2:     // validate the unwind info across the CFG making sure that the incoming
        // edges contain the same unwind info here.
        restore r3
        .cfi_restore r3
        return

In general, with shrink-wrapping, we can have essentially arbitrary
differences in unwind info between blocks that are sequential.  We have
to be prepared to fully adjust the unwind state between blocks.

Assume a { x } is the set of registers saved into the stack frame in a
given block.  We have both incoming and outgoing sets.

foo:                            // in: { }
        cmp     r1,r2
        jne     L1              // out: { }

L0:                             // in: { }
        save r8
        save r9
        body
        ...                     // out: { r8, r9 }

L2:                             // in: { r8, r9, r10 }
        body
        body
        ...                     // out: { r8, r9, r10 }

L1:                             // in: { }
        save r8
        save r9
        save r10
        body
        ...                     // out: { r8, r9, r10 }

L3:                             // in: { r8, r9, r10 }
        restore r10             // out: { r8, r9 }

L4:                             // in: { r8, r9 }
        restore r9
        restore r8
        return

This layout requires more than just .cfi_remember_state/restore_state
between blocks.  We have to be prepared to emit full unwind info at
any point.  Assume cfi info marked with XXX exists between basic blocks
to fixup the transition points:

L0:     save r8
        save r9
        .cfi_offset r8,x
        .cfi_offset r9,y
        body
        
        .cfi_offset r10,z       XXX

L2:     body
        body

        .cfi_restore r8         XXX
        .cfi_restore r9         XXX
        .cfi_restore r10        XXX

L1:     save r8
        save r9
        save r10
        .cfi_offset r8,x
        .cfi_offset r9,y
        .cfi_offset r10,z
        body

If this isn't clear, please ask questions.  The problem of unwinding is
way more complicated than what you appear to be assuming.


r~

Reply via email to