In preparation for some other changes to the Nios II prologue code that are in my queue, I've checked in the attached patch to the stack limit checking logic. With this patch, the check generation code now takes an offset so that the check can be emitted before the SP adjustment; this allows cases where multiple stack adjustments are emitted to do only a single stack limit check.

While I was at it, I also added support for -fstack-limit-symbol as well as -fstack-limit-register.

-Sandra

2015-07-14  Sandra Loosemore  <san...@codesourcery.com>

	gcc/
	* config/nios2/nios2.c (TEMP_REG_NUM): Move define up in file.
	(nios2_emit_stack_limit_check): Add size parameter.  Handle
	-fstack-limit-symbol as well as -fstack-limit-register.
	(nios2_expand_prologue): Emit only a single stack limit check,
	even if multiple stack adjustments are required.
	(nios2_option_override): Diagnose unsupported combination of -fpic
	and -stack-limit-symbol.

	gcc/testsuite/
	* gcc.target/nios2/nios2-stack-check-1.c: Adjust patterns.
	* gcc.target/nios2/nios2-stack-check-2.c: Likewise.
	* gcc.target/nios2/nios2-stack-check-3.c: New test case.
Index: gcc/testsuite/gcc.target/nios2/nios2-stack-check-1.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/nios2-stack-check-1.c	(revision 225722)
+++ gcc/testsuite/gcc.target/nios2/nios2-stack-check-1.c	(working copy)
@@ -1,7 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-fstack-limit-register=et" } */
-/* { dg-final { scan-assembler "bgeu\\tsp, et" } } */
-/* { dg-final { scan-assembler "trap\\t3" } } */
+/* { dg-final { scan-assembler "bgeu\\tsp, " } } */
+/* { dg-final { scan-assembler "trap\\t3|trap.n\\t3" } } */
+
 /* check stack checking */
 void test()
 {
Index: gcc/testsuite/gcc.target/nios2/nios2-stack-check-2.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/nios2-stack-check-2.c	(revision 225722)
+++ gcc/testsuite/gcc.target/nios2/nios2-stack-check-2.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options " " } */
-/* { dg-final { scan-assembler-not "bgeu\\tsp, et" } } */
-/* { dg-final { scan-assembler-not "break\\t3" } } */
+/* { dg-final { scan-assembler-not "trap\\t3|trap.n\\t3" } } */
+
 /* check stack checking */
 void test()
 {
Index: gcc/testsuite/gcc.target/nios2/nios2-stack-check-3.c
===================================================================
--- gcc/testsuite/gcc.target/nios2/nios2-stack-check-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/nios2/nios2-stack-check-3.c	(revision 0)
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fstack-limit-symbol=__stackend -fno-pic" } */
+/* { dg-final { scan-assembler "movhi\\t.*, %hiadj\\(__stackend.*\\)" } } */
+/* { dg-final { scan-assembler "addi\\t.*, .*, %lo\\(__stackend.*\\)" } } */
+/* { dg-final { scan-assembler "bgeu\\tsp, " } } */
+/* { dg-final { scan-assembler "trap\\t3|trap.n\\t3" } } */
+
+/* check stack checking */
+void test()
+{
+  int a, b, c;
+}
Index: gcc/config/nios2/nios2.c
===================================================================
--- gcc/config/nios2/nios2.c	(revision 225722)
+++ gcc/config/nios2/nios2.c	(working copy)
@@ -456,20 +456,47 @@ restore_reg (int regno, unsigned offset)
   RTX_FRAME_RELATED_P (insn) = 1;
 }
 
-/* Emit conditional trap for checking stack limit.  */
+/* Temp regno used inside prologue/epilogue.  */
+#define TEMP_REG_NUM 8
+
+/* Emit conditional trap for checking stack limit.  SIZE is the number of
+   additional bytes required.  
+
+   GDB prologue analysis depends on this generating a direct comparison
+   to the SP register, so the adjustment to add SIZE needs to be done on
+   the other operand to the comparison.  Use TEMP_REG_NUM as a temporary,
+   if necessary.  */
 static void
-nios2_emit_stack_limit_check (void)
+nios2_emit_stack_limit_check (int size)
 {
-  if (REG_P (stack_limit_rtx))
-    emit_insn (gen_ctrapsi4 (gen_rtx_LTU (VOIDmode, stack_pointer_rtx,
-					  stack_limit_rtx),
-			     stack_pointer_rtx, stack_limit_rtx, GEN_INT (3)));
+  rtx sum;
+
+  if (GET_CODE (stack_limit_rtx) == SYMBOL_REF)
+    {
+      /* This generates a %hiadj/%lo pair with the constant size
+	 add handled by the relocations.  */
+      sum = gen_rtx_REG (Pmode, TEMP_REG_NUM);
+      emit_move_insn (sum, plus_constant (Pmode, stack_limit_rtx, size));
+    }
+  else if (!REG_P (stack_limit_rtx))
+    sorry ("Unknown form for stack limit expression");
+  else if (size == 0)
+    sum = stack_limit_rtx;
+  else if (SMALL_INT (size))
+    {
+      sum = gen_rtx_REG (Pmode, TEMP_REG_NUM);
+      emit_move_insn (sum, plus_constant (Pmode, stack_limit_rtx, size));
+    }
   else
-    sorry ("only register based stack limit is supported");
-}
+    {
+      sum = gen_rtx_REG (Pmode, TEMP_REG_NUM);
+      emit_move_insn (sum, gen_int_mode (size, Pmode));
+      emit_insn (gen_add2_insn (sum, stack_limit_rtx));
+    }
 
-/* Temp regno used inside prologue/epilogue.  */
-#define TEMP_REG_NUM 8
+  emit_insn (gen_ctrapsi4 (gen_rtx_LTU (VOIDmode, stack_pointer_rtx, sum),
+			   stack_pointer_rtx, sum, GEN_INT (3)));
+}
 
 static rtx_insn *
 nios2_emit_add_constant (rtx reg, HOST_WIDE_INT immed)
@@ -511,6 +538,8 @@ nios2_expand_prologue (void)
       RTX_FRAME_RELATED_P (insn) = 1;
       save_regs_base = 0;
       sp_offset = -cfun->machine->save_regs_offset;
+      if (crtl->limit_stack)
+	nios2_emit_stack_limit_check (cfun->machine->save_regs_offset);
     }
   else if (total_frame_size)
     {
@@ -520,13 +549,12 @@ nios2_expand_prologue (void)
       RTX_FRAME_RELATED_P (insn) = 1;
       save_regs_base = cfun->machine->save_regs_offset;
       sp_offset = 0;
+      if (crtl->limit_stack)
+	nios2_emit_stack_limit_check (0);
     }
   else
     save_regs_base = sp_offset = 0;
 
-  if (crtl->limit_stack)
-    nios2_emit_stack_limit_check ();
-
   save_offset = save_regs_base + cfun->machine->save_reg_size;
 
   for (regno = LAST_GP_REG; regno > 0; regno--)
@@ -561,9 +589,6 @@ nios2_expand_prologue (void)
 	  add_reg_note (insn, REG_FRAME_RELATED_EXPR, sp_adjust);
 	}
       RTX_FRAME_RELATED_P (insn) = 1;
-
-      if (crtl->limit_stack)
-	nios2_emit_stack_limit_check ();
     }
 
   /* Load the PIC register if needed.  */
@@ -1029,6 +1054,9 @@ nios2_option_override (void)
   /* Check for unsupported options.  */
   if (flag_pic && !TARGET_LINUX_ABI)
     sorry ("position-independent code requires the Linux ABI");
+  if (flag_pic && stack_limit_rtx
+      && GET_CODE (stack_limit_rtx) == SYMBOL_REF)
+    sorry ("PIC support for -fstack-limit-symbol");
 
   /* Function to allocate machine-dependent function status.  */
   init_machine_status = &nios2_init_machine_status;

Reply via email to