Add -mstring support.
authorMichael Meissner <meissner@gcc.gnu.org>
Tue, 16 May 1995 23:07:37 +0000 (23:07 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Tue, 16 May 1995 23:07:37 +0000 (23:07 +0000)
From-SVN: r9734

gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md
gcc/config/rs6000/sysv4.h
gcc/config/rs6000/sysv4le.h

index bbefc03..c24631e 100644 (file)
@@ -184,6 +184,24 @@ rs6000_override_options ()
      override with the processor default */
   if (TARGET_MULTIPLE_SET)
     target_flags = (target_flags & ~MASK_MULTIPLE) | multiple;
+
+  /* Don't allow -mmultiple or -mstring on little endian systems, because the
+     hardware doesn't support the instructions used in little endian mode */
+  if (!BYTES_BIG_ENDIAN)
+    {
+      if (TARGET_MULTIPLE)
+       {
+         target_flags &= ~MASK_MULTIPLE;
+         if (TARGET_MULTIPLE_SET)
+           warning ("-mmultiple is not supported on little endian systems");
+       }
+
+      if (TARGET_STRING)
+       {
+         target_flags &= ~MASK_STRING;
+         warning ("-mstring is not supported on little endian systems");
+       }
+    }
 }
 \f
 /* Create a CONST_DOUBLE like immed_double_const, except reverse the
@@ -615,6 +633,142 @@ input_operand (op, mode)
   return add_operand (op, mode);
 }
 \f
+/* Expand a block move operation, and return 1 if successful.  Return 0
+   if we should let the compiler generate normal code.
+
+   operands[0] is the destination
+   operands[1] is the source
+   operands[2] is the length
+   operands[3] is the alignment */
+
+int
+expand_block_move (operands)
+     rtx operands[];
+{
+  rtx bytes_rtx        = operands[2];
+  int constp   = (GET_CODE (bytes_rtx) == CONST_INT);
+  int bytes    = (constp ? INTVAL (bytes_rtx) : 0);
+  rtx align_rtx = operands[3];
+  int align    = XINT (align_rtx, 0);
+  rtx src_reg;
+  rtx dest_reg;
+  rtx tmp_reg;
+  int move_bytes;
+
+  /* Anything to move? */
+  if (constp && bytes <= 0)
+    return 1;
+
+  /* If we don't want to use multiple string instructions, quit now and
+     generate the normal code.  */
+  if (!TARGET_STRING)
+    return 0;
+
+  /* We don't support variable sized moves at this time or real large moves */
+  if (!constp || bytes > 64)
+    return 0;
+
+  /* Move the address into scratch registers.  */
+  dest_reg = copy_addr_to_reg (XEXP (operands[0], 0));
+  src_reg  = copy_addr_to_reg (XEXP (operands[1], 0));
+
+  for ( ; bytes > 0; bytes -= move_bytes)
+    {
+      if (bytes > 24           /* move up to 32 bytes at a time */
+         && !fixed_regs[5]
+         && !fixed_regs[6]
+         && !fixed_regs[7]
+         && !fixed_regs[8]
+         && !fixed_regs[9]
+         && !fixed_regs[10]
+         && !fixed_regs[11]
+         && !fixed_regs[12])
+       {
+         move_bytes = (bytes > 32) ? 32 : bytes;
+         emit_insn (gen_movstrsi_8reg (dest_reg,
+                                       src_reg,
+                                       GEN_INT ((move_bytes == 32) ? 0 : move_bytes),
+                                       align_rtx,
+                                       GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
+       }
+      else if (bytes > 16      /* move up to 24 bytes at a time */
+         && !fixed_regs[7]
+         && !fixed_regs[8]
+         && !fixed_regs[9]
+         && !fixed_regs[10]
+         && !fixed_regs[11]
+         && !fixed_regs[12])
+       {
+         move_bytes = (bytes > 24) ? 24 : bytes;
+         emit_insn (gen_movstrsi_6reg (dest_reg,
+                                       src_reg,
+                                       GEN_INT (move_bytes),
+                                       align_rtx,
+                                       GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
+       }
+      else if (bytes > 8       /* move up to 16 bytes at a time */
+              && !fixed_regs[9]
+              && !fixed_regs[10]
+              && !fixed_regs[11]
+              && !fixed_regs[12])
+       {
+         move_bytes = (bytes > 16) ? 16 : bytes;
+         emit_insn (gen_movstrsi_4reg (dest_reg,
+                                       src_reg,
+                                       GEN_INT (move_bytes),
+                                       align_rtx,
+                                       GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
+       }
+      else if (bytes > 4 && !TARGET_64BIT)
+       {                       /* move up to 8 bytes at a time */
+         move_bytes = (bytes > 8) ? 8 : bytes;
+         emit_insn (gen_movstrsi_2reg (dest_reg,
+                                       src_reg,
+                                       GEN_INT (move_bytes),
+                                       align_rtx,
+                                       GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
+       }
+      else if (bytes >= 4 && (align >= 4 || !STRICT_ALIGNMENT))
+       {                       /* move 4 bytes */
+         move_bytes = 4;
+         tmp_reg = gen_reg_rtx (SImode);
+         emit_move_insn (tmp_reg, gen_rtx (MEM, SImode, src_reg));
+         emit_move_insn (gen_rtx (MEM, SImode, dest_reg), tmp_reg);
+         if (bytes > move_bytes)
+           {
+             emit_insn (gen_addsi3 (src_reg, src_reg, GEN_INT (move_bytes)));
+             emit_insn (gen_addsi3 (dest_reg, dest_reg, GEN_INT (move_bytes)));
+           }
+       }
+      else if (bytes == 2 && (align >= 2 || !STRICT_ALIGNMENT))
+       {                       /* move 2 bytes */
+         move_bytes = 2;
+         tmp_reg = gen_reg_rtx (HImode);
+         emit_move_insn (tmp_reg, gen_rtx (MEM, HImode, src_reg));
+         emit_move_insn (gen_rtx (MEM, HImode, dest_reg), tmp_reg);
+       }
+      else if (bytes == 1)     /* move 1 byte */
+       {
+         move_bytes = 1;
+         tmp_reg = gen_reg_rtx (QImode);
+         emit_move_insn (tmp_reg, gen_rtx (MEM, QImode, src_reg));
+         emit_move_insn (gen_rtx (MEM, QImode, dest_reg), tmp_reg);
+       }
+      else
+       {                       /* move up to 4 bytes at a time */
+         move_bytes = (bytes > 4) ? 4 : bytes;
+         emit_insn (gen_movstrsi_1reg (dest_reg,
+                                       src_reg,
+                                       GEN_INT (move_bytes),
+                                       align_rtx,
+                                       GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
+       }
+    }
+
+  return 1;
+}
+
+\f
 /* Return 1 if OP is a load multiple operation.  It is known to be a
    PARALLEL and the first section will be tested.  */
 
index 96b7951..4c5103a 100644 (file)
@@ -153,22 +153,26 @@ extern int target_flags;
 #define        MASK_MULTIPLE           0x1000
 #define        MASK_MULTIPLE_SET       0x2000
 
-#define TARGET_POWER                   (target_flags & MASK_POWER)
-#define TARGET_POWER2                  (target_flags & MASK_POWER2)
-#define TARGET_POWERPC                 (target_flags & MASK_POWERPC)
-#define TARGET_PPC_GPOPT               (target_flags & MASK_PPC_GPOPT)
-#define TARGET_PPC_GFXOPT              (target_flags & MASK_PPC_GFXOPT)
-#define TARGET_POWERPC64               (target_flags & MASK_POWERPC64)
-#define TARGET_NEW_MNEMONICS           (target_flags & MASK_NEW_MNEMONICS)
-#define TARGET_NO_FP_IN_TOC            (target_flags & MASK_NO_FP_IN_TOC)
-#define TARGET_NO_SUM_IN_TOC           (target_flags & MASK_NO_SUM_IN_TOC)
-#define TARGET_MINIMAL_TOC             (target_flags & MASK_MINIMAL_TOC)
-#define TARGET_64BIT                   (target_flags & MASK_64BIT)
-#define TARGET_SOFT_FLOAT              (target_flags & MASK_SOFT_FLOAT)
-#define        TARGET_MULTIPLE                 (target_flags & MASK_MULTIPLE)
-#define        TARGET_MULTIPLE_SET             (target_flags & MASK_MULTIPLE_SET)
-
-#define TARGET_HARD_FLOAT              (! TARGET_SOFT_FLOAT)
+/* Use string instructions for block moves */
+#define MASK_STRING            0x4000
+
+#define TARGET_POWER           (target_flags & MASK_POWER)
+#define TARGET_POWER2          (target_flags & MASK_POWER2)
+#define TARGET_POWERPC         (target_flags & MASK_POWERPC)
+#define TARGET_PPC_GPOPT       (target_flags & MASK_PPC_GPOPT)
+#define TARGET_PPC_GFXOPT      (target_flags & MASK_PPC_GFXOPT)
+#define TARGET_POWERPC64       (target_flags & MASK_POWERPC64)
+#define TARGET_NEW_MNEMONICS   (target_flags & MASK_NEW_MNEMONICS)
+#define TARGET_NO_FP_IN_TOC    (target_flags & MASK_NO_FP_IN_TOC)
+#define TARGET_NO_SUM_IN_TOC   (target_flags & MASK_NO_SUM_IN_TOC)
+#define TARGET_MINIMAL_TOC     (target_flags & MASK_MINIMAL_TOC)
+#define TARGET_64BIT           (target_flags & MASK_64BIT)
+#define TARGET_SOFT_FLOAT      (target_flags & MASK_SOFT_FLOAT)
+#define        TARGET_MULTIPLE         (target_flags & MASK_MULTIPLE)
+#define        TARGET_MULTIPLE_SET     (target_flags & MASK_MULTIPLE_SET)
+#define TARGET_STRING          (target_flags & MASK_STRING)
+
+#define TARGET_HARD_FLOAT      (! TARGET_SOFT_FLOAT)
 
 /* Run-time compilation parameters selecting different hardware subsets.
 
@@ -211,6 +215,8 @@ extern int target_flags;
   {"multiple",         MASK_MULTIPLE | MASK_MULTIPLE_SET},     \
   {"no-multiple",      - MASK_MULTIPLE},                       \
   {"no-multiple",      MASK_MULTIPLE_SET},                     \
+  {"string",           MASK_STRING},                           \
+  {"no-string",                - MASK_STRING},                         \
   SUBTARGET_SWITCHES                                           \
   {"",                 TARGET_DEFAULT}}
 
@@ -1493,8 +1499,8 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
 
 /* Max number of bytes we can move from memory to memory
    in one reasonably fast instruction.  */
-#define MOVE_MAX (TARGET_MULTIPLE ? 16 : (TARGET_POWERPC64 ? 8 : 4))
-#define MAX_MOVE_MAX 16
+#define MOVE_MAX (TARGET_POWERPC64 ? 8 : 4)
+#define MAX_MOVE_MAX 8
 
 /* Nonzero if access to memory by bytes is no faster than for words.
    Also non-zero if doing byte operations (specifically shifts) in registers
@@ -2377,6 +2383,7 @@ extern int lwa_operand ();
 extern int call_operand ();
 extern int current_file_function_operand ();
 extern int input_operand ();
+extern int expand_block_move ();
 extern int load_multiple_operation ();
 extern int store_multiple_operation ();
 extern int branch_comparison_operator ();
index 7e701db..f44883f 100644 (file)
    {cax.|add.} %3,%1,%2
    {ai.|addic.} %3,%1,%2"
   [(set_attr "type" "compare")])
-   
+
 (define_insn ""
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,x")
        (compare:CC (plus:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r")
    {cax.|add.} %0,%1,%2
    {ai.|addic.} %0,%1,%2"
   [(set_attr "type" "compare")])
-   
+
 ;; Split an add that we can't do in one insn into two insns, each of which
 ;; does one 16-bit part.  This is used by combine.  Note that the low-order
 ;; add should be last in case the result gets used in an address.
       else
        return \"{andil.|andi.} %4,%1,%3\";
     }
-  
+
   if (start + size >= 32)
     operands[3] = const0_rtx;
   else
       operands[3] = gen_rtx (CONST_INT, VOIDmode, (1 << (32 - start)) - 1);
       return \"{andil.|andi.} %0,%1,%3\";
     }
-  
+
   if (start + size >= 32)
     operands[3] = const0_rtx;
   else
   ""
   "#"
   [(set_attr "length" "8")])
-  
+
 (define_split
   [(set (match_operand:DI 0 "gpc_reg_operand" "=")
        (plus:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
        (reg:SI 3))]
   "TARGET_HARD_FLOAT"
   "
-{ 
+{
   rs6000_trunc_used = 1;
 }")
 
   "
 { operands[2] = operand_subword (operands[0], 0, 0, SFmode);
   operands[3] = operand_subword (operands[1], 0, 0, SFmode); }")
-  
+
 (define_insn ""
   [(set (match_operand:SF 0 "fp_reg_or_mem_operand" "=f,f,m")
        (match_operand:SF 1 "input_operand" "f,m,f"))]
   [(parallel [(set (match_operand:TI 0 "general_operand" "")
                   (match_operand:TI 1 "general_operand" ""))
              (clobber (scratch:SI))])]
-  "TARGET_MULTIPLE || TARGET_POWERPC64"
+  "TARGET_STRING || TARGET_POWERPC64"
   "
 {
   if (GET_CODE (operands[0]) == MEM)
   [(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
        (match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))
    (clobber (match_scratch:SI 2 "=q,q#X,X,X,X"))]
-  "TARGET_MULTIPLE && TARGET_POWER && ! TARGET_POWERPC64
+  "TARGET_STRING && TARGET_POWER && ! TARGET_POWERPC64
    && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
   "*
 {
   [(set (match_operand:TI 0 "reg_or_mem_operand" "=m,????r,????r")
        (match_operand:TI 1 "reg_or_mem_operand" "r,r,m"))
    (clobber (match_scratch:SI 2 "=X,X,X"))]
-  "TARGET_MULTIPLE && !TARGET_POWER && ! TARGET_POWERPC64
+  "TARGET_STRING && !TARGET_POWER && ! TARGET_POWERPC64
    && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
   "*
 {
   [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
                          (match_operand:SI 1 "" ""))
                     (use (match_operand:SI 2 "" ""))])]
-  "TARGET_MULTIPLE"
+  "TARGET_STRING"
   "
 {
   int regno;
   [(match_parallel 0 "load_multiple_operation"
                   [(set (match_operand:SI 1 "gpc_reg_operand" "=r")
                         (match_operand:SI 2 "indirect_operand" "Q"))])]
-  "TARGET_MULTIPLE"
+  "TARGET_STRING"
   "*
 {
   /* We have to handle the case where the pseudo used to contain the address
                          (match_operand:SI 1 "" ""))
                     (clobber (scratch:SI))
                     (use (match_operand:SI 2 "" ""))])]
-  "TARGET_MULTIPLE"
+  "TARGET_STRING"
   "
 {
   int regno;
                   [(set (match_operand:SI 1 "indirect_operand" "=Q")
                         (match_operand:SI 2 "gpc_reg_operand" "r"))
                    (clobber (match_scratch:SI 3 "=q"))])]
-  "TARGET_MULTIPLE && TARGET_POWER"
+  "TARGET_STRING && TARGET_POWER"
   "{stsi|stswi} %2,%P1,%O0")
 
 (define_insn ""
                   [(set (match_operand:SI 1 "indirect_operand" "=Q")
                         (match_operand:SI 2 "gpc_reg_operand" "r"))
                    (clobber (match_scratch:SI 3 "X"))])]
-  "TARGET_MULTIPLE && !TARGET_POWER"
+  "TARGET_STRING && !TARGET_POWER"
   "{stsi|stswi} %2,%P1,%O0")
+
+\f
+;; String/block move insn.
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+
+(define_expand "movstrsi"
+  [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+                  (match_operand:BLK 1 "memory_operand" ""))
+             (use (match_operand:SI 2 "general_operand" ""))
+             (use (match_operand:SI 3 "immediate_operand" ""))])]
+  ""
+  "
+{
+  if (expand_block_move (operands))
+    DONE;
+  else
+    FAIL;
+}")
+
+;; Move up to 32 bytes at a time.  The fixed registers are needed because the
+;; register allocator doesn't have a clue about allocating 8 word registers
+(define_expand "movstrsi_8reg"
+  [(parallel [(set (mem:BLK (match_operand:SI 0 "register_operand" ""))
+                  (mem:BLK (match_operand:SI 1 "register_operand" "")))
+             (set (match_dup 0)
+                  (plus:SI (match_dup 0)
+                           (match_operand:SI 4 "immediate_operand" "")))
+             (set (match_dup 1)
+                  (plus:SI (match_dup 1)
+                           (match_dup 4)))
+             (use (match_operand:SI 2 "immediate_operand" ""))
+             (use (match_operand:SI 3 "immediate_operand" ""))
+             (clobber (reg:SI  5))
+             (clobber (reg:SI  6))
+             (clobber (reg:SI  7))
+             (clobber (reg:SI  8))
+             (clobber (reg:SI  9))
+             (clobber (reg:SI 10))
+             (clobber (reg:SI 11))
+             (clobber (reg:SI 12))
+             (clobber (match_scratch:SI 5 ""))])]
+  "TARGET_STRING"
+  "")
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_operand:SI 5 "register_operand" "r,r"))
+   (clobber (reg:SI  6))
+   (clobber (reg:SI  7))
+   (clobber (reg:SI  8))
+   (clobber (reg:SI  9))
+   (clobber (reg:SI 10))
+   (clobber (reg:SI 11))
+   (clobber (reg:SI 12))
+   (clobber (match_scratch:SI 6 "=q,q"))]
+  "TARGET_STRING && TARGET_POWER
+   && ((INTVAL (operands[2]) > 24 && INTVAL (operands[2]) < 32) || INTVAL (operands[2]) == 0)
+   && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 12)
+   && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 12)
+   && REGNO (operands[5]) == 5"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_operand:SI 5 "register_operand" "r,r"))
+   (clobber (reg:SI  6))
+   (clobber (reg:SI  7))
+   (clobber (reg:SI  8))
+   (clobber (reg:SI  9))
+   (clobber (reg:SI 10))
+   (clobber (reg:SI 11))
+   (clobber (reg:SI 12))
+   (clobber (match_scratch:SI 6 "X,X"))]
+  "TARGET_STRING && !TARGET_POWER
+   && ((INTVAL (operands[2]) > 24 && INTVAL (operands[2]) < 32) || INTVAL (operands[2]) == 0)
+   && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 12)
+   && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 12)
+   && REGNO (operands[5]) == 5"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+;; Move up to 24 bytes at a time.  The fixed registers are needed because the
+;; register allocator doesn't have a clue about allocating 6 word registers
+(define_expand "movstrsi_6reg"
+  [(parallel [(set (mem:BLK (match_operand:SI 0 "register_operand" ""))
+                  (mem:BLK (match_operand:SI 1 "register_operand" "")))
+             (set (match_dup 0)
+                  (plus:SI (match_dup 0)
+                           (match_operand:SI 4 "immediate_operand" "")))
+             (set (match_dup 1)
+                  (plus:SI (match_dup 1)
+                           (match_dup 4)))
+             (use (match_operand:SI 2 "immediate_operand" ""))
+             (use (match_operand:SI 3 "immediate_operand" ""))
+             (clobber (reg:SI  7))
+             (clobber (reg:SI  8))
+             (clobber (reg:SI  9))
+             (clobber (reg:SI 10))
+             (clobber (reg:SI 11))
+             (clobber (reg:SI 12))
+             (clobber (match_scratch:SI 5 ""))])]
+  "TARGET_STRING"
+  "")
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_operand:SI 5 "register_operand" "r,r"))
+   (clobber (reg:SI  8))
+   (clobber (reg:SI  9))
+   (clobber (reg:SI 10))
+   (clobber (reg:SI 11))
+   (clobber (reg:SI 12))
+   (clobber (match_scratch:SI 6 "=q,q"))]
+  "TARGET_STRING && TARGET_POWER
+   && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24
+   && (REGNO (operands[0]) < 7 || REGNO (operands[0]) > 12)
+   && (REGNO (operands[1]) < 7 || REGNO (operands[1]) > 12)
+   && REGNO (operands[5]) == 7"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_operand:SI 5 "register_operand" "r,r"))
+   (clobber (reg:SI  8))
+   (clobber (reg:SI  9))
+   (clobber (reg:SI 10))
+   (clobber (reg:SI 11))
+   (clobber (reg:SI 12))
+   (clobber (match_scratch:SI 6 "X,X"))]
+  "TARGET_STRING && !TARGET_POWER
+   && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 32
+   && (REGNO (operands[0]) < 7 || REGNO (operands[0]) > 12)
+   && (REGNO (operands[1]) < 7 || REGNO (operands[1]) > 12)
+   && REGNO (operands[5]) == 7"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+;; Move up to 16 bytes at a time, using 4 fixed registers to avoid spill problems
+;; with TImode
+(define_expand "movstrsi_4reg"
+  [(parallel [(set (mem:BLK (match_operand:SI 0 "register_operand" ""))
+                  (mem:BLK (match_operand:SI 1 "register_operand" "")))
+             (set (match_dup 0)
+                  (plus:SI (match_dup 0)
+                           (match_operand:SI 4 "immediate_operand" "")))
+             (set (match_dup 1)
+                  (plus:SI (match_dup 1)
+                           (match_dup 4)))
+             (use (match_operand:SI 2 "immediate_operand" ""))
+             (use (match_operand:SI 3 "immediate_operand" ""))
+             (clobber (reg:SI  9))
+             (clobber (reg:SI 10))
+             (clobber (reg:SI 11))
+             (clobber (reg:SI 12))
+             (clobber (match_scratch:SI 5 ""))])]
+  "TARGET_STRING"
+  "")
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_operand:SI 5 "register_operand" "r,r"))
+   (clobber (reg:SI 10))
+   (clobber (reg:SI 11))
+   (clobber (reg:SI 12))
+   (clobber (match_scratch:SI 6 "=q,q"))]
+  "TARGET_STRING && TARGET_POWER
+   && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16
+   && (REGNO (operands[0]) < 9 || REGNO (operands[0]) > 12)
+   && (REGNO (operands[1]) < 9 || REGNO (operands[1]) > 12)
+   && REGNO (operands[5]) == 9"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_operand:SI 5 "register_operand" "r,r"))
+   (clobber (reg:SI 10))
+   (clobber (reg:SI 11))
+   (clobber (reg:SI 12))
+   (clobber (match_scratch:SI 6 "X,X"))]
+  "TARGET_STRING && !TARGET_POWER
+   && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16
+   && (REGNO (operands[0]) < 9 || REGNO (operands[0]) > 12)
+   && (REGNO (operands[1]) < 9 || REGNO (operands[1]) > 12)
+   && REGNO (operands[5]) == 9"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+;; Move up to 8 bytes at a time.
+(define_expand "movstrsi_2reg"
+  [(parallel [(set (mem:BLK (match_operand:SI 0 "register_operand" ""))
+                  (mem:BLK (match_operand:SI 1 "register_operand" "")))
+             (set (match_dup 0)
+                  (plus:SI (match_dup 0)
+                           (match_operand:SI 4 "immediate_operand" "")))
+             (set (match_dup 1)
+                  (plus:SI (match_dup 1)
+                           (match_dup 4)))
+             (use (match_operand:SI 2 "immediate_operand" ""))
+             (use (match_operand:SI 3 "immediate_operand" ""))
+             (clobber (match_scratch:DI 5 ""))
+             (clobber (match_scratch:SI 6 ""))])]
+  "TARGET_STRING && !TARGET_64BIT"
+  "")
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_scratch:DI 5 "=&r,&r"))
+   (clobber (match_scratch:SI 6 "=q,q"))]
+  "TARGET_STRING && TARGET_POWER && !TARGET_64BIT
+    && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_scratch:DI 5 "=&r,&r"))
+   (clobber (match_scratch:SI 6 "X,X"))]
+  "TARGET_STRING && !TARGET_POWER && !TARGET_64BIT
+   && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+;; Move up to 4 bytes at a time.
+(define_expand "movstrsi_1reg"
+  [(parallel [(set (mem:BLK (match_operand:SI 0 "register_operand" ""))
+                  (mem:BLK (match_operand:SI 1 "register_operand" "")))
+             (set (match_dup 0)
+                  (plus:SI (match_dup 0)
+                           (match_operand:SI 4 "immediate_operand" "")))
+             (set (match_dup 1)
+                  (plus:SI (match_dup 1)
+                           (match_dup 4)))
+             (use (match_operand:SI 2 "immediate_operand" ""))
+             (use (match_operand:SI 3 "immediate_operand" ""))
+             (clobber (match_scratch:SI 5 ""))
+             (clobber (match_scratch:SI 6 ""))])]
+  "TARGET_STRING"
+  "")
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_scratch:SI 5 "=&r,&r"))
+   (clobber (match_scratch:SI 6 "=q,q"))]
+  "TARGET_STRING && TARGET_POWER
+   && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
+(define_insn ""
+  [(set (mem:BLK (match_operand:SI 0 "register_operand" "+&b,&b"))
+       (mem:BLK (match_operand:SI 1 "register_operand" "+&b,&b")))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0)
+                (match_operand:SI 4 "immediate_operand" "O,i")))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1)
+                (match_dup 4)))
+   (use (match_operand:SI 2 "immediate_operand" "i,i"))
+   (use (match_operand:SI 3 "immediate_operand" "i,i"))
+   (clobber (match_scratch:SI 5 "=&r,&r"))
+   (clobber (match_scratch:SI 6 "X,X"))]
+  "TARGET_STRING && !TARGET_POWER
+   && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4"
+  "@
+   {lsi|lswi} %5,%1,%2\;{stsi|stswi} %5,%0,%2
+   {lsi|lswi} %5,%1,%2\;{cal %0,%4(%0)|addi %0,%0,%4}\;{stsi|stswi} %5,%0,%2\;{cal %1,%4(%1)|addi %1,%1,%4}"
+  [(set_attr "length" "8,16")])
+
 \f
-;; Define insns that do load or store with update.  Some of these we can 
+;; Define insns that do load or store with update.  Some of these we can
 ;; get by using pre-decrement or pre-increment, but the hardware can also
 ;; do cases where the increment is not the size of the object.
 ;;
 ;; Next come insns related to the calling sequence.
 ;;
 ;; First, an insn to allocate new stack space for dynamic use (e.g., alloca).
-;; We move the back-chain and decrement the stack pointer.  
+;; We move the back-chain and decrement the stack pointer.
 
 (define_expand "allocate_stack"
   [(set (reg:SI 1)
   emit_move_insn (operand_subword (operands[0], 1, 0, DImode), operands[1]);
   DONE;
 }")
-                 
+
 (define_expand "restore_stack_nonlocal"
   [(match_operand:SI 0 "register_operand" "")
    (match_operand:DI 1 "memory_operand" "")]
 ;; A function pointer is a pointer to a data area whose first word contains
 ;; the actual address of the function, whose second word contains a pointer
 ;; to its TOC, and whose third word contains a value to place in the static
-;; chain register (r11).  Note that if we load the static chain, our 
+;; chain register (r11).  Note that if we load the static chain, our
 ;; "trampoline" need not have any executable code.
 ;;
 ;; operands[0] is an SImode pseudo in which we place the address of the
   "")
 \f
 ;; Compare insns are next.  Note that the RS/6000 has two types of compares,
-;; signed & unsigned, and one type of branch.  
+;; signed & unsigned, and one type of branch.
 ;;
 ;; Start with the DEFINE_EXPANDs to generate the rtl for compares, scc
 ;; insns, and branches.  We store the operands of compares until we see
   ""
   "#"
   [(set_attr "length" "8")])
-   
+
 (define_insn ""
   [(set (match_operand:CCUNS 3 "cc_reg_operand" "=y")
        (compare:CCUNS (match_operand:SI 1 "gpc_reg_operand" "r")
   ""
   "#"
   [(set_attr "length" "8")])
-   
+
 (define_split
   [(set (match_operand:CC 3 "cc_reg_operand" "")
        (compare:CC (match_operand:SI 1 "gpc_reg_operand" "")
 
 (define_insn ""
   [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,x,x,x")
-       (compare:CC 
+       (compare:CC
         (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r")
                (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I"))
         (const_int 0)))
 
 (define_insn ""
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,x")
-       (compare:CC 
+       (compare:CC
         (plus:SI
          (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r")
                 (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I"))
 
 (define_insn ""
   [(set (match_operand:CC 5 "cc_reg_operand" "=x,x,x,x,x")
-       (compare:CC 
+       (compare:CC
         (plus:SI
          (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r")
                 (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I"))
   ""
   "{cror 0,0,0|nop}")
 \f
-;; Define the subtract-one-and-jump insns, starting with the template 
+;; Define the subtract-one-and-jump insns, starting with the template
 ;; so loop.c knows what to generate.
 
 (define_expand "decrement_and_branchsi"
 
 ;; We need to be able to do this for any operand, including MEM, or we
 ;; will cause reload to blow up since we don't allow output reloads on
-;; JUMP_INSNs. 
+;; JUMP_INSNs.
 (define_insn ""
   [(set (pc)
        (if_then_else (ne (match_operand:SI 1 "register_operand" "0,*r,*r")
 }"
   [(set_attr "type" "branch")
    (set_attr "length" "*,12,16")])
-                              
+
 ;; Similar, but we can use GE since we have a REG_NONNEG.
 (define_insn ""
   [(set (pc)
 }"
   [(set_attr "type" "branch")
    (set_attr "length" "*,12,16")])
-                              
+
 (define_insn ""
   [(set (pc)
        (if_then_else (eq (match_operand:SI 1 "register_operand" "0,*r,*r")
index b309fa3..4ad6016 100644 (file)
@@ -28,12 +28,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define MASK_LITTLE_ENDIAN     0x04000000      /* target is little endian */
 
 #define        TARGET_NO_BITFIELD_TYPE (target_flags & MASK_NO_BITFIELD_TYPE)
-#define        TARGET_BITFIELD_TYPE    (! TARGET_NO_BITFIELD_TYPE)
 #define TARGET_STRICT_ALIGN    (target_flags & MASK_STRICT_ALIGN)
 #define TARGET_RELOCATABLE     (target_flags & MASK_RELOCATABLE)
 #define TARGET_NO_TRACEBACK    (target_flags & MASK_NO_TRACEBACK)
-#define        TARGET_TRACEBACK        (! TARGET_NO_TRACEBACK)
 #define TARGET_LITTLE_ENDIAN   (target_flags & MASK_LITTLE_ENDIAN)
+
+#define        TARGET_BITFIELD_TYPE    (! TARGET_NO_BITFIELD_TYPE)
+#define        TARGET_TRACEBACK        (! TARGET_NO_TRACEBACK)
 #define TARGET_BIG_ENDIAN      (! TARGET_LITTLE_ENDIAN)
 
 #undef SUBTARGET_SWITCHES
@@ -51,17 +52,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
   { "big-endian",      -MASK_LITTLE_ENDIAN },                          \
   { "big",             -MASK_LITTLE_ENDIAN },
 
-/* If the user wants little endian support, don't allow -mmultiple */
-#define SUBTARGET_OVERRIDE_OPTIONS                                     \
-{                                                                      \
-  if (TARGET_LITTLE_ENDIAN && TARGET_MULTIPLE)                         \
-    {                                                                  \
-      target_flags &= ~MASK_MULTIPLE;                                  \
-      if (TARGET_MULTIPLE_SET)                                         \
-       warning ("-mmultiple is not supported on little endian PowerPC systems"); \
-    }                                                                  \
-}
-
 #include "rs6000/powerpc.h"
 
 /* Override default big endianism */
@@ -321,6 +311,9 @@ extern int rs6000_pic_labelno;
 #define CPP_SPEC "\
 %{posix: -D_POSIX_SOURCE} \
 %{mrelocatable: -D_RELOCATABLE} \
+%{mlittle: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
+%{mlittle-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
+%{!mlittle: %{!mlittle-endian: -D_BIG_ENDIAN -Amachine(bigendian)}} \
 %{!mcpu*: \
   %{mpower: %{!mpower2: -D_ARCH_PWR}} \
   %{mpower2: -D_ARCH_PWR2} \
index b61ac19..3ce7796 100644 (file)
@@ -23,3 +23,37 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #undef TARGET_DEFAULT
 #define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_LITTLE_ENDIAN)
+
+#undef CPP_SPEC
+#define CPP_SPEC "\
+%{posix: -D_POSIX_SOURCE} \
+%{mrelocatable: -D_RELOCATABLE} \
+%{mbig: -D_BIG_ENDIAN -Amachine(bigendian)} \
+%{mbig-endian: -D_BIG_ENDIAN -Amachine(bigendian)} \
+%{!mbig: %{!mbig-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)}} \
+%{!mcpu*: \
+  %{mpower: %{!mpower2: -D_ARCH_PWR}} \
+  %{mpower2: -D_ARCH_PWR2} \
+  %{mpowerpc*: -D_ARCH_PPC} \
+  %{mno-powerpc: %{!mpower: %{!mpower2: -D_ARCH_COM}}} \
+  %{!mno-powerpc: -D_ARCH_PPC}} \
+%{mcpu=common: -D_ARCH_COM} \
+%{mcpu=power: -D_ARCH_PWR} \
+%{mcpu=powerpc: -D_ARCH_PPC} \
+%{mcpu=rios: -D_ARCH_PWR} \
+%{mcpu=rios1: -D_ARCH_PWR} \
+%{mcpu=rios2: -D_ARCH_PWR2} \
+%{mcpu=rsc: -D_ARCH_PWR} \
+%{mcpu=rsc1: -D_ARCH_PWR} \
+%{mcpu=403: -D_ARCH_PPC} \
+%{mcpu=mpc403: -D_ARCH_PPC} \
+%{mcpu=ppc403: -D_ARCH_PPC} \
+%{mcpu=601: -D_ARCH_PPC -D_ARCH_PWR} \
+%{mcpu=mpc601: -D_ARCH_PPC -D_ARCH_PWR} \
+%{mcpu=ppc601: -D_ARCH_PPC -D_ARCH_PWR} \
+%{mcpu=603: -D_ARCH_PPC} \
+%{mcpu=mpc603: -D_ARCH_PPC} \
+%{mcpu=ppc603: -D_ARCH_PPC} \
+%{mcpu=604: -D_ARCH_PPC} \
+%{mcpu=mpc604: -D_ARCH_PPC} \
+%{mcpu=ppc604: -D_ARCH_PPC}"