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]

Don't lose asm sets of frame pointer


This fixes PR 13169, so that global_alloc now sees all regs set or
clobbered by asm statements.  Previously, we had the situation that not
all regs set in an asm were noticed in regs_ever_live.  In particular, a
set of the frame pointer isn't marked, but asms ought to be able to use
the frame pointer reg when -fomit-frame-pointer and other requirements
like no alloca in the function are met.  On ppc, we also have a curious
fudge in ELIMINABLE_REGS with r30 being "eliminated" to itself, which
made r30 dangerous to use in an asm.  See the PR for more details on
what currently happens.

	PR 13169
	* basic-block.h (PROP_ASM_SCAN): Define.
	* final.c (regs_asm_clobbered): New array.
	* regs.h (regs_asm_clobbered): Declare.
	* flow.c (life_analysis): Init it.
	(mark_set_regs): Set PROP_ASM_SCAN for asms.
	(mark_set_1): Set regs_asm_clobbered.
	* global.c (global_alloc): Don't set eliminable_regset when
	regs_asm_clobbered.

Bootstrapped and tested on the 3.3 branch.  Mainline regression test in
progress.

diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/basic-block.h gcc-ppc64-34/gcc/basic-block.h
--- gcc-ppc64-34.orig/gcc/basic-block.h	2003-07-19 22:50:33.000000000 +0930
+++ gcc-ppc64-34/gcc/basic-block.h	2003-11-25 00:51:13.000000000 +1030
@@ -477,6 +477,8 @@ enum update_life_extent
 #define PROP_AUTOINC		64	/* Create autoinc mem references.  */
 #define PROP_EQUAL_NOTES	128	/* Take into account REG_EQUAL notes.  */
 #define PROP_SCAN_DEAD_STORES	256	/* Scan for dead code.  */
+#define PROP_ASM_SCAN		512	/* Internal flag used within flow.c
+					   to flag analysis of asms.  */
 #define PROP_FINAL		(PROP_DEATH_NOTES | PROP_LOG_LINKS  \
 				 | PROP_REG_INFO | PROP_KILL_DEAD_CODE  \
 				 | PROP_SCAN_DEAD_CODE | PROP_AUTOINC \
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/final.c gcc-ppc64-34/gcc/final.c
--- gcc-ppc64-34.orig/gcc/final.c	2003-11-01 11:13:55.000000000 +1030
+++ gcc-ppc64-34/gcc/final.c	2003-11-25 00:29:46.000000000 +1030
@@ -170,6 +170,12 @@ CC_STATUS cc_prev_status;
 
 char regs_ever_live[FIRST_PSEUDO_REGISTER];
 
+/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
+   Unlike regs_ever_live, elements of this array corresponding to
+   eliminable regs like the frame pointer are set if an asm sets them.  */
+
+char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
+
 /* Nonzero means current function must be given a frame pointer.
    Set in stmt.c if anything is allocated on the stack there.
    Set in reload1.c if anything is allocated on the stack there.  */
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/flow.c gcc-ppc64-34/gcc/flow.c
--- gcc-ppc64-34.orig/gcc/flow.c	2003-11-25 00:17:41.000000000 +1030
+++ gcc-ppc64-34/gcc/flow.c	2003-11-25 00:29:46.000000000 +1030
@@ -463,7 +463,10 @@ life_analysis (rtx f, FILE *file, int fl
      is not immediately handy.  */
 
   if (flags & PROP_REG_INFO)
-    memset (regs_ever_live, 0, sizeof (regs_ever_live));
+    {
+      memset (regs_ever_live, 0, sizeof (regs_ever_live));
+      memset (regs_asm_clobbered, 0, sizeof (regs_asm_clobbered));
+    }
   update_life_info (NULL, UPDATE_LIFE_GLOBAL, flags);
 
   /* Clean up.  */
@@ -2444,6 +2447,7 @@ mark_set_regs (struct propagate_block_in
   rtx cond = NULL_RTX;
   rtx link;
   enum rtx_code code;
+  int flags = pbi->flags;
 
   if (insn)
     for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
@@ -2452,14 +2456,17 @@ mark_set_regs (struct propagate_block_in
 	  mark_set_1 (pbi, SET, XEXP (link, 0),
 		      (GET_CODE (x) == COND_EXEC
 		       ? COND_EXEC_TEST (x) : NULL_RTX),
-		      insn, pbi->flags);
+		      insn, flags);
       }
  retry:
   switch (code = GET_CODE (x))
     {
     case SET:
+      if (GET_CODE (XEXP (x, 1)) == ASM_OPERANDS)
+	flags |= PROP_ASM_SCAN;
+      /* Fall thru */
     case CLOBBER:
-      mark_set_1 (pbi, code, SET_DEST (x), cond, insn, pbi->flags);
+      mark_set_1 (pbi, code, SET_DEST (x), cond, insn, flags);
       return;
 
     case COND_EXEC:
@@ -2482,13 +2489,20 @@ mark_set_regs (struct propagate_block_in
 
 		cond = COND_EXEC_TEST (sub);
 		sub = COND_EXEC_CODE (sub);
-		if (GET_CODE (sub) != SET && GET_CODE (sub) != CLOBBER)
-		  break;
-		/* Fall through.  */
+		if (GET_CODE (sub) == SET)
+		  goto mark_set;
+		if (GET_CODE (sub) == CLOBBER)
+		  goto mark_clob;
+		break;
 
 	      case SET:
+	      mark_set:
+		if (GET_CODE (XEXP (sub, 1)) == ASM_OPERANDS)
+		  flags |= PROP_ASM_SCAN;
+		/* Fall thru */
 	      case CLOBBER:
-		mark_set_1 (pbi, code, SET_DEST (sub), cond, insn, pbi->flags);
+	      mark_clob:
+		mark_set_1 (pbi, code, SET_DEST (sub), cond, insn, flags);
 		break;
 
 	      default:
@@ -2712,6 +2726,9 @@ mark_set_1 (struct propagate_block_info 
 		{
 		  for (i = regno_first; i <= regno_last; i++)
 		    regs_ever_live[i] = 1;
+		  if (flags & PROP_ASM_SCAN)
+		    for (i = regno_first; i <= regno_last; i++)
+		      regs_asm_clobbered[i] = 1;
 		}
 	      else
 		{
@@ -2797,6 +2814,14 @@ mark_set_1 (struct propagate_block_info 
     {
       if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
 	pbi->reg_next_use[regno_first] = 0;
+
+      if ((flags & PROP_REG_INFO) != 0
+	  && (flags & PROP_ASM_SCAN) != 0
+	  &&  regno_first < FIRST_PSEUDO_REGISTER)
+	{
+	  for (i = regno_first; i <= regno_last; i++)
+	    regs_asm_clobbered[i] = 1;
+	}
     }
 
   /* If this is the last pass and this is a SCRATCH, show it will be dying
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/global.c gcc-ppc64-34/gcc/global.c
--- gcc-ppc64-34.orig/gcc/global.c	2003-07-20 13:40:21.000000000 +0930
+++ gcc-ppc64-34/gcc/global.c	2003-11-25 00:29:46.000000000 +1030
@@ -342,23 +342,30 @@ global_alloc (FILE *file)
      that we already know won't be eliminated.  */
 #ifdef ELIMINABLE_REGS
   for (i = 0; i < ARRAY_SIZE (eliminables); i++)
-    {
-      SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
+    if (!regs_asm_clobbered[eliminables[i].from])
+      {
+	SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
 
-      if (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
-	  || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp))
-	SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
-    }
+	if (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
+	    || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp))
+	  SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
+      }
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-  SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
-  if (need_fp)
-    SET_HARD_REG_BIT (no_global_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+  if (!regs_asm_clobbered[HARD_FRAME_POINTER_REGNUM])
+    {
+      SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
+      if (need_fp)
+	SET_HARD_REG_BIT (no_global_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+    }
 #endif
 
 #else
-  SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
-  if (need_fp)
-    SET_HARD_REG_BIT (no_global_alloc_regs, FRAME_POINTER_REGNUM);
+  if (!regs_asm_clobbered[FRAME_POINTER_REGNUM])
+    {
+      SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
+      if (need_fp)
+	SET_HARD_REG_BIT (no_global_alloc_regs, FRAME_POINTER_REGNUM);
+    }
 #endif
 
   /* Track which registers have already been used.  Start with registers
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/regs.h gcc-ppc64-34/gcc/regs.h
--- gcc-ppc64-34.orig/gcc/regs.h	2003-07-14 14:07:26.000000000 +0930
+++ gcc-ppc64-34/gcc/regs.h	2003-11-25 00:30:50.000000000 +1030
@@ -153,11 +153,14 @@ extern bitmap_head subregs_of_mode;
 
 extern short *reg_renumber;
 
-/* Vector indexed by hardware reg
-   saying whether that reg is ever used.  */
+/* Vector indexed by hardware reg saying whether that reg is ever used.  */
 
 extern char regs_ever_live[FIRST_PSEUDO_REGISTER];
 
+/* Like regs_ever_live, but saying whether reg is set by asm statements.  */
+
+extern char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
+
 /* For each hard register, the widest mode object that it can contain.
    This will be a MODE_INT mode if the register can hold integers.  Otherwise
    it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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