File nov189571.diff of Package gcc41

Fixes nov #189571 == PR25062.
Backport of:
2006-05-23  Alexandre Oliva  <aoliva@redhat.com>

        * simplify-rtx.c (simplify_subreg): Adjust REG_OFFSET for
        big-endian paradoxical subregs.
        * var-tracking.c (struct micro_operation_def): Document that,
        for modify micro operations, insn is the subsequent instruction.
        (var_reg_delete_and_set, var_mem_delete_and_set): Split into...
        (var_reg_set, var_mem_set): ... new functions.
        (add_stores): Record subsequent insn.
        (compute_bb_dataflow): Use new functions for MO_USE.
        (emit_notes_in_bb): Use new functions for MO_USE.  Emit use
        notes after the insn, and modify notes before the insn known
        to be the subsequent one.
        (vt_initialize): Invert sorting of MO_CLOBBERs and MO_SETs.

Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	(revision 115205)
+++ gcc/simplify-rtx.c	(working copy)
@@ -3931,8 +3931,23 @@
       if (HARD_REGNO_MODE_OK (final_regno, outermode)
 	  || ! HARD_REGNO_MODE_OK (regno, innermode))
 	{
-	  rtx x = gen_rtx_REG_offset (op, outermode, final_regno, byte);
+	  rtx x;
+	  int final_offset = byte;
 
+	  /* Adjust offset for paradoxical subregs.  */
+	  if (byte == 0
+	      && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
+	    {
+	      int difference = (GET_MODE_SIZE (innermode)
+				- GET_MODE_SIZE (outermode));
+	      if (WORDS_BIG_ENDIAN)
+		final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+	      if (BYTES_BIG_ENDIAN)
+		final_offset += difference % UNITS_PER_WORD;
+	    }
+
+	  x = gen_rtx_REG_offset (op, outermode, final_regno, final_offset);
+
 	  /* Propagate original regno.  We don't have any way to specify
 	     the offset inside original regno, so do so only for lowpart.
 	     The information is used only by alias analysis that can not
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	(revision 115205)
+++ gcc/var-tracking.c	(working copy)
@@ -140,7 +140,11 @@
     HOST_WIDE_INT adjust;
   } u;
 
-  /* The instruction which the micro operation is in.  */
+  /* The instruction which the micro operation is in, for MO_USE,
+     MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent
+     instruction or note in the original flow (before any var-tracking
+     notes are inserted, to simplify emission of notes), for MO_SET
+     and MO_CLOBBER.  */
   rtx insn;
 } micro_operation;
 
@@ -291,9 +295,11 @@
 static variable unshare_variable (dataflow_set *set, variable var);
 static int vars_copy_1 (void **, void *);
 static void vars_copy (htab_t, htab_t);
+static void var_reg_set (dataflow_set *, rtx);
 static void var_reg_delete_and_set (dataflow_set *, rtx);
 static void var_reg_delete (dataflow_set *, rtx);
 static void var_regno_delete (dataflow_set *, int);
+static void var_mem_set (dataflow_set *, rtx);
 static void var_mem_delete_and_set (dataflow_set *, rtx);
 static void var_mem_delete (dataflow_set *, rtx);
 
@@ -792,6 +798,19 @@
   htab_traverse (src, vars_copy_1, dst);
 }
 
+/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
+
+static void
+var_reg_set (dataflow_set *set, rtx loc)
+{
+  tree decl = REG_EXPR (loc);
+  HOST_WIDE_INT offset = REG_OFFSET (loc);
+
+  if (set->regs[REGNO (loc)] == NULL)
+    attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
+  set_variable_part (set, loc, decl, offset);
+}
+
 /* Delete current content of register LOC in dataflow set SET
    and set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
 
@@ -819,9 +838,7 @@
 	  nextp = &node->next;
 	}
     }
-  if (set->regs[REGNO (loc)] == NULL)
-    attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
-  set_variable_part (set, loc, decl, offset);
+  var_reg_set (set, loc);
 }
 
 /* Delete current content of register LOC in dataflow set SET.  */
@@ -858,12 +875,12 @@
   *reg = NULL;
 }
 
-/* Delete and set the location part of variable MEM_EXPR (LOC)
-   in dataflow set SET to LOC.
+/* Set the location part of variable MEM_EXPR (LOC) in dataflow set
+   SET to LOC.
    Adjust the address first if it is stack pointer based.  */
 
 static void
-var_mem_delete_and_set (dataflow_set *set, rtx loc)
+var_mem_set (dataflow_set *set, rtx loc)
 {
   tree decl = MEM_EXPR (loc);
   HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
@@ -871,6 +888,16 @@
   set_variable_part (set, loc, decl, offset);
 }
 
+/* Delete and set the location part of variable MEM_EXPR (LOC)
+   in dataflow set SET to LOC.
+   Adjust the address first if it is stack pointer based.  */
+
+static void
+var_mem_delete_and_set (dataflow_set *set, rtx loc)
+{
+  var_mem_set (set, loc);
+}
+
 /* Delete the location part LOC from dataflow set SET.
    Adjust the address first if it is stack pointer based.  */
 
@@ -1547,7 +1574,7 @@
 		   && track_expr_p (REG_EXPR (loc)))
 		  ? MO_SET : MO_CLOBBER);
       mo->u.loc = loc;
-      mo->insn = (rtx) insn;
+      mo->insn = NEXT_INSN ((rtx) insn);
     }
   else if (MEM_P (loc)
 	   && MEM_EXPR (loc)
@@ -1558,7 +1585,7 @@
 
       mo->type = GET_CODE (expr) == CLOBBER ? MO_CLOBBER : MO_SET;
       mo->u.loc = loc;
-      mo->insn = (rtx) insn;
+      mo->insn = NEXT_INSN ((rtx) insn);
     }
 }
 
@@ -1589,6 +1616,16 @@
 	    break;
 
 	  case MO_USE:
+	    {
+	      rtx loc = VTI (bb)->mos[i].u.loc;
+
+	      if (GET_CODE (loc) == REG)
+		var_reg_set (out, loc);
+	      else if (GET_CODE (loc) == MEM)
+		var_mem_set (out, loc);
+	    }
+	    break;
+
 	  case MO_SET:
 	    {
 	      rtx loc = VTI (bb)->mos[i].u.loc;
@@ -2356,6 +2393,18 @@
 	    break;
 
 	  case MO_USE:
+	    {
+	      rtx loc = VTI (bb)->mos[i].u.loc;
+
+	      if (GET_CODE (loc) == REG)
+		var_reg_set (&set, loc);
+	      else
+		var_mem_set (&set, loc);
+
+	      emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+	    }
+	    break;
+
 	  case MO_SET:
 	    {
 	      rtx loc = VTI (bb)->mos[i].u.loc;
@@ -2365,10 +2414,7 @@
 	      else
 		var_mem_delete_and_set (&set, loc);
 
-	      if (VTI (bb)->mos[i].type == MO_USE)
-		emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
-	      else
-		emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+	      emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
 	    }
 	    break;
 
@@ -2383,9 +2429,9 @@
 		var_mem_delete (&set, loc);
 
 	      if (VTI (bb)->mos[i].type == MO_USE_NO_VAR)
+		emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+	      else
 		emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
-	      else
-		emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
 	    }
 	    break;
 
@@ -2599,15 +2645,18 @@
 		}
 
 	      n1 = VTI (bb)->n_mos;
+	      /* This will record NEXT_INSN (insn), such that we can
+		 insert notes before it without worrying about any
+		 notes that MO_USEs might emit after the insn.  */
 	      note_stores (PATTERN (insn), add_stores, insn);
 	      n2 = VTI (bb)->n_mos - 1;
 
-	      /* Order the MO_SETs to be before MO_CLOBBERs.  */
+	      /* Order the MO_CLOBBERs to be before MO_SETs.  */
 	      while (n1 < n2)
 		{
-		  while (n1 < n2 && VTI (bb)->mos[n1].type == MO_SET)
+		  while (n1 < n2 && VTI (bb)->mos[n1].type == MO_CLOBBER)
 		    n1++;
-		  while (n1 < n2 && VTI (bb)->mos[n2].type == MO_CLOBBER)
+		  while (n1 < n2 && VTI (bb)->mos[n2].type == MO_SET)
 		    n2--;
 		  if (n1 < n2)
 		    {
openSUSE Build Service is sponsored by