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]

[power7-meissner] Add more secondary_reload cases


This fixes a few more failures with secondary_reload.

2009-04-14  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config/rs6000/rs6000.c (rs6000_secondary_reload_inner): Handle
	more possible combinations of addresses.

	* config/rs6000/vector.md (vec_reload_and_plus_<mptrsize>): Allow
	register+small constant in addition to register+register, and
	restrict the insn to only match during reload and afterwards.
	(vec_reload_and_reg_<mptrsize>): Allow for and of register
	indirect to not generate insn not found message.

Index: gcc/config/rs6000/vector.md
===================================================================
--- gcc/config/rs6000/vector.md	(revision 145781)
+++ gcc/config/rs6000/vector.md	(working copy)
@@ -129,14 +129,15 @@
 })
 
 ;; Reload sometimes tries to move the address to a GPR, and can generate
-;; invalid RTL for addresses involving AND -16.
+;; invalid RTL for addresses involving AND -16.  Allow addresses involving
+;; reg+reg, reg+small constant, or just reg, all wrapped in an AND -16.
 
 (define_insn_and_split "*vec_reload_and_plus_<mptrsize>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
 	(and:P (plus:P (match_operand:P 1 "gpc_reg_operand" "r")
-		       (match_operand:P 2 "gpc_reg_operand" "r"))
+		       (match_operand:P 2 "reg_or_cint_operand" "rI"))
 	       (const_int -16)))]
-  "TARGET_ALTIVEC || TARGET_VSX"
+  "(TARGET_ALTIVEC || TARGET_VSX) && (reload_in_progress || reload_completed)"
   "#"
   "&& reload_completed"
   [(set (match_dup 0)
@@ -146,6 +147,21 @@
 		   (and:P (match_dup 0)
 			  (const_int -16)))
 	      (clobber:CC (scratch:CC))])])
+
+;; The normal ANDSI3/ANDDI3 won't match if reload decides to move an AND -16
+;; address to a register because there is no clobber of a (scratch), so we add
+;; it here.
+(define_insn_and_split "*vec_reload_and_reg_<mptrsize>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	(and:P (match_operand:P 1 "gpc_reg_operand" "r")
+	       (const_int -16)))]
+  "(TARGET_ALTIVEC || TARGET_VSX) && (reload_in_progress || reload_completed)"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0)
+		   (and:P (match_dup 1)
+			  (const_int -16)))
+	      (clobber:CC (scratch:CC))])])
 
 ;; Generic floating point vector arithmetic support
 (define_expand "add<mode>3"
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 145781)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -12574,6 +12574,11 @@ rs6000_secondary_reload_inner (rtx reg, 
   enum reg_class rclass;
   rtx addr;
   rtx and_op2 = NULL_RTX;
+  rtx addr_op1;
+  rtx addr_op2;
+  rtx scratch_or_premodify = scratch;
+  rtx and_rtx;
+  rtx cc_clobber;
 
   if (TARGET_DEBUG_ADDR)
     {
@@ -12595,7 +12600,8 @@ rs6000_secondary_reload_inner (rtx reg, 
 
   switch (rclass)
     {
-      /* Move reg+reg addresses into a scratch register for GPRs.  */
+      /* GPRs can handle reg + small constant, all other addresses need to use
+	 the scratch register.  */
     case GENERAL_REGS:
     case BASE_REGS:
       if (GET_CODE (addr) == AND)
@@ -12603,70 +12609,152 @@ rs6000_secondary_reload_inner (rtx reg, 
 	  and_op2 = XEXP (addr, 1);
 	  addr = XEXP (addr, 0);
 	}
+
+      if (GET_CODE (addr) == PRE_MODIFY)
+	{
+	  scratch_or_premodify = XEXP (addr, 0);
+	  gcc_assert (REG_P (scratch_or_premodify));
+	  gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
+	  addr = XEXP (addr, 1);
+	}
+
       if (GET_CODE (addr) == PLUS
 	  && (!rs6000_legitimate_offset_address_p (TImode, addr, true)
 	      || and_op2 != NULL_RTX))
 	{
-	  if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == CONST
-	      || GET_CODE (addr) == CONST_INT)
-	    rs6000_emit_move (scratch, addr, GET_MODE (addr));
-	  else
-	    emit_insn (gen_rtx_SET (VOIDmode, scratch, addr));
-	  addr = scratch;
+	  addr_op1 = XEXP (addr, 0);
+	  addr_op2 = XEXP (addr, 1);
+	  gcc_assert (legitimate_indirect_address_p (addr_op1, true));
+
+	  if (!REG_P (addr_op2)
+	      && (GET_CODE (addr_op2) != CONST_INT
+		  || !satisfies_constraint_I (addr_op2)))
+	    {
+	      rs6000_emit_move (scratch, addr_op2, Pmode);
+	      addr_op2 = scratch;
+	    }
+
+	  emit_insn (gen_rtx_SET (VOIDmode,
+				  scratch_or_premodify,
+				  gen_rtx_PLUS (Pmode,
+						addr_op1,
+						addr_op2)));
+
+	  addr = scratch_or_premodify;
+	  scratch_or_premodify = scratch;
 	}
-      else if (GET_CODE (addr) == PRE_MODIFY
-	       && REG_P (XEXP (addr, 0))
-	       && GET_CODE (XEXP (addr, 1)) == PLUS)
+      else if (!legitimate_indirect_address_p (addr, true)
+	       && !rs6000_legitimate_offset_address_p (TImode, addr, true))
 	{
-	  emit_insn (gen_rtx_SET (VOIDmode, XEXP (addr, 0), XEXP (addr, 1)));
-	  addr = XEXP (addr, 0);
+	  rs6000_emit_move (scratch_or_premodify, addr, Pmode);
+	  addr = scratch_or_premodify;
+	  scratch_or_premodify = scratch;
 	}
       break;
 
+      /* Float/Altivec registers can only handle reg+reg addressing.  Move
+	 other addresses into a scratch register.  */
+    case FLOAT_REGS:
+    case VSX_REGS:
+    case ALTIVEC_REGS:
+
       /* With float regs, we need to handle the AND ourselves, since we can't
 	 use the Altivec instruction with an implicit AND -16.  Allow scalar
 	 loads to float registers to use reg+offset even if VSX.  */
-    case FLOAT_REGS:
-    case VSX_REGS:
-      if (GET_CODE (addr) == AND)
+      if (GET_CODE (addr) == AND
+	  && (rclass != ALTIVEC_REGS || GET_MODE_SIZE (mode) != 16))
 	{
 	  and_op2 = XEXP (addr, 1);
 	  addr = XEXP (addr, 0);
 	}
-      /* fall through */
 
-      /* Move reg+offset addresses into a scratch register.  */
-    case ALTIVEC_REGS:
-      if (!legitimate_indirect_address_p (addr, true)
-	  && !legitimate_indexed_address_p (addr, true)
-	  && (GET_CODE (addr) != PRE_MODIFY
-	      || !legitimate_indexed_address_p (XEXP (addr, 1), true))
-	  && (rclass != FLOAT_REGS
-	      || GET_MODE_SIZE (mode) != 8
+      /* If we aren't using a VSX load, save the PRE_MODIFY register and use it
+	 as the address later.  */
+      if (GET_CODE (addr) == PRE_MODIFY
+	  && (!VECTOR_MEM_VSX_P (mode)
 	      || and_op2 != NULL_RTX
-	      || !rs6000_legitimate_offset_address_p (mode, addr, true)))
+	      || !legitimate_indexed_address_p (XEXP (addr, 1), true)))
 	{
-	  if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == CONST
-	      || GET_CODE (addr) == CONST_INT)
-	    rs6000_emit_move (scratch, addr, GET_MODE (addr));
-	  else
-	    emit_insn (gen_rtx_SET (VOIDmode, scratch, addr));
-	  addr = scratch;
+	  scratch_or_premodify = XEXP (addr, 0);
+	  gcc_assert (legitimate_indirect_address_p (scratch_or_premodify,
+						     true));
+	  gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
+	  addr = XEXP (addr, 1);
+	}
+
+      if (legitimate_indirect_address_p (addr, true)	/* reg */
+	  || legitimate_indexed_address_p (addr, true)	/* reg+reg */
+	  || GET_CODE (addr) == PRE_MODIFY		/* VSX pre-modify */
+	  || GET_CODE (addr) == AND			/* Altivec memory */
+	  || (rclass == FLOAT_REGS			/* legacy float mem */
+	      && GET_MODE_SIZE (mode) == 8
+	      && and_op2 == NULL_RTX
+	      && scratch_or_premodify == scratch
+	      && rs6000_legitimate_offset_address_p (mode, addr, true)))
+	;
+
+      else if (GET_CODE (addr) == PLUS)
+	{
+	  addr_op1 = XEXP (addr, 0);
+	  addr_op2 = XEXP (addr, 1);
+	  gcc_assert (REG_P (addr_op1));
+
+	  rs6000_emit_move (scratch, addr_op2, Pmode);
+	  emit_insn (gen_rtx_SET (VOIDmode,
+				  scratch_or_premodify,
+				  gen_rtx_PLUS (Pmode,
+						addr_op1,
+						scratch)));
+	  addr = scratch_or_premodify;
+	  scratch_or_premodify = scratch;
 	}
+
+      else if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == CONST
+	       || GET_CODE (addr) == CONST_INT)
+	{
+	  rs6000_emit_move (scratch_or_premodify, addr, Pmode);
+	  addr = scratch_or_premodify;
+	  scratch_or_premodify = scratch;
+	}
+
+      else
+	gcc_unreachable ();
+
       break;
 
     default:
       gcc_unreachable ();
     }
 
-  /* If the original address involved an AND -16 that is part of the Altivec
-     addresses, recreate the and now.  */
+  /* If the original address involved a pre-modify that we couldn't use the VSX
+     memory instruction with update, and we haven't taken care of already,
+     store the address in the pre-modify register and use that as the
+     address.  */
+  if (scratch_or_premodify != scratch && scratch_or_premodify != addr)
+    {
+      emit_insn (gen_rtx_SET (VOIDmode, scratch_or_premodify, addr));
+      addr = scratch_or_premodify;
+    }
+
+  /* If the original address involved an AND -16 and we couldn't use an ALTIVEC
+     memory instruction, recreate the AND now, including the clobber which is
+     generated by the general ANDSI3/ANDDI3 patterns for the
+     andi. instruction.  */
   if (and_op2 != NULL_RTX)
     {
-      rtx and_rtx = gen_rtx_SET (VOIDmode,
-				 scratch,
-				 gen_rtx_AND (Pmode, addr, and_op2));
-      rtx cc_clobber = gen_rtx_CLOBBER (CCmode, gen_rtx_SCRATCH (CCmode));
+      if (! legitimate_indirect_address_p (addr, true))
+	{
+	  emit_insn (gen_rtx_SET (VOIDmode, scratch, addr));
+	  addr = scratch;
+	}
+
+      and_rtx = gen_rtx_SET (VOIDmode,
+			     scratch,
+			     gen_rtx_AND (Pmode,
+					  addr,
+					  and_op2));
+
+      cc_clobber = gen_rtx_CLOBBER (CCmode, gen_rtx_SCRATCH (CCmode));
       emit_insn (gen_rtx_PARALLEL (VOIDmode,
 				   gen_rtvec (2, and_rtx, cc_clobber)));
       addr = scratch;


-- 
Michael Meissner, IBM
4 Technology Place Drive, MS 2203A, Westford, MA, 01886, USA
meissner@linux.vnet.ibm.com


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