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]

SMALL_REGISTER_CLASSES fixes for combine.c


While trying to make the Linux kernel compile with -mregparm=3 on ix86, I
noticed some problems with the handling of SMALL_REGISTER_CLASSES in combine.
On a S_R_C machine, the lifetime of hard registers must be kept to a minimum,
and it is not valid to use hard regs in arbitrary insns.  For example, one
problem that can currently occur is when combine sees a sequence like this
[from linux-2.1.130, fs/ext2/inode.c]:

(set (pseudo 1) (ashift (pseudo2) (pseudo 3)))
[.. insns ..]
(set (ecx) (pseudo1))

and changes it to read:

[.. insns ..]
(set (ecx) (ashift (pseudo2) (pseudo 3)))

which reload can't handle. Similar problems can happen in the reverse
direction, e.g. [arch/i386/kernel/traps.c]:

(set (pseudo) (hardreg))
(insn (.. use pseudo somehow...))

gets combined to use the hardreg within insn, which can also lead to similar
compiler aborts.

The patch below changes the SMALL_REGISTER_CLASSES handling in combine.c to
be extremely conservative.  It assumes that the rtl generation phase ensures
that hard regs are only used in insns that copy them in or out of pseudos
(there are some exceptions; e.g. calls or insns that explicitly clobber hard
regs, but these should be handled properly by the patch as well), and
disallows any combinations involving such insns.

This patch makes it possible to compile a working 2.1.130 kernel with
-mregparm=3 (although the kernel needs a few patches as well to get the
calling conventions right everywhere).

Bernd

	* combine.c (insn_unsafe_p): New function.
	(can_combine_p): Don't do tests depending on SMALL_REGISTER_CLASSES.
	(combinable_i3pat): Likewise.
	(try_combine): Likewise.
	Add new test for SMALL_REGISTER_CLASSES; call insn_unsafe_p for
	each of the involved insns and do nothing if it returns true.


diff -u -p -r1.1.1.44 combine.c
--- combine.c	1998/11/13 10:03:03	1.1.1.44
+++ combine.c	1998/11/27 18:22:43
@@ -395,6 +395,7 @@ static void set_nonzero_bits_and_sign_co
 static int can_combine_p	PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *));
 static int sets_function_arg_p	PROTO((rtx));
 static int combinable_i3pat	PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
+static int insn_unsafe_p	PROTO((rtx));
 static rtx try_combine		PROTO((rtx, rtx, rtx));
 static void undo_all		PROTO((void));
 static rtx *find_split_point	PROTO((rtx *, rtx));
@@ -999,32 +1000,17 @@ can_combine_p (insn, i3, pred, succ, pde
 	 cases except for parameters, it is possible to have a register copy
 	 insn referencing a hard register that is not allowed to contain the
 	 mode being copied and which would not be valid as an operand of most
-	 insns.  Eliminate this problem by not combining with such an insn.
+	 insns.  Eliminate this problem by not combining with such an
+	 insn.  */
 
-	 Also, on some machines we don't want to extend the life of a hard
-	 register.
-
-	 This is the same test done in can_combine except that we don't test
-	 if SRC is a CALL operation to permit a hard register with
-	 SMALL_REGISTER_CLASSES, and that we have to take all_adjacent
-	 into account.  */
-
       if (GET_CODE (src) == REG
 	  && ((REGNO (dest) < FIRST_PSEUDO_REGISTER
 	       && ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest)))
-	      /* Don't extend the life of a hard register unless it is
-		 user variable (if we have few registers) or it can't
+	      /* Don't extend the life of a hard register if it can't
 		 fit into the desired register (meaning something special
-		 is going on).
-		 Also avoid substituting a return register into I3, because
-		 reload can't handle a conflict with constraints of other
-		 inputs.  */
+		 is going on).  */
 	      || (REGNO (src) < FIRST_PSEUDO_REGISTER
-		  && (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))
-		      || (SMALL_REGISTER_CLASSES
-			  && ((! all_adjacent && ! REG_USERVAR_P (src))
-			      || (FUNCTION_VALUE_REGNO_P (REGNO (src))
-				  && ! REG_USERVAR_P (src))))))))
+		  && ! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src)))))
 	return 0;
     }
   else if (GET_CODE (dest) != CC0)
@@ -1179,10 +1165,6 @@ sets_function_arg_p (pat)
    If I1_NOT_IN_SRC is non-zero, it means that finding I1 in the source
    of a SET must prevent combination from occurring.
 
-   On machines where SMALL_REGISTER_CLASSES is non-zero, we don't combine
-   if the destination of a SET is a hard register that isn't a user
-   variable.
-
    Before doing the above check, we first try to expand a field assignment
    into a set of logical operations.
 
@@ -1251,27 +1233,12 @@ combinable_i3pat (i3, loc, i2dest, i1des
 	   && (reg_overlap_mentioned_p (i2dest, inner_dest)
 	       || (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
 
-	  /* This is the same test done in can_combine_p except that we
-	     allow a hard register with SMALL_REGISTER_CLASSES if SRC is a
-	     CALL operation. Moreover, we can't test all_adjacent; we don't
-	     have to, since this instruction will stay in place, thus we are
-	     not considering increasing the lifetime of INNER_DEST.
-
-	     Also, if this insn sets a function argument, combining it with
-	     something that might need a spill could clobber a previous
-	     function argument; the all_adjacent test in can_combine_p also
-	     checks this; here, we do a more specific test for this case.  */
-	     
+	  /* This is the same test done in can_combine_p.  */
 	  || (GET_CODE (inner_dest) == REG
 	      && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
 	      && (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
-					GET_MODE (inner_dest))
-		 || (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL
-		     && ! REG_USERVAR_P (inner_dest)
-		     && (FUNCTION_VALUE_REGNO_P (REGNO (inner_dest))
-			 || (FUNCTION_ARG_REGNO_P (REGNO (inner_dest))
-			     && i3 != 0
-			     && sets_function_arg_p (prev_nonnote_insn (i3)))))))
+					GET_MODE (inner_dest))))
+
 	  || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
 	return 0;
 
@@ -1312,6 +1279,32 @@ combinable_i3pat (i3, loc, i2dest, i1des
   return 1;
 }
 
+/* On SMALL_REGISTER_CLASSES machines, hard registers should only be used
+   in insns that copy them into or out of pseudos.  This function returns
+   nonzero if INSN uses a hard reg in such a way; it is unsafe to combine
+   it in that case.  */
+static int
+insn_unsafe_p (insn)
+     rtx insn;
+{
+  rtx set, x;
+  if (insn == 0)
+    return 0;
+  set = single_set (insn);
+  if (! set)
+    return 0;
+  x = SET_DEST (set);
+  if (GET_CODE (x) == REG
+      && REGNO (x) < FIRST_PSEUDO_REGISTER
+      && ! REG_USERVAR_P (x))
+    return 1;
+  x = SET_SRC (set);
+  if (GET_CODE (x) == REG
+      && REGNO (x) < FIRST_PSEUDO_REGISTER
+      && ! REG_USERVAR_P (x))
+    return 1;
+  return 0;
+}
 /* Try to combine the insns I1 and I2 into I3.
    Here I1 and I2 appear earlier than I3.
    I1 can be zero; then we combine just I2 into I3.
@@ -1362,6 +1355,10 @@ try_combine (i3, i2, i1)
   register rtx link;
   int i;
 
+  if (SMALL_REGISTER_CLASSES
+      && (insn_unsafe_p (i1) || insn_unsafe_p (i2) || insn_unsafe_p (i3)))
+    return 0;
+
   /* If any of I1, I2, and I3 isn't really an insn, we can't do anything.
      This can occur when flow deletes an insn that it has merged into an
      auto-increment address.  We also can't do anything if I3 has a
@@ -1414,10 +1411,6 @@ try_combine (i3, i2, i1)
   if (i1 == 0 && GET_CODE (i3) == INSN && GET_CODE (PATTERN (i3)) == SET
       && GET_CODE (SET_SRC (PATTERN (i3))) == REG
       && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
-      && (! SMALL_REGISTER_CLASSES
-	  || (GET_CODE (SET_DEST (PATTERN (i3))) != REG
-	      || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
-	      || REG_USERVAR_P (SET_DEST (PATTERN (i3)))))
       && find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
       && GET_CODE (PATTERN (i2)) == PARALLEL
       && ! side_effects_p (SET_DEST (PATTERN (i3)))



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