[Patch]: Splitter for Altivec moves

Hartmut Penner HPENNER@de.ibm.com
Fri Jun 27 16:33:00 GMT 2003


> Did you test with the little endian multilibs?  Just curious, because
> I think there are endianness issues with your patch.
No, I did not test eith little endian. Right now I don't see the endian
issue. As I read
the altivec abi, the altivec vectors are big endian.

> Also, could you please come up with a testcase that triggers at least
> one of the conditions, ideally all of them?

With the eabi it is hard to issue code using the splitter. But
on the AIX abi using altivec and varargs this splitter are definitly
used. But to use altivec on AIX some more patches are needed and
this patches here a prerequisit. Maybe I can put out some testcases
later together with the AIX altivec patches.

Hartmut

2003-06-26  Hartmut Penner  <hpenner@de.ibm.com>

      * config/rs6000/rs6000.c (rs6000_split_altivec_in_gprs): New function.
      (altivec_in_gprs_p): New function.

      * config/rs6000/rs6000-protos (rs6000_split_altivec_in_gprs): New
      prototype.
      (altivec_in_gprs_p): New prototype.

            * config/rs6000/altivec.md (*movv4si_internal): Change
      multi-assembler alternative to '#'. Add postreload splitter to
      handle this cases.
      (*movv4hi_internal): Likewise.
      (*movv4qi_internal): Likewise.
      (*movv4sf_internal): Likewise.

Index: altivec.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/altivec.md,v
retrieving revision 1.7
diff -c -p -r1.7 altivec.md
*** altivec.md    13 Apr 2003 17:51:06 -0000    1.7
--- altivec.md    27 Jun 2003 16:10:21 -0000
***************
*** 101,115 ****
      case 0: return \"stvx %1,%y0\";
      case 1: return \"lvx %0,%y1\";
      case 2: return \"vor %0,%1,%1\";
!     case 3: return \"stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw %Z1,%Z0\";
!     case 4: return \"lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz %Z0,%Z1\";
!     case 5: return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
      case 6: return output_vec_const_move (operands);
      default: abort();
      }
  }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")
!    (set_attr "length" "*,*,*,16,16,16,*")])

  (define_split
    [(set (match_operand:V4SI 0 "altivec_register_operand" "")
--- 101,138 ----
      case 0: return \"stvx %1,%y0\";
      case 1: return \"lvx %0,%y1\";
      case 2: return \"vor %0,%1,%1\";
!     case 3: return \"#\";
!     case 4: return \"#\";
!     case 5: return \"#\";
      case 6: return output_vec_const_move (operands);
      default: abort();
      }
  }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")])
!
! (define_split
!   [(set (match_operand:V4SI 0 "nonimmediate_operand" "")
!         (match_operand:V4SI 1 "input_operand" ""))]
!   "TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
!    && altivec_in_gprs_p (operands[0], operands[1])"
!   [(set (match_dup 2) (match_dup 4))
!    (set (match_dup 3) (match_dup 5))]
! "{
!      rs6000_split_altivec_in_gprs (operands);
! }")
!
! (define_split
!   [(set (match_operand:V4SI 0 "nonimmediate_operand" "")
!         (match_operand:V4SI 1 "input_operand" ""))]
!   "TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
!    && altivec_in_gprs_p (operands[0], operands[1])"
!   [(set (match_dup 2) (match_dup 6))
!    (set (match_dup 3) (match_dup 7))
!    (set (match_dup 4) (match_dup 8))
!    (set (match_dup 5) (match_dup 9))]
! "{
!      rs6000_split_altivec_in_gprs (operands);
! }")

  (define_split
    [(set (match_operand:V4SI 0 "altivec_register_operand" "")
***************
*** 140,154 ****
       case 0: return \"stvx %1,%y0\";
       case 1: return \"lvx %0,%y1\";
       case 2: return \"vor %0,%1,%1\";
!      case 3: return \"stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw %Z1,%Z0\";
!      case 4: return \"lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz %Z0,%Z1\";
!      case 5: return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
       case 6: return output_vec_const_move (operands);
       default: abort ();
       }
  }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")
!    (set_attr "length" "*,*,*,16,16,16,*")])

  (define_split
    [(set (match_operand:V8HI 0 "altivec_register_operand" "")
--- 163,200 ----
       case 0: return \"stvx %1,%y0\";
       case 1: return \"lvx %0,%y1\";
       case 2: return \"vor %0,%1,%1\";
!      case 3: return \"#\";
!      case 4: return \"#\";
!      case 5: return \"#\";
       case 6: return output_vec_const_move (operands);
       default: abort ();
       }
  }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")])
!
! (define_split
!   [(set (match_operand:V8HI 0 "nonimmediate_operand" "")
!         (match_operand:V8HI 1 "input_operand" ""))]
!   "TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
!    && altivec_in_gprs_p (operands[0], operands[1])"
!   [(set (match_dup 2) (match_dup 4))
!    (set (match_dup 3) (match_dup 5))]
! "{
!      rs6000_split_altivec_in_gprs (operands);
! }")
!
! (define_split
!   [(set (match_operand:V8HI 0 "nonimmediate_operand" "")
!         (match_operand:V8HI 1 "input_operand" ""))]
!   "TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
!    && altivec_in_gprs_p (operands[0], operands[1])"
!   [(set (match_dup 2) (match_dup 6))
!    (set (match_dup 3) (match_dup 7))
!    (set (match_dup 4) (match_dup 8))
!    (set (match_dup 5) (match_dup 9))]
! "{
!      rs6000_split_altivec_in_gprs (operands);
! }")

  (define_split
    [(set (match_operand:V8HI 0 "altivec_register_operand" "")
***************
*** 179,193 ****
      case 0: return \"stvx %1,%y0\";
      case 1: return \"lvx %0,%y1\";
      case 2: return \"vor %0,%1,%1\";
!     case 3: return \"stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw %Z1,%Z0\";
!     case 4: return \"lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz %Z0,%Z1\";
!     case 5: return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
      case 6: return output_vec_const_move (operands);
      default: abort ();
      }
  }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")
!    (set_attr "length" "*,*,*,16,16,16,*")])

  (define_split
    [(set (match_operand:V16QI 0 "altivec_register_operand" "")
--- 225,262 ----
      case 0: return \"stvx %1,%y0\";
      case 1: return \"lvx %0,%y1\";
      case 2: return \"vor %0,%1,%1\";
!     case 3: return \"#\";
!     case 4: return \"#\";
!     case 5: return \"#\";
      case 6: return output_vec_const_move (operands);
      default: abort ();
      }
  }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")])
!
! (define_split
!   [(set (match_operand:V16QI 0 "nonimmediate_operand" "")
!         (match_operand:V16QI 1 "input_operand" ""))]
!   "TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
!    && altivec_in_gprs_p (operands[0], operands[1])"
!   [(set (match_dup 2) (match_dup 4))
!    (set (match_dup 3) (match_dup 5))]
! "{
!      rs6000_split_altivec_in_gprs (operands);
! }")
!
! (define_split
!   [(set (match_operand:V16QI 0 "nonimmediate_operand" "")
!         (match_operand:V16QI 1 "input_operand" ""))]
!   "TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
!    && altivec_in_gprs_p (operands[0], operands[1])"
!   [(set (match_dup 2) (match_dup 6))
!    (set (match_dup 3) (match_dup 7))
!    (set (match_dup 4) (match_dup 8))
!    (set (match_dup 5) (match_dup 9))]
! "{
!      rs6000_split_altivec_in_gprs (operands);
! }")

  (define_split
    [(set (match_operand:V16QI 0 "altivec_register_operand" "")
***************
*** 218,232 ****
      case 0: return \"stvx %1,%y0\";
      case 1: return \"lvx %0,%y1\";
      case 2: return \"vor %0,%1,%1\";
!     case 3: return \"stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw %Z1,%Z0\";
!     case 4: return \"lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz %Z0,%Z1\";
!     case 5: return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
      case 6: return output_vec_const_move (operands);
      default: abort ();
      }
  }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")
!    (set_attr "length" "*,*,*,16,16,16,*")])

  (define_insn "get_vrsave_internal"
    [(set (match_operand:SI 0 "register_operand" "=r")
--- 287,324 ----
      case 0: return \"stvx %1,%y0\";
      case 1: return \"lvx %0,%y1\";
      case 2: return \"vor %0,%1,%1\";
!     case 3: return \"#\";
!     case 4: return \"#\";
!     case 5: return \"#\";
      case 6: return output_vec_const_move (operands);
      default: abort ();
      }
  }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")])
!
! (define_split
!   [(set (match_operand:V4SF 0 "nonimmediate_operand" "")
!         (match_operand:V4SF 1 "input_operand" ""))]
!   "TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
!    && altivec_in_gprs_p (operands[0], operands[1])"
!   [(set (match_dup 2) (match_dup 4))
!    (set (match_dup 3) (match_dup 5))]
! "{
!      rs6000_split_altivec_in_gprs (operands);
! }")
!
! (define_split
!   [(set (match_operand:V4SF 0 "nonimmediate_operand" "")
!         (match_operand:V4SF 1 "input_operand" ""))]
!   "TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
!    && altivec_in_gprs_p (operands[0], operands[1])"
!   [(set (match_dup 2) (match_dup 6))
!    (set (match_dup 3) (match_dup 7))
!    (set (match_dup 4) (match_dup 8))
!    (set (match_dup 5) (match_dup 9))]
! "{
!      rs6000_split_altivec_in_gprs (operands);
! }")

  (define_insn "get_vrsave_internal"
    [(set (match_operand:SI 0 "register_operand" "=r")
Index: rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.58
diff -c -p -r1.58 rs6000-protos.h
*** rs6000-protos.h     19 Jun 2003 21:47:21 -0000    1.58
--- rs6000-protos.h     27 Jun 2003 16:10:21 -0000
*************** extern int includes_rldic_lshift_p PARAM
*** 101,106 ****
--- 101,107 ----
  extern int includes_rldicr_lshift_p PARAMS ((rtx, rtx));
  extern int registers_ok_for_quad_peep PARAMS ((rtx, rtx));
  extern int addrs_ok_for_quad_peep PARAMS ((rtx, rtx));
+ extern int altivec_in_gprs_p (rtx, rtx);
  extern enum reg_class secondary_reload_class PARAMS ((enum reg_class,
                                          enum machine_mode, rtx));
  extern int ccr_bit PARAMS ((rtx, int));
*************** extern int mtcrf_operation PARAMS ((rtx,
*** 125,130 ****
--- 126,132 ----
  extern int lmw_operation PARAMS ((rtx, enum machine_mode));
  extern struct rtx_def *create_TOC_reference PARAMS ((rtx));
  extern void rs6000_emit_eh_toc_restore PARAMS ((rtx));
+ extern void rs6000_split_altivec_in_gprs (rtx *);
  extern void rs6000_emit_move PARAMS ((rtx, rtx, enum machine_mode));
  extern rtx rs6000_legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
  extern rtx rs6000_legitimize_reload_address PARAMS ((rtx, enum machine_mode,
Index: rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.498
diff -c -p -r1.498 rs6000.c
*** rs6000.c      27 Jun 2003 09:49:41 -0000    1.498
--- rs6000.c      27 Jun 2003 16:10:26 -0000
*************** small_data_operand (op, mode)
*** 2305,2310 ****
--- 2305,2325 ----
    return 0;
  #endif
  }
+
+ /* Return 1 for all valid move insn operand combination involving altivec
+    vectors in gprs.  */
+
+ int
+ altivec_in_gprs_p (rtx op0, rtx op1)
+ {
+   if (REG_P (op0) && REGNO_REG_CLASS (REGNO (op0)) == GENERAL_REGS)
+     return 1;
+
+   if (REG_P (op1) && REGNO_REG_CLASS (REGNO (op1)) == GENERAL_REGS)
+     return 1;
+   return 0;
+ }
+

  /* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address.  */

*************** rs6000_emit_minmax (dest, code, op0, op1
*** 9637,9642 ****
--- 9652,9734 ----
    if (target != dest)
      emit_move_insn (dest, target);
  }
+
+ /* Called by altivec splitter.
+    Input:
+           operands[0] : Destination of move
+           operands[1] : Source of move
+       noperands   : Size of operands vector
+    Output:
+       operands[2-5] ([2-3] in 64 bit) : Destination slots
+       operands[6-9] ([4-5] in 64 bit) : Source slots
+
+    Splits the move of operands[1] to operands[0].
+    This is done, if GPRs are one of the operands.  In this case
+    a sequence of simple move insns has to be issued.  The sequence of these
+    move insns has to be done in correct order to avoid early clobber of the
+    base register or destructive overlap of registers.
+ */
+
+ void
+ rs6000_split_altivec_in_gprs (rtx *operands)
+ {
+     int nregs, reg, i, j;
+   enum machine_mode mode;
+
+   /* Calculate number to move (2/4 for 32/64 bit mode).  */
+
+   reg = REG_P (operands[0]) ? REGNO (operands[0]) : REGNO (operands[1]);
+   mode = GET_MODE (operands[0]);
+   nregs = HARD_REGNO_NREGS (reg, mode);
+
+   if (REG_P (operands[1])
+       && REG_P (operands[0])
+       && (REGNO (operands[1]) < REGNO (operands[0])))
+     {
+       /* Move register range backwards, if we have destructive overlap.  */
+
+       j = nregs;
+       for (i = 0; i < nregs; i++)
+         {
+           j--;
+           operands[i + 2] = operand_subword (operands[0], j, 0, mode);
+           operands[i + 2 + nregs] =
+             operand_subword (operands[1], j, 0, mode);
+         }
+     }
+   else
+     {
+       j = -1;
+
+       if (GET_CODE (operands[1]) == MEM)
+         {
+           rtx breg;
+           /* We have offsettable addresses only. If we use one of the
+              registers to address memory, we have change that register last.  */
+           breg = GET_CODE (XEXP (operands[1], 0)) == PLUS ?
+               XEXP (XEXP (operands[1], 0), 0) :
+               XEXP (operands[1], 0);
+
+           if (REGNO (breg) >= REGNO (operands[0])
+               && REGNO (breg) < REGNO (operands[0]) + nregs)
+               j = REGNO (breg) - REGNO (operands[0]);
+         }
+
+       for (i = 0; i < nregs; i++)
+         {
+           /* Calculate index to next subword.  */
+           j++;
+           if (j == nregs)
+             j = 0;
+
+           operands[i + 2] = operand_subword (operands[0], j, 0, mode);
+           operands[i + 2 + nregs] =
+             operand_subword (operands[1], j, 0, mode);
+
+         }
+     }
+ }
+

  /* This page contains routines that are used to determine what the
     function prologue and epilogue code will do and write them out.  */




More information about the Gcc-patches mailing list