This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[ARM] Fix broken sibcall with longcall, APCS frame and VFP


Hi,

this is a regression present on the mainline and 6 branch and introduced by:

2014-04-25  Jiong Wang  <jiong.wang@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  <ebotcazou@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  <ebotcazou@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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]