[LLVMdev] spilling & restoring registers for EHReturn & return _Unwind_Reason_Code
Pasi Parviainen
pasi.parviainen at iki.fi
Sat Dec 21 04:54:46 PST 2013
On 20.12.2013 19:33, Robert Lytton wrote:
> Hi
>
> I'm working on the XCore target and am having difficulty building libgcc.
>
> Background:
> If I use a libgcc built by llvm3.0-gcc with my current clang-llvm3.3 compiler, exceptions 'seem' to work.
> Trying to rebuild libgcc however breaks exception handling - they aren't caught!
> I thus assumed I needed to focus on the unwind code and particularly functions that call @llvm.eh.unwind.init().
> I reinforced this assumption by swapping the assembler output from the llvm-gcc lib into my new lib for some such functions - and exceptions 'seem' to work again.
> (the critical functions being found in eh_personality.o, unwind-dw2.o, eh_throw.o)
>
> Looking at functions built using the llvm3.0-gcc front end, I noticed that R0 & R1 were spilled/restored (clobbering '_Unwind_Reason_Code') , along with the callee saved regs.
>
> So how are things meant to work?
Hi, this has been a long standing issue in llvm, and is tracked in
following bug report: http://llvm.org/bugs/show_bug.cgi?id=8541
You might find my attempt for fixing this issue for x86 target
informational. It is a hack, but a working one at least (at the time):
http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20130415/172180.html
And resulting discussion, with more detailed description of underlying
issue, can be found from here:
http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20130513/174459.html
At least that resulted to a proper handling of llvm.eh.unwind.init
intrinsic in PrologueEpilogueInserter, to spill callee saved registers.
What needs to be done, is to have a general interface to handle
exception registers.
Also you might find http://gcc.gnu.org/wiki/Dwarf2EHNewbiesHowto helpful
for understanding all of this.
All of this is really a target specific and rest of the reply is based
on my (now diminished) understanding how things work on x86.
> For example take:
> define i32 @_Unwind_RaiseException(%struct._Unwind_Exception* %exc)
>
> This calls:
> @llvm.eh.unwind.init()
> followed by:
> call void @llvm.eh.return()
> ret i32 '_Unwind_Reason_Code'
> call void @abort()
>
> From my reading, I need to spill all callee save regs (R4-R10) during the prologue.
> (R0-R3, LR & FP are caller saved/argument registers)
Spilling of callee saved registers are taken care of by
llvm.eh.unwind.init and it should be already ensured by
PrologueEpilogueEmitter automatically.
What llvm.eh.return() does from a spilling stand point of view is that
it reserves spill slots for a exception registers in the prologue (i.e.
you don't need to actually spill the registers in prologue, just need to
reserve space for them and have proper CFI register specs generated
where these are locate in the stack). On normal return paths you just
ignore these extra spill slots by adjusting the stack properly.
The need for CFI register specs for these spill slots is so that the
unwinder knows where to put the exception information when exception occurs.
> BUT
> Q: what about exception info (and what is this)?
> Q: is it %exc (R0)?
> Q: is it 'ExceptionPointerRegister' & 'ExceptionSelectorRegister' (R0&R1)?
It is information delivered by both ExceptionPointer and
ExceptionSelector registers to a landing pad on llvm.eh.return() return
paths.
> Then:
>
> Calling abort, does not restore callee save regs.
>
> For 'return' epilogues, I restore callee save regs (R4-10) & R0 will hold the '_Unwind_Reason_Code'.
>
> However, what must I do for llvm.eh.return() epilogues?
> Q: do I restore callee save regs (R4-R10)?
> Q: do I restore exception info (R0-R1)?
On llvm.eh.return() epilogues, you must restore both, callee saved
registers and exception info registers (and be sure when lowering
llvm.eh.return not to clobber restored exception info registers! i.e.
neither of those are used as a temporary after restoring.).
In a essence llvm.eh.return() intrinsic is a terminator and must be
treated as a such from a lowering stand point of view.
> I have tried only spilling/restoring callee save regs - but this doesn't work, I end up with an uncaught exception.
>
> So I tried spilling R0 & R1 and trying to restore them only for llvm.eh.return() but this will not compile.
> viz unwind-dw2.c will report:
> BB#0: derived from LLVM BB %entry
> Live Ins: %R0 %R0 %R1 %R4 %R5 %R6 %R7 %R8 %R9 %R10 %LR %R0 %R1
> ENTSP_lu6 120, %SP<imp-def>, %SP<imp-use>, %LR<imp-use,kill>
> PROLOG_LABEL <MCSym=.Ltmp68>
> PROLOG_LABEL <MCSym=.Ltmp69>
> STWSP_lru6 %R0<kill>, 119, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp59>
> STWSP_lru6 %R1<kill>, 118, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp60>
> STWSP_lru6 %R4<kill>, 117, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp61>
> STWSP_lru6 %R5<kill>, 116, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp62>
> STWSP_lru6 %R6<kill>, 115, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp63>
> STWSP_lru6 %R7<kill>, 114, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp64>
> STWSP_lru6 %R8<kill>, 113, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp65>
> STWSP_lru6 %R9<kill>, 112, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp66>
> STWSP_lru6 %R10<kill>, 111, %SP<imp-use>
> PROLOG_LABEL <MCSym=.Ltmp67>
> %R4<def> = COPY %R0
> ...
> *** Bad machine code: Using an undefined physical register ***
> - function: _Unwind_RaiseException
> - basic block: BB#0 entry (0x33d9f20)
> - instruction: %R4<def> = COPY %R0
> - operand 1: %R0
>
>
> To see if I am on the right track I may try to:
> 1. hack llvm to not kill R0 during the spill
> 2. manually add spilled/restore R0 & R1 into the assembler output for functions that call llvm.eh.return().
Hopefully above descriptions gave you insight how to handle
llvm.eh.return(). In short, have a spill slots reserved for these
registers in prologue, and most importantly have CFI register specs for
these spill slots. On llvm.eh.return epilogues restore R0 & R1 from
these slots and on normal epilogues just ignore this extra space.
Pasi.
> However, I would prefer knowledgeable input at this stage!
>
> Thank you.
>
> Robert
>
More information about the llvm-dev
mailing list