On 05/09/13 15:07, Eric Botcazou wrote: > Hi, > > in case the ip register needs to be saved before establishing an APCS frame, > i.e. when it is used as the static chain register, the prologue tries various > tricks in the following order: > > 1. The last argument register r3. > 2. A slot on the stack above the frame. (This only > works if the function is not a varargs function). > 3. Register r3 again, after pushing the argument registers > onto the stack. > > #3 doesn't really work since its implementation reads: > > { > /* Store the args on the stack. */ > if (cfun->machine->uses_anonymous_args) > insn = emit_multi_reg_push > ((0xf0 >> (args_to_push / 4)) & 0xf); > else > insn = emit_insn > (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, > GEN_INT (- args_to_push))); > > RTX_FRAME_RELATED_P (insn) = 1; > > saved_pretend_args = 1; > fp_offset = args_to_push; > args_to_push = 0; > > /* Now reuse r3 to preserve IP. */ > emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); > } > > It works only if cfun->machine->uses_anonymous_args is true, because in this > case r3 is pushed onto the stack as part of the multi-reg push. Otherwise, > the contents of r3 are simply overwritten by the last line. > > Fixed by saving ip on the stack in this latter case, using one of the slots > to > be used by the pushed arguments. This eliminates the last ACATS failures on > ARM/VxWorks. OK for the mainline? > > > 2013-09-05 Eric Botcazou <ebotca...@adacore.com> > > * config/arm/arm.c (arm_expand_prologue): In a nested APCS frame with > arguments to push onto the stack and no varargs, save ip into a stack > slot if r3 isn't available on entry. > >
This is all fragile code, so a testcase would be very much appreciated. R. > > p.diff > > > Index: config/arm/arm.c > =================================================================== > --- config/arm/arm.c (revision 202160) > +++ config/arm/arm.c (working copy) > @@ -18209,11 +18209,13 @@ arm_expand_prologue (void) > whilst the frame is being created. We try the following > places in order: > > - 1. The last argument register r3. > - 2. A slot on the stack above the frame. (This only > - works if the function is not a varargs function). > + 1. The last argument register r3 if it is available. > + 2. A slot on the stack above the frame if there are no > + arguments to push onto the stack. > 3. Register r3 again, after pushing the argument registers > - onto the stack. > + onto the stack, if this is a varargs function. > + 4. A slot on the stack created for the arguments to push, > + if this isn't a varargs function. > > Note - we only need to tell the dwarf2 backend about the SP > adjustment in the second variant; the static chain register > @@ -18244,21 +18246,25 @@ arm_expand_prologue (void) > { > /* Store the args on the stack. */ > if (cfun->machine->uses_anonymous_args) > - insn = emit_multi_reg_push > - ((0xf0 >> (args_to_push / 4)) & 0xf); > + { > + insn > + = emit_multi_reg_push ((0xf0 >> (args_to_push / 4)) & 0xf); > + emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); > + saved_pretend_args = 1; > + } > else > - insn = emit_insn > - (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, > - GEN_INT (- args_to_push))); > + { > + rtx x = plus_constant (Pmode, stack_pointer_rtx, > + args_to_push - 4); > + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, > + stack_pointer_rtx, > + GEN_INT (- args_to_push))); > + emit_set_insn (gen_frame_mem (SImode, x), ip_rtx); > + } > > RTX_FRAME_RELATED_P (insn) = 1; > - > - saved_pretend_args = 1; > fp_offset = args_to_push; > args_to_push = 0; > - > - /* Now reuse r3 to preserve IP. */ > - emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); > } > } > > @@ -18363,7 +18369,7 @@ arm_expand_prologue (void) > /* Recover the static chain register. */ > if (!arm_r3_live_at_start_p () || saved_pretend_args) > insn = gen_rtx_REG (SImode, 3); > - else /* if (crtl->args.pretend_args_size == 0) */ > + else > { > insn = plus_constant (Pmode, hard_frame_pointer_rtx, 4); > insn = gen_frame_mem (SImode, insn); >