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]

sibcall_blocked


Hi Richard,

This is the patch I was talking about earlier.  It's a bit dated now,
and the testcase dg-directives need tweaking, but it still should
apply.  I've been using it for a while; if it looks plausible to you
I can go find some cycles to regtest it on HEAD.

When I wrote this (for gcc 3.3?) this was the only case where we needed
to preserve stack alignment.  Nowadays we need it for the AAPCS, so
maybe there's a better way.  I didn't immediately see how non-IWMMXT
code handles this.

-- 
Daniel Jacobowitz

2004-04-21  Daniel Jacobowitz  <drow@mvista.com>

	* config/arm/arm.c (arm_function_ok_for_sibcall): Remove
	sibcall_blocked test.
	(arm_compute_saved_reg_mask): Don't set sibcall_blocked.
	(output_return_instruction, arm_output_epilogue): Handle
	saved r3 specially.
	* config/arm/arm.h (struct machine_function): Remove
	sibcall_blocked field.

2004-04-21  Daniel Jacobowitz  <drow@mvista.com>

	* testsuite/gcc.dg/arm-mmx-2.c: New test.

Index: config/arm/arm.c
===================================================================
RCS file: /big/fsf/rsync/gcc-cvs/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.346
diff -u -p -r1.346 arm.c
--- config/arm/arm.c	16 Apr 2004 13:20:36 -0000	1.346
+++ config/arm/arm.c	21 Apr 2004 15:16:22 -0000
@@ -2735,9 +2735,6 @@ arm_function_ok_for_sibcall (tree decl, 
 {
   int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
 
-  if (cfun->machine->sibcall_blocked)
-    return false;
-
   /* Never tailcall something for which we have no decl, or if we
      are in Thumb mode.  */
   if (decl == NULL || TARGET_THUMB)
@@ -8947,7 +8944,9 @@ arm_compute_save_reg_mask (void)
 	 an iWMMXt instruction).  Therefore we need to push another
 	 ARM register, so that the stack will be 64-bit aligned.  We
 	 try to avoid using the arg registers (r0 -r3) as they might be
-	 used to pass values in a tail call.  */
+	 used to pass values in a tail call.  If we have to use r3,
+	 then we'll have to be careful to pop it into a scratch register
+	 later.  */
       for (reg = 4; reg <= 12; reg++)
 	if ((save_reg_mask & (1 << reg)) == 0)
 	  break;
@@ -8955,10 +8954,7 @@ arm_compute_save_reg_mask (void)
       if (reg <= 12)
 	save_reg_mask |= (1 << reg);
       else
-	{
-	  cfun->machine->sibcall_blocked = 1;
-	  save_reg_mask |= (1 << 3);
-	}
+	save_reg_mask |= (1 << 3);
     }
 
   return save_reg_mask;
@@ -9088,6 +9084,19 @@ output_return_instruction (rtx operand, 
 	    }
 	}
 
+      /* If r3 is marked as a saved register, than it was saved just to
+	 preserve stack alignment.  We don't want to actually restore
+	 it if we're doing a sibcall, since it might have an outgoing
+	 argument by this point.  */
+      if (! really_return && (live_regs_mask & (1 << 3)))
+	{
+	  if (! TARGET_IWMMXT)
+	    abort ();
+	  sprintf (instr, "add%s\t%%|sp, %%|sp, #4", conditional);
+	  output_asm_insn (instr, & operand);
+	  live_regs_mask &= ~ (1 << 3);
+	}
+
       /* On some ARM architectures it is faster to use LDR rather than
 	 LDM to load a single register.  On other architectures, the
 	 cost is the same.  In 26 bit mode, or for exception handlers,
@@ -9521,6 +9530,18 @@ arm_output_epilogue (rtx sibling)
       else
 	saved_regs_mask &= ~ (1 << PC_REGNUM);
 
+      /* If r3 is marked as a saved register, than it was saved just to
+	 preserve stack alignment.  We don't want to actually restore
+	 it if we're doing a sibcall, since it might have an outgoing
+	 argument by this point.  */
+      if (! really_return && (saved_regs_mask & (1 << 3)))
+	{
+	  if (! TARGET_IWMMXT)
+	    abort ();
+	  asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
+	  saved_regs_mask &= ~ (1 << 3);
+	}
+
       /* We must use SP as the base register, because SP is one of the
          registers being restored.  If an interrupt or page fault
          happens in the ldm instruction, the SP might or might not
@@ -9638,6 +9659,18 @@ arm_output_epilogue (rtx sibling)
 	}
       else if (saved_regs_mask)
 	{
+	  /* If r3 is marked as a saved register, than it was saved just to
+	     preserve stack alignment.  We don't want to actually restore
+	     it if we're doing a sibcall, since it might have an outgoing
+	     argument by this point.  */
+	  if (! really_return && (saved_regs_mask & (1 << 3)))
+	    {
+	      if (! TARGET_IWMMXT)
+		abort ();
+	      asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
+	      saved_regs_mask &= ~ (1 << 3);
+	    }
+
 	  if (saved_regs_mask & (1 << SP_REGNUM))
 	    /* Note - write back to the stack register is not enabled
 	       (ie "ldmfd sp!...").  We know that the stack pointer is
--- /dev/null	1969-12-31 19:00:00.000000000 -0500
+++ testsuite/gcc.dg/arm-mmx-2.c	2004-04-21 11:14:41.000000000 -0400
@@ -0,0 +1,51 @@
+/* Verify that if r3 is saved to ensure stack alignment, it is not restored
+   to clobber a tail call argument register.  */
+/* { dg-do compile { target arm*-*-* strongarm*-*-* xscale*-*-* } } */
+/* { dg-options "-O2 -mapcs-frame -mcpu=iwmmxt -mabi=iwmmxt" } */
+/* { dg-final { global compiler_flags; if ![string match "*-mthumb *" $compiler_flags] { scan-assembler-not "ldmfd\[ 	]sp.*r3," } } } */
+
+struct foo {
+  int a, b, c;
+};
+
+int func1(int a, int b, int c, int d)
+{
+  return a + b + c + d;
+}
+
+volatile int i;
+
+void
+dummy(int a, int b, int c, int d, int e, int f)
+{
+  i = 1;
+}
+
+int glob[10];
+
+int func2(int a, int b, int c, struct foo foo)
+{
+  register int loc0, loc1, loc2, loc3, loc4, loc5, loc6, loc7, loc8, loc9;
+  loc0 = glob[0];
+  loc1 = glob[1];
+  loc2 = glob[2];
+  loc3 = glob[3];
+  loc4 = glob[4];
+  loc5 = glob[5];
+  loc6 = glob[6];
+  loc7 = glob[7];
+  loc8 = glob[8];
+  loc9 = glob[9];
+  dummy (a, b, c, a, b, c);
+  glob[0] = loc0;
+  glob[1] = loc1;
+  glob[2] = loc2;
+  glob[3] = loc3;
+  glob[4] = loc4;
+  glob[5] = loc5;
+  glob[6] = loc6;
+  glob[7] = loc7;
+  glob[8] = loc8;
+  glob[9] = loc9;
+  return func1(a, b, b, a);
+}
Index: config/arm/arm.h
===================================================================
RCS file: /big/fsf/rsync/gcc-cvs/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.230
diff -u -p -r1.230 arm.h
--- config/arm/arm.h	8 Apr 2004 19:02:20 -0000	1.230
+++ config/arm/arm.h	20 Apr 2004 22:16:04 -0000
@@ -1835,9 +1835,6 @@ typedef struct machine_function GTY(())
   unsigned long func_type;
   /* Record if the function has a variable argument list.  */
   int uses_anonymous_args;
-  /* Records if sibcalls are blocked because an argument
-     register is needed to preserve stack alignment.  */
-  int sibcall_blocked;
 }
 machine_function;
 


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