Hi,
this is a regression present on the mainline and 6 branch and introduced by:
2014-04-25 Jiong Wang <jiong.w...@arm.com>
* config/arm/predicates.md (call_insn_operand): Add long_call check.
* config/arm/arm.md (sibcall, sibcall_value): Force the address to
reg for long_call.
* config/arm/arm.c (arm_function_ok_for_sibcall): Remove long_call
restriction.
For a longcall, any sibcall becomes an indirect sibcall and therefore requires
a register to hold the target address. Now if all the argument registers are
taken, this register will be IP but, for APCS frames and VFP, IP can be used
in the sibcall epilogue to restore the VFP registers, so the target address is
overwritten and the call goes astray. Testcase attached, compile it with e.g.
-mapcs-frame -mfloat-abi=soft -O -foptimize-sibling-calls -ffunction-sections
and you'll see for arm-eabi:
sub ip, fp, #36
vldm ip!, {d8}
sub sp, fp, #28
ldmfd sp, {r4, r5, r6, r7, fp, sp, lr}
bx ip
The attached patch reinstates the restriction for APCS frames and VFP. This
might be deemed a big hammer, but isn't a regression from earlier releases of
the compiler and APCS frames are deprecated in any case (we still support them
for VxWorks 6 but VxWorks 7 switched to AAPCS).
Tested on ARM/VxWorks 6 and ARM/EABI, OK for mainline and 6 branch?
2016-08-31 Eric Botcazou <ebotca...@adacore.com>
* config/arm/arm.c (arm_function_ok_for_sibcall): Add back restriction
for long calls with APCS frame and VFP.
2016-08-31 Eric Botcazou <ebotca...@adacore.com>
* gcc.target/arm/vfp-longcall-apcs.c: New test.
--
Eric Botcazou
Index: config/arm/arm.c
===================================================================
--- config/arm/arm.c (revision 239888)
+++ config/arm/arm.c (working copy)
@@ -6773,6 +6773,14 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
if (TARGET_VXWORKS_RTP && flag_pic && decl && !targetm.binds_local_p (decl))
return false;
+ /* ??? Cannot tail-call to long calls with APCS frame and VFP, because IP
+ may be used both as target of the call and base register for restoring
+ the VFP registers */
+ if (TARGET_APCS_FRAME && TARGET_ARM
+ && TARGET_HARD_FLOAT && TARGET_VFP
+ && decl && arm_is_long_call_p (decl))
+ return false;
+
/* If we are interworking and the function is not declared static
then we can't tail-call it unless we know that it exists in this
compilation unit (since it might be a Thumb routine). */
/* { dg-do run } */
/* { dg-require-effective-target arm_vfp_ok } */
/* { dg-options "-mapcs-frame -mfpu=vfp -mfloat-abi=softfp -O -foptimize-sibling-calls -ffunction-sections" } */
extern void abort (void);
static __attribute__((noclone, noinline, long_call))
int foo (int a, int b, int c, int d, double i)
{
return a;
}
static __attribute__((noclone, noinline))
double baz (double i)
{
return i;
}
static __attribute__((noclone, noinline))
int bar (int a, int b, int c, int d, double i, double j)
{
double l = baz (i) * j;
return foo (a, b, c, d, l);
}
int
main (void)
{
if (bar (0, 0, 0, 0, 0.0, 0.0) != 0)
abort ();
return 0;
}