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]

E500 subreg fixes


When generating PowerPC E500 SPE code, there are various problems with 
subregs associated with registers being 64 bits for some modes but 32 bits 
for others, and various associated instruction patterns and restrictions 
to address those problems.

Some of the patterns are restricted to DFmode in the TARGET_E500_DOUBLE 
case, but would equally apply with vector modes in the TARGET_SPE case, 
and are needed to avoid generic patterns such as movsi_internal1 getting 
used with the high part of a 64-bit register, for which such generic 
patterns will not work.  This patch extends the patterns that store into 
SImode subregs of 64-bit values to apply to the other modes, adds 
corresponding patterns that load values from those subregs, and adds 
memory alternatives.  It makes invalid_e500_subreg detect the high-part 
SImode subregs, and makes input_operand reject invalid subregs the same 
way rs6000_nonimmediate_operand does.

Tested with no regressions with crosses to powerpc-none-linux-gnuspe 
--enable-e500_double, mainline, 4.2 and 4.1.  This fixes the following 
test failures (in all three places):

FAIL: gcc.c-torture/execute/20050604-1.c execution,  -O0 
FAIL: gcc.c-torture/execute/pr23135.c execution,  -O0 
FAIL: gcc.dg/tree-ssa/gen-vect-25.c execution test

OK to commit to mainline, 4.2, 4.1?

2006-11-21  Joseph Myers  <joseph@codesourcery.com>

	* spe.md (SPE64): New mode macro.
	(mov_sidf_e500_subreg0): Change to mov_si<mode>_e500_subreg0.  Add
	memory load.
	(mov_si<mode>_e500_subreg0_2): New.
	(mov_sidf_e500_subreg4): Change to mov_si<mode>_e500_subreg4.  Add
	memory load.
	(mov_si<mode>_e500_subreg4_2): New.
	* predicates.md (input_operand): Do not allow invalid E500
	subregs.
	(rs6000_nonimmediate_operand): Check for invalid E500 subregs also
	if TARGET_SPE.
	* rs6000.c (invalid_e500_subreg): Check for subregs involving
	DFmode if TARGET_E500_DOUBLE.  Check for subregs involving vector
	modes if TARGET_SPE.

Index: spe.md
===================================================================
--- spe.md	(revision 118968)
+++ spe.md	(working copy)
@@ -32,6 +32,9 @@
    (E500_CR_IOR_COMPARE 1012)
    ])
 
+;; Modes using a 64-bit register.
+(define_mode_macro SPE64 [DF V4HI V2SF V1DI V2SI])
+
 (define_insn "*negsf2_gpr"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=r")
         (neg:SF (match_operand:SF 1 "gpc_reg_operand" "r")))]
@@ -2241,18 +2244,40 @@
 }"
   [(set_attr "length" "8,8")])
 
-(define_insn "*mov_sidf_e500_subreg0"
-  [(set (subreg:SI (match_operand:DF 0 "register_operand" "+r") 0)
-	(match_operand:SI 1 "register_operand" "r"))]
-  "TARGET_E500_DOUBLE"
-  "evmergelo %0,%1,%0")
+(define_insn "*mov_si<mode>_e500_subreg0"
+  [(set (subreg:SI (match_operand:SPE64 0 "register_operand" "+r,&r") 0)
+	(match_operand:SI 1 "input_operand" "r,m"))]
+  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode) || (TARGET_SPE && <MODE>mode != DFmode)"
+  "@
+   evmergelo %0,%1,%0
+   evmergelohi %0,%0,%0\;{l%U1%X1|lwz%U1%X1} %0,%1\;evmergelohi %0,%0,%0")
 
-(define_insn "*mov_sidf_e500_subreg4"
-  [(set (subreg:SI (match_operand:DF 0 "register_operand" "+r") 4)
-	(match_operand:SI 1 "register_operand" "r"))]
-  "TARGET_E500_DOUBLE"
-  "mr %0,%1")
+;; ??? Could use evstwwe for memory stores in some cases, depending on
+;; the offset.
+(define_insn "*mov_si<mode>_e500_subreg0_2"
+  [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
+	(subreg:SI (match_operand:SPE64 1 "register_operand" "+r,&r") 0))]
+  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode) || (TARGET_SPE && <MODE>mode != DFmode)"
+  "@
+   evmergehi %0,%0,%1
+   evmergelohi %1,%1,%1\;{st%U0%X0|stw%U0%X0} %1,%0")
 
+(define_insn "*mov_si<mode>_e500_subreg4"
+  [(set (subreg:SI (match_operand:SPE64 0 "register_operand" "+r,r") 4)
+	(match_operand:SI 1 "input_operand" "r,m"))]
+  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode) || (TARGET_SPE && <MODE>mode != DFmode)"
+  "@
+   mr %0,%1
+   {l%U1%X1|lwz%U1%X1} %0,%1")
+
+(define_insn "*mov_si<mode>_e500_subreg4_2"
+  [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
+	(subreg:SI (match_operand:SPE64 1 "register_operand" "r,r") 4))]
+  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode) || (TARGET_SPE && <MODE>mode != DFmode)"
+  "@
+   mr %0,%1
+   {st%U0%X0|stw%U0%X0} %1,%0")
+
 ;; FIXME: Allow r=CONST0.
 (define_insn "*movdf_e500_double"
   [(set (match_operand:DF 0 "rs6000_nonimmediate_operand" "=r,r,m")
Index: rs6000.c
===================================================================
--- rs6000.c	(revision 118968)
+++ rs6000.c	(working copy)
@@ -2713,20 +2713,31 @@
 bool
 invalid_e500_subreg (rtx op, enum machine_mode mode)
 {
-  /* Reject (subreg:SI (reg:DF)).  */
-  if (GET_CODE (op) == SUBREG
+  if (TARGET_E500_DOUBLE)
+    {
+      /* Reject (subreg:SI (reg:DF)).  */
+      if (GET_CODE (op) == SUBREG
+	  && mode == SImode
+	  && REG_P (SUBREG_REG (op))
+	  && GET_MODE (SUBREG_REG (op)) == DFmode)
+	return true;
+
+      /* Reject (subreg:DF (reg:DI)).  */
+      if (GET_CODE (op) == SUBREG
+	  && mode == DFmode
+	  && REG_P (SUBREG_REG (op))
+	  && GET_MODE (SUBREG_REG (op)) == DImode)
+	return true;
+    }
+
+  if (TARGET_SPE
+      && GET_CODE (op) == SUBREG
       && mode == SImode
       && REG_P (SUBREG_REG (op))
-      && GET_MODE (SUBREG_REG (op)) == DFmode)
+      && SPE_VECTOR_MODE (GET_MODE (SUBREG_REG (op)))
+      && SUBREG_BYTE (op) != 4)
     return true;
 
-  /* Reject (subreg:DF (reg:DI)).  */
-  if (GET_CODE (op) == SUBREG
-      && mode == DFmode
-      && REG_P (SUBREG_REG (op))
-      && GET_MODE (SUBREG_REG (op)) == DImode)
-    return true;
-
   return false;
 }
 
Index: predicates.md
===================================================================
--- predicates.md	(revision 118968)
+++ predicates.md	(working copy)
@@ -722,6 +722,12 @@
       && easy_vector_constant (op, mode))
     return 1;
 
+  /* Do not allow invalid E500 subregs.  */
+  if ((TARGET_E500_DOUBLE || TARGET_SPE)
+      && GET_CODE (op) == SUBREG
+      && invalid_e500_subreg (op, mode))
+    return 0;
+
   /* For floating-point or multi-word mode, the only remaining valid type
      is a register.  */
   if (SCALAR_FLOAT_MODE_P (mode)
@@ -756,7 +762,7 @@
 (define_predicate "rs6000_nonimmediate_operand"
   (match_code "reg,subreg,mem")
 {
-  if (TARGET_E500_DOUBLE
+  if ((TARGET_E500_DOUBLE || TARGET_SPE)
       && GET_CODE (op) == SUBREG
       && invalid_e500_subreg (op, mode))
     return 0;

-- 
Joseph S. Myers
joseph@codesourcery.com


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