I have realised that part of the problem is that the receiver block has
no incoming edges so cfgcleanup removes it as unreachable block - right?
So any target that need a non trivial receiver for builtin_setjmp will
not work? That would mean any that have an offset between stack and
pointers?
I guess the same problem exists for non-local goto?
I am not convinced it could be this wrong. So please comment and suggest
solution - I'm sure I can write target handler but it seems so wrong to
leave this as issue open.
Andy
Andrew Hutchinson wrote:
I have real problems trying to get to the root of bug in
builtin_setjmp implementation and seek anyones wisdom on what I have
found and a way forward.
Sometimes it's not always clear which part is wrong - when presented
with mismatches.
I will post a bug report when I have got a little closer.
The problem I was looking at is the frame pointer being wrong on the
AVR target. (Stack and PC are ok)
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21078 - but ANY
setjmp/longjump has the problem.
I traced this down to the handling of the frame pointer: by the
receiver - (which is the code the longjmp will jump back to)
Setjmp: - save pointer
Buf[0] = Virtual_stack_var
Longjmp: get pointer
Hard_Frame_pointer=buf[0]
Receiver: put back in frame pointer
Virtual_stack_var = Hard_Frame_pointer
The uniqueness on AVR is that Frame_pointer (and stack pointer) are 1
byte different from the first stack element. So the Virtual_stack_var
is 1 different from the frame_pointer
i.e.
#define STACK_GROWS_DOWNWARD
#define STARTING_FRAME_OFFSET 1
#define STACK_POINTER_OFFSET 1
That's ok as this is recognized by instantiate_virtual_regs, which
makes the replacements later. In this case
Buf[0] = Frame_pointer+1
..
..
Frame_pointer = Virtual_stack_var - 1
However, what is happening is that an earlier pass noted in RTL dump
file "sibling" eliminates the receiver code block. So the frane
point is not reset correctly, and ends up being 1 out (which is bad).
Other targets may survive if they don't have offset between stack and
pointers.
So where do I look to find out why this is happening? Does the RTL
have something missing or is the other pass not checking?
The RTL that gets eliminated is:
;; Start of basic block () -> 5
(code_label/s 13 12 14 5 4 "" [2 uses])
(note 14 13 15 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
(insn 15 14 16 5 built-in-setjmp.c:17 (use (reg/f:HI 28 r28)) -1 (nil))
(insn 16 15 17 5 built-in-setjmp.c:17 (clobber (reg:HI 2 r2)) -1 (nil))
(insn 17 16 18 5 built-in-setjmp.c:17 (set (reg/f:HI 37
virtual-stack-vars)
(reg/f:HI 28 r28)) -1 (nil))
(insn 18 17 19 5 built-in-setjmp.c:17 (clobber (reg/f:HI 28 r28)) -1
(nil))
(insn 19 18 20 5 built-in-setjmp.c:17 (asm_input/v ("") 0) -1 (nil))
;; End of basic block 5 -> ( 6)
The second PROBLEM I noted is that gcc creates RTL for TWO receivers
for a setjmp. One is naturally from "expand_builtin_setjmp_receiver"
but there is then another one just after created by
"expand_nl_goto_receiver" in stmt.c- whats all this about?
Despite having two, both get optimised out!
Andy