c-decl.c (init_decl_processing): Provide proper fallback symbol for __builtin_memset.
authorRichard Henderson <rth@cygnus.com>
Fri, 2 Jan 1998 04:48:04 +0000 (20:48 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 2 Jan 1998 04:48:04 +0000 (20:48 -0800)
* c-decl.c (init_decl_processing): Provide proper fallback symbol
for __builtin_memset.
* expr.c (expand_builtin) [MEMSET]: Arg 3 type code is INTEGER_TYPE
not INTEGER_CST.  Assert arg 3 is a constant.
* alpha.c (mode_width_operand): Accept 64-bit modes.
(mode_mask_operand): Likewise.
(print_operand): Likewise for 'M' and 'U' codes.
(alpha_expand_unaligned_load): New function.
(alpha_expand_unaligned_store): Likewise.
(alpha_expand_unaligned_load_words): Likewise.
(alpha_expand_unaligned_store_words): Likewise.
(alpha_expand_block_move): Likewise.
(alpha_expand_block_clear): Likewise.
* alpha.h (MOVE_RATIO): New define.
* alpha.md (extxl, ext*h, ins*l, mskxl): Name them.
(insql, insxh, mskxh, extv, extzv, insv, movstrqi, clrstrqi): New.
* alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Set to 3.
(CONSTANT_ALIGNMENT, DATA_ALIGNMENT): Disable.

From-SVN: r17278

gcc/ChangeLog
gcc/c-decl.c
gcc/config/alpha/alpha.c
gcc/config/alpha/alpha.h
gcc/config/alpha/alpha.md
gcc/expr.c

index d8d1901c626981980b3bf8e28cf29e29cd40a58e..8e52ace9210da8b4696b9aab0272df9f5d821e9b 100644 (file)
@@ -1,3 +1,26 @@
+Fri Jan  2 04:34:14 1998  Richard Henderson  <rth@cygnus.com>
+
+       * c-decl.c (init_decl_processing): Provide proper fallback symbol
+       for __builtin_memset.
+       * expr.c (expand_builtin) [MEMSET]: Arg 3 type code is INTEGER_TYPE
+       not INTEGER_CST.  Assert arg 3 is a constant.
+
+       * alpha.c (mode_width_operand): Accept 64-bit modes.
+       (mode_mask_operand): Likewise.
+       (print_operand): Likewise for 'M' and 'U' codes.
+       (alpha_expand_unaligned_load): New function.
+       (alpha_expand_unaligned_store): Likewise.
+       (alpha_expand_unaligned_load_words): Likewise.
+       (alpha_expand_unaligned_store_words): Likewise.
+       (alpha_expand_block_move): Likewise.
+       (alpha_expand_block_clear): Likewise.
+       * alpha.h (MOVE_RATIO): New define.
+       * alpha.md (extxl, ext*h, ins*l, mskxl): Name them.
+       (insql, insxh, mskxh, extv, extzv, insv, movstrqi, clrstrqi): New.
+
+       * alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Set to 3.
+       (CONSTANT_ALIGNMENT, DATA_ALIGNMENT): Disable.
+
 Thu Jan  1 15:40:15 1998  Richard Henderson  <rth@cygnus.com>
 
        * configure.in: Put parenthesis around TARGET_CPU_DEFAULT's value.
index 0bc292a51950f308e7d5fe02edf73d049cd7c70f..d7f5737d3a92b48c3df3630e4bd40ddea59027cf 100644 (file)
@@ -3353,7 +3353,7 @@ init_decl_processing ()
   builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet,
                    BUILT_IN_MEMCMP, "memcmp");
   builtin_function ("__builtin_memset", memset_ftype,
-                   BUILT_IN_MEMSET, NULL_PTR);
+                   BUILT_IN_MEMSET, "memset");
   builtin_function ("__builtin_strcmp", int_ftype_string_string,
                    BUILT_IN_STRCMP, "strcmp");
   builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
@@ -3450,8 +3450,6 @@ init_decl_processing ()
                    BUILT_IN_FMOD, NULL_PTR);
   builtin_function ("__builtin_frem", double_ftype_double_double,
                    BUILT_IN_FREM, NULL_PTR);
-  builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int,
-                   BUILT_IN_MEMSET, NULL_PTR);
   builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
                    NULL_PTR);
   builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
index e36629fad958fa3781923c47a45b6513767b53ac..168ca7c8b99a0ccc2bd64ddff622a763ab22a00c 100644 (file)
@@ -450,7 +450,8 @@ mode_width_operand (op, mode)
      enum machine_mode mode;
 {
   return (GET_CODE (op) == CONST_INT
-         && (INTVAL (op) == 8 || INTVAL (op) == 16 || INTVAL (op) == 32));
+         && (INTVAL (op) == 8 || INTVAL (op) == 16
+             || INTVAL (op) == 32 || INTVAL (op) == 64));
 }
 
 /* Return 1 if OP is a constant that is the width of an integral machine mode
@@ -463,7 +464,12 @@ mode_mask_operand (op, mode)
 {
 #if HOST_BITS_PER_WIDE_INT == 32
   if (GET_CODE (op) == CONST_DOUBLE)
-    return CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == -1;
+    return (CONST_DOUBLE_LOW (op) == -1
+           && (CONST_DOUBLE_HIGH (op) == -1
+               || CONST_DOUBLE_HIGH (op) == 0));
+#else
+  if (GET_CODE (op) == CONST_DOUBLE)
+    return (CONST_DOUBLE_LOW (op) == -1 && CONST_DOUBLE_HIGH (op) == 0);
 #endif
 
   return (GET_CODE (op) == CONST_INT
@@ -471,6 +477,7 @@ mode_mask_operand (op, mode)
              || INTVAL (op) == 0xffff
 #if HOST_BITS_PER_WIDE_INT == 64
              || INTVAL (op) == 0xffffffff
+             || INTVAL (op) == 0xffffffffffffffff
 #endif
              ));
 }
@@ -1262,6 +1269,587 @@ alpha_emit_conditional_move (cmp, mode)
   emit_move_insn (tem, gen_rtx (code, cmp_op_mode, op0, op1));
   return gen_rtx (cmov_code, VOIDmode, tem, CONST0_RTX (cmp_op_mode));
 }
+\f
+/* Use ext[wlq][lh] as the Architecture Handbook describes for extracting
+   unaligned data:
+
+           unsigned:                       signed:
+   word:   ldq_u  r1,X(r11)                ldq_u  r1,X(r11)
+           ldq_u  r2,X+1(r11)              ldq_u  r2,X+1(r11)
+           lda    r3,X(r11)                lda    r3,X+2(r11)
+           extwl  r1,r3,r1                 extql  r1,r3,r1
+           extwh  r2,r3,r2                 extqh  r2,r3,r2
+           or     r1.r2.r1                 or     r1,r2,r1
+                                           sra    r1,48,r1
+
+   long:   ldq_u  r1,X(r11)                ldq_u  r1,X(r11)
+           ldq_u  r2,X+3(r11)              ldq_u  r2,X+3(r11)
+           lda    r3,X(r11)                lda    r3,X(r11)
+           extll  r1,r3,r1                 extll  r1,r3,r1
+           extlh  r2,r3,r2                 extlh  r2,r3,r2
+           or     r1.r2.r1                 addl   r1,r2,r1
+
+   quad:   ldq_u  r1,X(r11)
+           ldq_u  r2,X+7(r11)
+           lda    r3,X(r11)
+           extql  r1,r3,r1
+           extqh  r2,r3,r2
+           or     r1.r2.r1
+*/
+
+void
+alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
+     rtx tgt, mem;
+     HOST_WIDE_INT size, ofs;
+     int sign;
+{
+  rtx meml, memh, addr, extl, exth;
+
+  meml = gen_reg_rtx (DImode);
+  memh = gen_reg_rtx (DImode);
+  addr = gen_reg_rtx (DImode);
+  extl = gen_reg_rtx (DImode);
+  exth = gen_reg_rtx (DImode);
+
+  emit_move_insn (meml,
+                 change_address (mem, DImode,
+                                 gen_rtx (AND, DImode, 
+                                          plus_constant (XEXP (mem, 0), ofs),
+                                          GEN_INT (-8))));
+
+  emit_move_insn (memh,
+                 change_address (mem, DImode,
+                                 gen_rtx (AND, DImode, 
+                                          plus_constant (XEXP (mem, 0),
+                                                         ofs + size - 1),
+                                          GEN_INT (-8))));
+
+  if (sign && size == 2)
+    {
+      emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs+2));
+
+      emit_insn (gen_extxl (extl, meml, GEN_INT (64), addr));
+      emit_insn (gen_extqh (exth, memh, addr));
+
+      expand_binop (DImode, ior_optab, extl, exth, addr, 1, OPTAB_WIDEN);
+      expand_binop (DImode, ashr_optab, addr, GEN_INT (48), addr,
+                   1, OPTAB_WIDEN);
+      emit_move_insn (tgt, addr);
+      return;
+    }
+
+  emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs));
+  emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr));
+  switch (size)
+    {
+    case 2:
+      emit_insn (gen_extwh (exth, memh, addr));
+      break;
+
+    case 4:
+      emit_insn (gen_extlh (exth, memh, addr));
+      break;
+
+    case 8:
+      emit_insn (gen_extqh (exth, memh, addr));
+      break;
+    }
+
+  expand_binop (DImode, ior_optab, extl, exth, tgt, sign, OPTAB_WIDEN);
+}
+
+/* Similarly, use ins and msk instructions to perform unaligned stores.  */
+
+void
+alpha_expand_unaligned_store (dst, src, size, ofs)
+     rtx dst, src;
+     HOST_WIDE_INT size, ofs;
+{
+  rtx dstl, dsth, addr, insl, insh, meml, memh;
+  
+  dstl = gen_reg_rtx (DImode);
+  dsth = gen_reg_rtx (DImode);
+  insl = gen_reg_rtx (DImode);
+  insh = gen_reg_rtx (DImode);
+
+  meml = change_address (dst, DImode,
+                        gen_rtx (AND, DImode, 
+                                 plus_constant (XEXP (dst, 0), ofs),
+                                 GEN_INT (-8)));
+  memh = change_address (dst, DImode,
+                        gen_rtx (AND, DImode, 
+                                 plus_constant (XEXP (dst, 0), ofs+size-1),
+                                 GEN_INT (-8)));
+
+  emit_move_insn (dsth, memh);
+  emit_move_insn (dstl, meml);
+  addr = copy_addr_to_reg (plus_constant (XEXP (dst, 0), ofs));
+
+  if (src != const0_rtx)
+    {
+      emit_insn (gen_insxh (insh, src, GEN_INT (size*8), addr));
+
+      switch (size)
+       {
+       case 2:
+         emit_insn (gen_inswl (insl, gen_lowpart (HImode, src), addr));
+         break;
+       case 4:
+         emit_insn (gen_insll (insl, gen_lowpart (SImode, src), addr));
+         break;
+       case 8:
+         emit_insn (gen_insql (insl, src, addr));
+         break;
+       }
+    }
+
+  emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
+
+  switch (size)
+    {
+    case 2:
+      emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffff), addr));
+      break;
+    case 4:
+      emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffffffff), addr));
+      break;
+    case 8:
+      {
+#if HOST_BITS_PER_WIDE_INT == 32
+       rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
+#else
+       rtx msk = immed_double_const (0xffffffffffffffff, 0, DImode);
+#endif
+       emit_insn (gen_mskxl (dstl, dstl, msk, addr));
+      }
+      break;
+    }
+
+  if (src != const0_rtx)
+    {
+      expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN);
+      expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN);
+    }
+  
+  /* Must store high before low for degenerate case of aligned.  */
+  emit_move_insn (memh, dsth);
+  emit_move_insn (meml, dstl);
+}
+
+/* Load an integral number of consecutive unaligned quadwords.  */
+
+#define MAX_MOVE_WORDS 4
+
+static void
+alpha_expand_unaligned_load_words (data_regs, src_addr, words)
+     rtx data_regs[MAX_MOVE_WORDS+1];
+     rtx src_addr;
+     HOST_WIDE_INT words;
+{
+  rtx const im8 = GEN_INT (-8);
+  rtx const i64 = GEN_INT (64);
+  rtx ext_tmps[MAX_MOVE_WORDS];
+  rtx src_reg, and_reg;
+  HOST_WIDE_INT i;
+
+  /* Generate all the tmp registers we need.  */
+  for (i = 0; i < words; ++i)
+    ext_tmps[i] = gen_reg_rtx(DImode);
+  
+  /* Load up all of the source data.  */
+  for (i = 0; i < words; ++i)
+    {
+      emit_move_insn (data_regs[i],
+                     change_address (src_addr, DImode,
+                                     gen_rtx (AND, DImode,
+                                              plus_constant (XEXP(src_addr,0),
+                                                             8*i),
+                                              im8)));
+    }
+  emit_move_insn (data_regs[words],
+                 change_address (src_addr, DImode,
+                                 gen_rtx (AND, DImode,
+                                          plus_constant (XEXP(src_addr,0),
+                                                         8*words - 1),
+                                          im8)));
+
+  /* Extract the half-word fragments.  Unfortunately DEC decided to make
+     extxh with offset zero a noop instead of zeroing the register, so 
+     we must take care of that edge condition ourselves with cmov.  */
+
+  src_reg = copy_addr_to_reg (XEXP (src_addr, 0));
+  and_reg = expand_binop (DImode, and_optab, src_reg, GEN_INT (7), NULL, 
+                         1, OPTAB_WIDEN);
+  for (i = 0; i < words; ++i)
+    {
+      emit_insn (gen_extxl (data_regs[i], data_regs[i], i64, src_reg));
+
+      emit_insn (gen_extqh (ext_tmps[i], data_regs[i+1], src_reg));
+      emit_insn (gen_rtx (SET, VOIDmode, ext_tmps[i],
+                         gen_rtx (IF_THEN_ELSE, DImode,
+                                  gen_rtx (EQ, DImode, and_reg, const0_rtx),
+                                  const0_rtx, ext_tmps[i])));
+    }
+
+  /* Merge the half-words into whole words.  */
+  for (i = 0; i < words; ++i)
+    {
+      expand_binop (DImode, ior_optab, data_regs[i], ext_tmps[i],
+                   data_regs[i], 1, OPTAB_WIDEN);
+    }
+}
+
+/* Store an integral number of consecutive unaligned quadwords.  DATA_REGS
+   may be NULL to store zeros.  */
+
+static void
+alpha_expand_unaligned_store_words (data_regs, dst_addr, words)
+     rtx *data_regs;
+     rtx dst_addr;
+     HOST_WIDE_INT words;
+{
+  rtx const im8 = GEN_INT (-8);
+  rtx const i64 = GEN_INT (64);
+#if HOST_BITS_PER_WIDE_INT == 32
+  rtx const im1 = immed_double_const (0xffffffff, 0xffffffff, DImode);
+#else
+  rtx const im1 = immed_double_const (0xffffffffffffffff, 0, DImode);
+#endif
+  rtx ins_tmps[MAX_MOVE_WORDS];
+  rtx st_tmp_1, st_tmp_2, dst_reg;
+  rtx st_addr_1, st_addr_2;
+  HOST_WIDE_INT i;
+
+  /* Generate all the tmp registers we need.  */
+  if (data_regs != NULL)
+    for (i = 0; i < words; ++i)
+      ins_tmps[i] = gen_reg_rtx(DImode);
+  st_tmp_1 = gen_reg_rtx(DImode);
+  st_tmp_2 = gen_reg_rtx(DImode);
+  
+  st_addr_2 = change_address (dst_addr, DImode,
+                             gen_rtx (AND, DImode,
+                                      plus_constant (XEXP(dst_addr,0),
+                                                     words*8 - 1),
+                                      im8));
+  st_addr_1 = change_address (dst_addr, DImode,
+                             gen_rtx (AND, DImode, 
+                                      XEXP (dst_addr, 0),
+                                      im8));
+
+  /* Load up the destination end bits.  */
+  emit_move_insn (st_tmp_2, st_addr_2);
+  emit_move_insn (st_tmp_1, st_addr_1);
+
+  /* Shift the input data into place.  */
+  dst_reg = copy_addr_to_reg (XEXP (dst_addr, 0));
+
+  if (data_regs != NULL)
+    {
+      for (i = words-1; i >= 0; --i)
+       {
+         emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dst_reg));
+         emit_insn (gen_insql (data_regs[i], data_regs[i], dst_reg));
+       }
+
+      for (i = words-1; i > 0; --i)
+       {
+         expand_binop (DImode, ior_optab, data_regs[i], ins_tmps[i-1],
+                       ins_tmps[i-1], 1, OPTAB_WIDEN);
+       }
+    }
+
+  /* Split and merge the ends with the destination data.  */
+  emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dst_reg));
+  emit_insn (gen_mskxl (st_tmp_1, st_tmp_1, im1, dst_reg));
+
+  if (data_regs != NULL)
+    {
+      expand_binop (DImode, ior_optab, st_tmp_2, ins_tmps[words-1],
+                   st_tmp_2, 1, OPTAB_WIDEN);
+      expand_binop (DImode, ior_optab, st_tmp_1, data_regs[0],
+                   st_tmp_1, 1, OPTAB_WIDEN);
+    }
+
+  /* Store it all.  */
+  emit_move_insn (st_addr_2, st_tmp_2);
+  for (i = words-1; i > 0; --i)
+    {
+      emit_move_insn (change_address (dst_addr, DImode,
+                                     gen_rtx (AND, DImode,
+                                              plus_constant(XEXP (dst_addr,0),
+                                                            i*8),
+                                              im8)),
+                     data_regs ? ins_tmps[i-1] : const0_rtx);
+    }
+  emit_move_insn (st_addr_1, st_tmp_1);
+}
+
+
+/* Expand string/block move operations.
+
+   operands[0] is the pointer to the destination.
+   operands[1] is the pointer to the source.
+   operands[2] is the number of bytes to move.
+   operands[3] is the alignment.  */
+
+int
+alpha_expand_block_move (operands)
+     rtx operands[];
+{
+  rtx bytes_rtx        = operands[2];
+  rtx align_rtx = operands[3];
+  HOST_WIDE_INT bytes = INTVAL (bytes_rtx);
+  HOST_WIDE_INT align = INTVAL (align_rtx);
+  rtx orig_src = operands[1];
+  rtx orig_dst = operands[0];
+  rtx tmp = NULL_RTX;
+  rtx data_regs[2*MAX_MOVE_WORDS];
+  HOST_WIDE_INT i, words, ofs = 0;
+  
+  if (bytes <= 0)
+    return 1;
+  if (bytes > MAX_MOVE_WORDS*8)
+    return 0;
+
+  /* Handle a block of contiguous words first.  */
+
+  if (align >= 8 && bytes >= 8)
+    {
+      words = bytes / 8;
+
+      /* Make some data registers. */
+      for (i = 0; i < words; ++i)
+       data_regs[i] = gen_reg_rtx(DImode);
+
+      /* Move in aligned hunks.  */
+      for (i = 0; i < words; ++i)
+       {
+         emit_move_insn (data_regs[i],
+                         change_address(orig_src, DImode,
+                                        plus_constant (XEXP (orig_src, 0),
+                                                       i*8)));
+       }
+      for (i = 0; i < words; ++i)
+       {
+         emit_move_insn (change_address(orig_dst, DImode,
+                                        plus_constant (XEXP (orig_dst, 0),
+                                                       i*8)),
+                         data_regs[i]);
+       }
+
+      bytes -= words * 8;
+      ofs = words * 8;
+    }
+  if (align >= 4 && bytes >= 4)
+    {
+      words = bytes / 4;
+
+      /* Make some data registers. */
+      for (i = 0; i < words; ++i)
+       data_regs[i] = gen_reg_rtx(SImode);
+
+      /* Move in aligned hunks.  */
+      for (i = 0; i < words; ++i)
+       {
+         emit_move_insn (data_regs[i],
+                         change_address(orig_src, SImode,
+                                        plus_constant (XEXP (orig_src, 0),
+                                                       i*4)));
+       }
+      for (i = 0; i < words; ++i)
+       {
+         emit_move_insn (change_address(orig_dst, SImode,
+                                        plus_constant (XEXP (orig_dst, 0),
+                                                       i*4)),
+                         data_regs[i]);
+       }
+
+      bytes -= words * 4;
+      ofs = words * 4;
+    }
+  if (bytes >= 16)
+    {
+      words = bytes / 8;
+
+      /* Make some data registers. */
+      for (i = 0; i < words+1; ++i)
+       data_regs[i] = gen_reg_rtx(DImode);
+
+      /* Move in unaligned hunks.  */
+      alpha_expand_unaligned_load_words (data_regs, orig_src, words);
+      alpha_expand_unaligned_store_words (data_regs, orig_dst, words);
+
+      bytes -= words * 8;
+      ofs = words * 8;
+    }
+
+  /* Next clean up any trailing pieces.  We know from the contiguous
+     block move that there are no aligned SImode or DImode hunks left.  */
+
+  if (!TARGET_BWX && bytes >= 8)
+    {
+      tmp = gen_reg_rtx (DImode);
+      alpha_expand_unaligned_load (tmp, orig_src, 8, ofs, 0);
+      alpha_expand_unaligned_store (orig_dst, tmp, 8, ofs);
+
+      bytes -= 8;
+      ofs += 8;
+    }
+  if (!TARGET_BWX && bytes >= 4)
+    {
+      tmp = gen_reg_rtx (DImode);
+      alpha_expand_unaligned_load (tmp, orig_src, 4, ofs, 0);
+      alpha_expand_unaligned_store (orig_dst, tmp, 4, ofs);
+
+      bytes -= 4;
+      ofs += 4;
+    }
+  if (bytes >= 2)
+    {
+      if (align >= 2)
+       {
+         do {
+           emit_move_insn (change_address (orig_dst, HImode,
+                                           plus_constant (XEXP (orig_dst, 0),
+                                                          ofs)),
+                           change_address (orig_src, HImode,
+                                           plus_constant (XEXP (orig_src, 0),
+                                                          ofs)));
+           bytes -= 2;
+           ofs += 2;
+         } while (bytes >= 2);
+       }
+      else if (!TARGET_BWX)
+       {
+         tmp = gen_reg_rtx (DImode);
+         alpha_expand_unaligned_load (tmp, orig_src, 2, ofs, 0);
+         alpha_expand_unaligned_store (orig_dst, tmp, 2, ofs);
+         bytes -= 2;
+         ofs += 2;
+       }
+    }
+  while (bytes > 0)
+    {
+      emit_move_insn (change_address (orig_dst, QImode,
+                                     plus_constant (XEXP (orig_dst, 0),
+                                                    ofs)),
+                     change_address (orig_src, QImode,
+                                     plus_constant (XEXP (orig_src, 0),
+                                                    ofs)));
+      bytes -= 1;
+      ofs += 1;
+    }
+
+  return 1;
+}
+
+int
+alpha_expand_block_clear (operands)
+     rtx operands[];
+{
+  rtx bytes_rtx        = operands[1];
+  rtx align_rtx = operands[2];
+  HOST_WIDE_INT bytes = INTVAL (bytes_rtx);
+  HOST_WIDE_INT align = INTVAL (align_rtx);
+  rtx orig_dst = operands[0];
+  HOST_WIDE_INT i, words, ofs = 0;
+  
+  if (bytes <= 0)
+    return 1;
+  if (bytes > MAX_MOVE_WORDS*8)
+    return 0;
+
+  /* Handle a block of contiguous words first.  */
+
+  if (align >= 8 && bytes >= 8)
+    {
+      words = bytes / 8;
+
+      for (i = 0; i < words; ++i)
+       {
+         emit_move_insn (change_address(orig_dst, DImode,
+                                        plus_constant (XEXP (orig_dst, 0),
+                                                       i*8)),
+                         const0_rtx);
+       }
+
+      bytes -= words * 8;
+      ofs = words * 8;
+    }
+  else if (align >= 4 && bytes >= 4)
+    {
+      words = bytes / 4;
+
+      for (i = 0; i < words; ++i)
+       {
+         emit_move_insn (change_address(orig_dst, SImode,
+                                        plus_constant (XEXP (orig_dst, 0),
+                                                       i*4)),
+                         const0_rtx);
+       }
+
+      bytes -= words * 4;
+      ofs = words * 4;
+    }
+  else if (bytes >= 16)
+    {
+      words = bytes / 8;
+
+      alpha_expand_unaligned_store_words (NULL, orig_dst, words);
+
+      bytes -= words * 8;
+      ofs = words * 8;
+    }
+
+  /* Next clean up any trailing pieces.  We know from the contiguous
+     block move that there are no aligned SImode or DImode hunks left.  */
+
+  if (!TARGET_BWX && bytes >= 8)
+    {
+      alpha_expand_unaligned_store (orig_dst, const0_rtx, 8, ofs);
+      bytes -= 8;
+      ofs += 8;
+    }
+  if (!TARGET_BWX && bytes >= 4)
+    {
+      alpha_expand_unaligned_store (orig_dst, const0_rtx, 4, ofs);
+      bytes -= 4;
+      ofs += 4;
+    }
+  if (bytes >= 2)
+    {
+      if (align >= 2)
+       {
+         do {
+           emit_move_insn (change_address (orig_dst, HImode,
+                                           plus_constant (XEXP (orig_dst, 0),
+                                                          ofs)),
+                           const0_rtx);
+           bytes -= 2;
+           ofs += 2;
+         } while (bytes >= 2);
+       }
+      else if (!TARGET_BWX)
+       {
+         alpha_expand_unaligned_store (orig_dst, const0_rtx, 2, ofs);
+         bytes -= 2;
+         ofs += 2;
+       }
+    }
+  while (bytes > 0)
+    {
+      emit_move_insn (change_address (orig_dst, QImode,
+                                     plus_constant (XEXP (orig_dst, 0),
+                                                    ofs)),
+                     const0_rtx);
+      bytes -= 1;
+      ofs += 1;
+    }
+
+  return 1;
+}
+
 \f
 /* Adjust the cost of a scheduling dependency.  Return the new cost of
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
@@ -1667,13 +2255,17 @@ print_operand (file, x, code)
       break;
 
     case 'M':
-      /* 'b', 'w', or 'l' as the value of the constant.  */
+      /* 'b', 'w', 'l', or 'q' as the value of the constant.  */
       if (GET_CODE (x) != CONST_INT
-         || (INTVAL (x) != 8 && INTVAL (x) != 16 && INTVAL (x) != 32))
+         || (INTVAL (x) != 8 && INTVAL (x) != 16
+             && INTVAL (x) != 32 && INTVAL (x) != 64))
        output_operand_lossage ("invalid %%M value");
 
       fprintf (file, "%s",
-              INTVAL (x) == 8 ? "b" : INTVAL (x) == 16 ? "w" : "l");
+              (INTVAL (x) == 8 ? "b"
+               : INTVAL (x) == 16 ? "w"
+               : INTVAL (x) == 32 ? "l"
+               : "q"));
       break;
 
     case 'U':
@@ -1687,9 +2279,19 @@ print_operand (file, x, code)
               && CONST_DOUBLE_HIGH (x) == 0
               && CONST_DOUBLE_LOW (x) == -1)
        fprintf (file, "l");
+      else if (GET_CODE (x) == CONST_DOUBLE
+              && CONST_DOUBLE_HIGH (x) == -1
+              && CONST_DOUBLE_LOW (x) == -1)
+       fprintf (file, "q");
 #else
       else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff)
        fprintf (file, "l");
+      else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffffffffffff)
+       fprintf (file, "q");
+      else if (GET_CODE (x) == CONST_DOUBLE
+              && CONST_DOUBLE_HIGH (x) == 0
+              && CONST_DOUBLE_LOW (x) == -1)
+       fprintf (file, "q");
 #endif
       else
        output_operand_lossage ("invalid %%U value");
index 501fe564d0f8b9461d2f8ce6d2b0d86396f21077..459af5d8527faa0fd3c546966b433c17f47e9930 100644 (file)
@@ -384,18 +384,22 @@ extern void override_options ();
    ??? Kludge this and the next macro for the moment by not doing anything if
    we don't optimize and also if we are writing ECOFF symbols to work around
    a bug in DEC's assembler. */
+/* Aligning past 2**3 wastes insn cache lines, and doesn't buy much 
+   issue-wise on average anyway.  */
 
 #define ASM_OUTPUT_LOOP_ALIGN(FILE) \
   if (optimize > 0 && write_symbols != SDB_DEBUG)  \
-    ASM_OUTPUT_ALIGN (FILE, 5)
+    ASM_OUTPUT_ALIGN (FILE, 3)
 
 /* This is how to align an instruction for optimal branching.
    On Alpha we'll get better performance by aligning on a quadword
    boundary.  */
+/* Aligning past 2**3 wastes insn cache lines, and doesn't buy much 
+   issue-wise on average anyway.  */
 
 #define ASM_OUTPUT_ALIGN_CODE(FILE)    \
   if (optimize > 0 && write_symbols != SDB_DEBUG) \
-    ASM_OUTPUT_ALIGN ((FILE), 4)
+    ASM_OUTPUT_ALIGN ((FILE), 3)
 
 /* No data type wants to be aligned rounder than this.  */
 #define BIGGEST_ALIGNMENT 64
@@ -406,8 +410,12 @@ extern void override_options ();
 
 /* Align all constants and variables to at least a word boundary so
    we can pick up pieces of them faster.  */
+/* ??? Only if block-move stuff knows about different source/destination
+   alignment.  */
+#if 0
 #define CONSTANT_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD)
 #define DATA_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD)
+#endif
 
 /* Set this non-zero if move instructions will actually fail to work
    when given unaligned data.
@@ -1509,6 +1517,12 @@ extern void alpha_init_expanders ();
 
 #define MOVE_MAX 8
 
+/* Controls how many units are moved by expr.c before resorting to movstr.
+   Without byte/word accesses, we want no more than one; with, several single
+   byte accesses are better.   */
+
+#define MOVE_RATIO  (TARGET_BWX ? 7 : 2)
+
 /* Largest number of bytes of an object that can be placed in a register.
    On the Alpha we have plenty of registers, so use TImode.  */
 #define MAX_FIXED_MODE_SIZE    GET_MODE_BITSIZE (TImode)
index 583517f633f9292c794bb19428366fba2a8a3511..364de59b33d28d0989e9dadd18c6bd14e98ca6d0 100644 (file)
   "ext%M2l %r1,%s3,%0"
   [(set_attr "type" "shift")])
 
-(define_insn ""
+(define_insn "extxl"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
                         (match_operand:DI 2 "mode_width_operand" "n")
   "ext%M2l %r1,%3,%0"
   [(set_attr "type" "shift")])
 
-(define_insn ""
+(define_insn "extqh"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
         (match_operand:DI 1 "reg_or_0_operand" "rJ")
   "extqh %r1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn ""
+(define_insn "extlh"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
         (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
   "extlh %r1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn ""
+(define_insn "extwh"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
         (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
   "insll %1,%s2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn ""
+(define_insn "insbl"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
                   (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
   "insbl %1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn ""
+(define_insn "inswl"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
                   (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
   "inswl %1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn ""
+(define_insn "insll"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
                   (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
   "insll %1,%2,%0"
   [(set_attr "type" "shift")])
 
+(define_insn "insql"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (ashift:DI (match_operand:DI 1 "register_operand" "r")
+                  (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                             (const_int 3))))]
+  ""
+  "insql %1,%2,%0"
+  [(set_attr "type" "shift")])
+
 ;; We do not include the insXh insns because they are complex to express
 ;; and it does not appear that we would ever want to generate them.
+;;
+;; Since we need them for block moves, though, cop out and use unspec.
 
-(define_insn ""
+(define_insn "insxh"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec [(match_operand:DI 1 "register_operand" "r")
+                (match_operand:DI 2 "mode_width_operand" "n")
+                (match_operand:DI 3 "reg_or_8bit_operand" "rI")] 2))]
+  ""
+  "ins%M2h %1,%3,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "mskxl"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (and:DI (not:DI (ashift:DI
                         (match_operand:DI 2 "mode_mask_operand" "n")
   "msk%U2l %r1,%3,%0"
   [(set_attr "type" "shift")])
 
-;; We do not include the mskXh insns because it does not appear we would ever
-;; generate one.
+;; We do not include the mskXh insns because it does not appear we would
+;; ever generate one.
+;;
+;; Again, we do for block moves and we use unspec again.
+
+(define_insn "mskxh"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec [(match_operand:DI 1 "register_operand" "r")
+                (match_operand:DI 2 "mode_width_operand" "n")
+                (match_operand:DI 3 "reg_or_8bit_operand" "rI")] 3))]
+  ""
+  "msk%M2h %1,%3,%0"
+  [(set_attr "type" "shift")])
 \f
 ;; Floating-point operations.  All the double-precision insns can extend
 ;; from single, so indicate that.  The exception are the ones that simply
   DONE;
 }")
 \f
+;; Bit field extract patterns which use ext[wlq][lh]
+
+(define_expand "extv"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (sign_extract:DI (match_operand:QI 1 "memory_operand" "")
+                        (match_operand:DI 2 "immediate_operand" "")
+                        (match_operand:DI 3 "immediate_operand" "")))]
+  ""
+  "
+{
+  /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries.  */
+  if (INTVAL (operands[3]) % 8 != 0
+      || (INTVAL (operands[2]) != 16
+         && INTVAL (operands[2]) != 32
+         && INTVAL (operands[2]) != 64))
+    FAIL;
+
+  /* From mips.md: extract_bit_field doesn't verify that our source
+     matches the predicate, so we force it to be a MEM here.  */
+  if (GET_CODE (operands[1]) != MEM)
+    FAIL;
+
+  alpha_expand_unaligned_load (operands[0], operands[1],
+                              INTVAL (operands[2]) / 8,
+                              INTVAL (operands[3]) / 8, 1);
+  DONE;
+}")
+
+(define_expand "extzv"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (zero_extract:DI (match_operand:QI 1 "memory_operand" "")
+                        (match_operand:DI 2 "immediate_operand" "")
+                        (match_operand:DI 3 "immediate_operand" "")))]
+  ""
+  "
+{
+  /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries.  */
+  if (INTVAL (operands[3]) % 8 != 0
+      || (INTVAL (operands[2]) != 16
+         && INTVAL (operands[2]) != 32
+         && INTVAL (operands[2]) != 64))
+    FAIL;
+
+  /* From mips.md: extract_bit_field doesn't verify that our source
+     matches the predicate, so we force it to be a MEM here.  */
+  if (GET_CODE (operands[1]) != MEM)
+    FAIL;
+
+  alpha_expand_unaligned_load (operands[0], operands[1],
+                              INTVAL (operands[2]) / 8,
+                              INTVAL (operands[3]) / 8, 0);
+  DONE;
+}")
+
+(define_expand "insv"
+  [(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "")
+                        (match_operand:DI 1 "immediate_operand" "")
+                        (match_operand:DI 2 "immediate_operand" ""))
+       (match_operand:DI 3 "register_operand" ""))]
+  ""
+  "
+{
+  /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries.  */
+  if (INTVAL (operands[2]) % 8 != 0
+      || (INTVAL (operands[1]) != 16
+         && INTVAL (operands[1]) != 32
+         && INTVAL (operands[1]) != 64))
+    FAIL;
+
+  /* From mips.md: store_bit_field doesn't verify that our source
+     matches the predicate, so we force it to be a MEM here.  */
+  if (GET_CODE (operands[0]) != MEM)
+    FAIL;
+
+  alpha_expand_unaligned_store (operands[0], operands[3],
+                               INTVAL (operands[1]) / 8,
+                               INTVAL (operands[2]) / 8);
+  DONE;
+}")
+
+
+
+;; Block move/clear, see alpha.c for more details.
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+
+(define_expand "movstrqi"
+  [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+                  (match_operand:BLK 1 "general_operand" ""))
+             (use (match_operand:DI 2 "immediate_operand" ""))
+             (use (match_operand:DI 3 "immediate_operand" ""))])]
+  ""
+  "
+{
+  if (alpha_expand_block_move (operands))
+    DONE;
+  else
+    FAIL;
+}")
+
+(define_expand "clrstrqi"
+  [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+                  (const_int 0))
+             (use (match_operand:DI 1 "immediate_operand" ""))
+             (use (match_operand:DI 2 "immediate_operand" ""))])]
+  ""
+  "
+{
+  if (alpha_expand_block_clear (operands))
+    DONE;
+  else
+    FAIL;
+}")
+\f
 ;; Subroutine of stack space allocation.  Perform a stack probe.
 (define_expand "probe_stack"
   [(set (match_dup 1) (match_operand:DI 0 "const_int_operand" ""))]
index 623a9039bad94a136f0e0f4e9111d5a5822e287e..e54f3e47a45004df9f9b3f2eaf10901c27a485d8 100644 (file)
@@ -9036,7 +9036,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
              != INTEGER_TYPE)
          || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
-         || (INTEGER_CST
+         || (INTEGER_TYPE
              != (TREE_CODE (TREE_TYPE
                             (TREE_VALUE
                              (TREE_CHAIN (TREE_CHAIN (arglist))))))))
@@ -9061,11 +9061,16 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx)
            break;
 
+         /* If LEN does not expand to a constant, don't do this
+            operation in-line.  */
+         len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+         if (GET_CODE (len_rtx) != CONST_INT)
+           break;
+
          dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM);
          dest_mem = gen_rtx (MEM, BLKmode,
                              memory_address (BLKmode, dest_rtx));
-         len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
-
+          
          /* Just check DST is writable and mark it as readable.  */
          if (flag_check_memory_usage)
            emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
@@ -9074,7 +9079,6 @@ expand_builtin (exp, target, subtarget, mode, ignore)
                               GEN_INT (MEMORY_USE_WO),
                               TYPE_MODE (integer_type_node));
 
-
          /* There could be a void* cast on top of the object.  */
          while (TREE_CODE (dest) == NOP_EXPR)
            dest = TREE_OPERAND (dest, 0);