alpha.c (code_for_builtin): Replace special-case builtin codes with ctzdi2, clzdi2...
authorRichard Henderson <rth@redhat.com>
Tue, 8 Mar 2005 12:01:17 +0000 (04:01 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Tue, 8 Mar 2005 12:01:17 +0000 (04:01 -0800)
        * config/alpha/alpha.c (code_for_builtin): Replace special-case
        builtin codes with ctzdi2, clzdi2, popcountdi2.
        (struct alpha_builtin_def): Add is_const.
        (zero_arg_builtins, one_arg_builtins, two_arg_builtins): Init it.
        (alpha_v8qi_u, alpha_v8qi_s, alpha_v4hi_u, alpha_v4hi_s): New.
        (alpha_init_builtins): Init them.  Set nothrow and const attributes
        on builtins.
        (alpha_fold_builtin_cmpbge, alpha_fold_builtin_zapnot,
        alpha_fold_builtin_extxx, alpha_fold_builtin_insxx,
        alpha_fold_builtin_mskxx, alpha_fold_builtin_umulh,
        alpha_fold_vector_minmax, alpha_fold_builtin_perr,
        alpha_fold_builtin_pklb, alpha_fold_builtin_pkwb,
        alpha_fold_builtin_unpkbl, alpha_fold_builtin_unpkbw,
        alpha_fold_builtin_cttz, alpha_fold_builtin_ctlz,
        alpha_fold_builtin_ctpop, alpha_fold_builtin): New.
        (TARGET_FOLD_BUILTIN): New.
        * config/alpha/alpha.md (UNSPEC_CTTZ): Remove.
        (UNSPEC_CTLZ, UNSPEC_CTPOP): Remove.
        (ffsdi2): Use ctz.
        (cttz, builtin_cttz, builtin_ctlz, builtin_ctpop): Remove.

From-SVN: r96098

gcc/ChangeLog
gcc/config/alpha/alpha.c
gcc/config/alpha/alpha.md

index 192220b347a3d023baab2f150a6a516d63fad497..82bd14d75fbb1c99f0c53498e25120689288dc68 100644 (file)
@@ -1,3 +1,26 @@
+2005-03-08  Richard Henderson  <rth@redhat.com>
+
+       * config/alpha/alpha.c (code_for_builtin): Replace special-case
+       builtin codes with ctzdi2, clzdi2, popcountdi2.
+       (struct alpha_builtin_def): Add is_const.
+       (zero_arg_builtins, one_arg_builtins, two_arg_builtins): Init it.
+       (alpha_v8qi_u, alpha_v8qi_s, alpha_v4hi_u, alpha_v4hi_s): New.
+       (alpha_init_builtins): Init them.  Set nothrow and const attributes
+       on builtins.
+       (alpha_fold_builtin_cmpbge, alpha_fold_builtin_zapnot, 
+       alpha_fold_builtin_extxx, alpha_fold_builtin_insxx, 
+       alpha_fold_builtin_mskxx, alpha_fold_builtin_umulh, 
+       alpha_fold_vector_minmax, alpha_fold_builtin_perr,
+       alpha_fold_builtin_pklb, alpha_fold_builtin_pkwb,
+       alpha_fold_builtin_unpkbl, alpha_fold_builtin_unpkbw,
+       alpha_fold_builtin_cttz, alpha_fold_builtin_ctlz,
+       alpha_fold_builtin_ctpop, alpha_fold_builtin): New.
+       (TARGET_FOLD_BUILTIN): New.
+       * config/alpha/alpha.md (UNSPEC_CTTZ): Remove.
+       (UNSPEC_CTLZ, UNSPEC_CTPOP): Remove.
+       (ffsdi2): Use ctz.
+       (cttz, builtin_cttz, builtin_ctlz, builtin_ctpop): Remove.
+
 2005-03-08  Ira Rosen  <irar@il.ibm.com>
 
        PR tree-optimization/20122
index 037dc4ad33e70bcd3912f0f505bf37b7c3bab976..773bd0d1c15b3ab895339a04d26468fad852c09d 100644 (file)
@@ -5901,9 +5901,9 @@ static unsigned int const code_for_builtin[ALPHA_BUILTIN_max] = {
   CODE_FOR_builtin_unpkbw,
 
   /* TARGET_CIX */
-  CODE_FOR_builtin_cttz,
-  CODE_FOR_builtin_ctlz,
-  CODE_FOR_builtin_ctpop
+  CODE_FOR_ctzdi2,
+  CODE_FOR_clzdi2,
+  CODE_FOR_popcountdi2
 };
 
 struct alpha_builtin_def
@@ -5911,75 +5911,84 @@ struct alpha_builtin_def
   const char *name;
   enum alpha_builtin code;
   unsigned int target_mask;
+  bool is_const;
 };
 
 static struct alpha_builtin_def const zero_arg_builtins[] = {
-  { "__builtin_alpha_implver", ALPHA_BUILTIN_IMPLVER,  0 },
-  { "__builtin_alpha_rpcc",    ALPHA_BUILTIN_RPCC,     0 }
+  { "__builtin_alpha_implver", ALPHA_BUILTIN_IMPLVER,  0, true },
+  { "__builtin_alpha_rpcc",    ALPHA_BUILTIN_RPCC,     0, false }
 };
 
 static struct alpha_builtin_def const one_arg_builtins[] = {
-  { "__builtin_alpha_amask",   ALPHA_BUILTIN_AMASK,    0 },
-  { "__builtin_alpha_pklb",    ALPHA_BUILTIN_PKLB,     MASK_MAX },
-  { "__builtin_alpha_pkwb",    ALPHA_BUILTIN_PKWB,     MASK_MAX },
-  { "__builtin_alpha_unpkbl",  ALPHA_BUILTIN_UNPKBL,   MASK_MAX },
-  { "__builtin_alpha_unpkbw",  ALPHA_BUILTIN_UNPKBW,   MASK_MAX },
-  { "__builtin_alpha_cttz",    ALPHA_BUILTIN_CTTZ,     MASK_CIX },
-  { "__builtin_alpha_ctlz",    ALPHA_BUILTIN_CTLZ,     MASK_CIX },
-  { "__builtin_alpha_ctpop",   ALPHA_BUILTIN_CTPOP,    MASK_CIX }
+  { "__builtin_alpha_amask",   ALPHA_BUILTIN_AMASK,    0, true },
+  { "__builtin_alpha_pklb",    ALPHA_BUILTIN_PKLB,     MASK_MAX, true },
+  { "__builtin_alpha_pkwb",    ALPHA_BUILTIN_PKWB,     MASK_MAX, true },
+  { "__builtin_alpha_unpkbl",  ALPHA_BUILTIN_UNPKBL,   MASK_MAX, true },
+  { "__builtin_alpha_unpkbw",  ALPHA_BUILTIN_UNPKBW,   MASK_MAX, true },
+  { "__builtin_alpha_cttz",    ALPHA_BUILTIN_CTTZ,     MASK_CIX, true },
+  { "__builtin_alpha_ctlz",    ALPHA_BUILTIN_CTLZ,     MASK_CIX, true },
+  { "__builtin_alpha_ctpop",   ALPHA_BUILTIN_CTPOP,    MASK_CIX, true }
 };
 
 static struct alpha_builtin_def const two_arg_builtins[] = {
-  { "__builtin_alpha_cmpbge",  ALPHA_BUILTIN_CMPBGE,   0 },
-  { "__builtin_alpha_extbl",   ALPHA_BUILTIN_EXTBL,    0 },
-  { "__builtin_alpha_extwl",   ALPHA_BUILTIN_EXTWL,    0 },
-  { "__builtin_alpha_extll",   ALPHA_BUILTIN_EXTLL,    0 },
-  { "__builtin_alpha_extql",   ALPHA_BUILTIN_EXTQL,    0 },
-  { "__builtin_alpha_extwh",   ALPHA_BUILTIN_EXTWH,    0 },
-  { "__builtin_alpha_extlh",   ALPHA_BUILTIN_EXTLH,    0 },
-  { "__builtin_alpha_extqh",   ALPHA_BUILTIN_EXTQH,    0 },
-  { "__builtin_alpha_insbl",   ALPHA_BUILTIN_INSBL,    0 },
-  { "__builtin_alpha_inswl",   ALPHA_BUILTIN_INSWL,    0 },
-  { "__builtin_alpha_insll",   ALPHA_BUILTIN_INSLL,    0 },
-  { "__builtin_alpha_insql",   ALPHA_BUILTIN_INSQL,    0 },
-  { "__builtin_alpha_inswh",   ALPHA_BUILTIN_INSWH,    0 },
-  { "__builtin_alpha_inslh",   ALPHA_BUILTIN_INSLH,    0 },
-  { "__builtin_alpha_insqh",   ALPHA_BUILTIN_INSQH,    0 },
-  { "__builtin_alpha_mskbl",   ALPHA_BUILTIN_MSKBL,    0 },
-  { "__builtin_alpha_mskwl",   ALPHA_BUILTIN_MSKWL,    0 },
-  { "__builtin_alpha_mskll",   ALPHA_BUILTIN_MSKLL,    0 },
-  { "__builtin_alpha_mskql",   ALPHA_BUILTIN_MSKQL,    0 },
-  { "__builtin_alpha_mskwh",   ALPHA_BUILTIN_MSKWH,    0 },
-  { "__builtin_alpha_msklh",   ALPHA_BUILTIN_MSKLH,    0 },
-  { "__builtin_alpha_mskqh",   ALPHA_BUILTIN_MSKQH,    0 },
-  { "__builtin_alpha_umulh",   ALPHA_BUILTIN_UMULH,    0 },
-  { "__builtin_alpha_zap",     ALPHA_BUILTIN_ZAP,      0 },
-  { "__builtin_alpha_zapnot",  ALPHA_BUILTIN_ZAPNOT,   0 },
-  { "__builtin_alpha_minub8",  ALPHA_BUILTIN_MINUB8,   MASK_MAX },
-  { "__builtin_alpha_minsb8",  ALPHA_BUILTIN_MINSB8,   MASK_MAX },
-  { "__builtin_alpha_minuw4",  ALPHA_BUILTIN_MINUW4,   MASK_MAX },
-  { "__builtin_alpha_minsw4",  ALPHA_BUILTIN_MINSW4,   MASK_MAX },
-  { "__builtin_alpha_maxub8",  ALPHA_BUILTIN_MAXUB8,   MASK_MAX },
-  { "__builtin_alpha_maxsb8",  ALPHA_BUILTIN_MAXSB8,   MASK_MAX },
-  { "__builtin_alpha_maxuw4",  ALPHA_BUILTIN_MAXUW4,   MASK_MAX },
-  { "__builtin_alpha_maxsw4",  ALPHA_BUILTIN_MAXSW4,   MASK_MAX },
-  { "__builtin_alpha_perr",    ALPHA_BUILTIN_PERR,     MASK_MAX }
+  { "__builtin_alpha_cmpbge",  ALPHA_BUILTIN_CMPBGE,   0, true },
+  { "__builtin_alpha_extbl",   ALPHA_BUILTIN_EXTBL,    0, true },
+  { "__builtin_alpha_extwl",   ALPHA_BUILTIN_EXTWL,    0, true },
+  { "__builtin_alpha_extll",   ALPHA_BUILTIN_EXTLL,    0, true },
+  { "__builtin_alpha_extql",   ALPHA_BUILTIN_EXTQL,    0, true },
+  { "__builtin_alpha_extwh",   ALPHA_BUILTIN_EXTWH,    0, true },
+  { "__builtin_alpha_extlh",   ALPHA_BUILTIN_EXTLH,    0, true },
+  { "__builtin_alpha_extqh",   ALPHA_BUILTIN_EXTQH,    0, true },
+  { "__builtin_alpha_insbl",   ALPHA_BUILTIN_INSBL,    0, true },
+  { "__builtin_alpha_inswl",   ALPHA_BUILTIN_INSWL,    0, true },
+  { "__builtin_alpha_insll",   ALPHA_BUILTIN_INSLL,    0, true },
+  { "__builtin_alpha_insql",   ALPHA_BUILTIN_INSQL,    0, true },
+  { "__builtin_alpha_inswh",   ALPHA_BUILTIN_INSWH,    0, true },
+  { "__builtin_alpha_inslh",   ALPHA_BUILTIN_INSLH,    0, true },
+  { "__builtin_alpha_insqh",   ALPHA_BUILTIN_INSQH,    0, true },
+  { "__builtin_alpha_mskbl",   ALPHA_BUILTIN_MSKBL,    0, true },
+  { "__builtin_alpha_mskwl",   ALPHA_BUILTIN_MSKWL,    0, true },
+  { "__builtin_alpha_mskll",   ALPHA_BUILTIN_MSKLL,    0, true },
+  { "__builtin_alpha_mskql",   ALPHA_BUILTIN_MSKQL,    0, true },
+  { "__builtin_alpha_mskwh",   ALPHA_BUILTIN_MSKWH,    0, true },
+  { "__builtin_alpha_msklh",   ALPHA_BUILTIN_MSKLH,    0, true },
+  { "__builtin_alpha_mskqh",   ALPHA_BUILTIN_MSKQH,    0, true },
+  { "__builtin_alpha_umulh",   ALPHA_BUILTIN_UMULH,    0, true },
+  { "__builtin_alpha_zap",     ALPHA_BUILTIN_ZAP,      0, true },
+  { "__builtin_alpha_zapnot",  ALPHA_BUILTIN_ZAPNOT,   0, true },
+  { "__builtin_alpha_minub8",  ALPHA_BUILTIN_MINUB8,   MASK_MAX, true },
+  { "__builtin_alpha_minsb8",  ALPHA_BUILTIN_MINSB8,   MASK_MAX, true },
+  { "__builtin_alpha_minuw4",  ALPHA_BUILTIN_MINUW4,   MASK_MAX, true },
+  { "__builtin_alpha_minsw4",  ALPHA_BUILTIN_MINSW4,   MASK_MAX, true },
+  { "__builtin_alpha_maxub8",  ALPHA_BUILTIN_MAXUB8,   MASK_MAX, true },
+  { "__builtin_alpha_maxsb8",  ALPHA_BUILTIN_MAXSB8,   MASK_MAX, true },
+  { "__builtin_alpha_maxuw4",  ALPHA_BUILTIN_MAXUW4,   MASK_MAX, true },
+  { "__builtin_alpha_maxsw4",  ALPHA_BUILTIN_MAXSW4,   MASK_MAX, true },
+  { "__builtin_alpha_perr",    ALPHA_BUILTIN_PERR,     MASK_MAX, true }
 };
 
+static GTY(()) tree alpha_v8qi_u;
+static GTY(()) tree alpha_v8qi_s;
+static GTY(()) tree alpha_v4hi_u;
+static GTY(()) tree alpha_v4hi_s;
+
 static void
 alpha_init_builtins (void)
 {
   const struct alpha_builtin_def *p;
-  tree ftype;
+  tree ftype, attrs[2];
   size_t i;
 
+  attrs[0] = tree_cons (get_identifier ("nothrow"), NULL, NULL);
+  attrs[1] = tree_cons (get_identifier ("const"), NULL, attrs[0]);
+
   ftype = build_function_type (long_integer_type_node, void_list_node);
 
   p = zero_arg_builtins;
   for (i = 0; i < ARRAY_SIZE (zero_arg_builtins); ++i, ++p)
     if ((target_flags & p->target_mask) == p->target_mask)
       lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
-                                  NULL, NULL_TREE);
+                                  NULL, attrs[p->is_const]);
 
   ftype = build_function_type_list (long_integer_type_node,
                                    long_integer_type_node, NULL_TREE);
@@ -5988,7 +5997,7 @@ alpha_init_builtins (void)
   for (i = 0; i < ARRAY_SIZE (one_arg_builtins); ++i, ++p)
     if ((target_flags & p->target_mask) == p->target_mask)
       lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
-                                  NULL, NULL_TREE);
+                                  NULL, attrs[p->is_const]);
 
   ftype = build_function_type_list (long_integer_type_node,
                                    long_integer_type_node,
@@ -5998,17 +6007,22 @@ alpha_init_builtins (void)
   for (i = 0; i < ARRAY_SIZE (two_arg_builtins); ++i, ++p)
     if ((target_flags & p->target_mask) == p->target_mask)
       lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
-                                  NULL, NULL_TREE);
+                                  NULL, attrs[p->is_const]);
 
   ftype = build_function_type (ptr_type_node, void_list_node);
   lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
                               ALPHA_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
-                              NULL, NULL_TREE);
+                              NULL, attrs[0]);
 
   ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
   lang_hooks.builtin_function ("__builtin_set_thread_pointer", ftype,
                               ALPHA_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
-                              NULL, NULL_TREE);
+                              NULL, attrs[0]);
+
+  alpha_v8qi_u = build_vector_type (unsigned_intQI_type_node, 8);
+  alpha_v8qi_s = build_vector_type (intQI_type_node, 8);
+  alpha_v4hi_u = build_vector_type (unsigned_intHI_type_node, 4);
+  alpha_v4hi_s = build_vector_type (intHI_type_node, 4);
 }
 
 /* Expand an expression EXP that calls a built-in function,
@@ -6096,6 +6110,483 @@ alpha_expand_builtin (tree exp, rtx target,
   else
     return const0_rtx;
 }
+
+
+/* Several bits below assume HWI >= 64 bits.  This should be enforced
+   by config.gcc.  */
+#if HOST_BITS_PER_WIDE_INT < 64
+# error "HOST_WIDE_INT too small"
+#endif
+
+/* Fold the builtin for the CMPBGE instruction.  This is a vector comparison
+   with an 8 bit output vector.  OPINT contains the integer operands; bit N
+   of OP_CONST is set if OPINT[N] is valid.  */
+
+static tree
+alpha_fold_builtin_cmpbge (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  if (op_const == 3)
+    {
+      int i, val;
+      for (i = 0, val = 0; i < 8; ++i)
+       {
+         unsigned HOST_WIDE_INT c0 = (opint[0] >> (i * 8)) & 0xff;
+         unsigned HOST_WIDE_INT c1 = (opint[1] >> (i * 8)) & 0xff;
+         if (c0 >= c1)
+           val |= 1 << i;
+       }
+      return build_int_cst (long_integer_type_node, val);
+    }
+  else if (op_const == 1 && opint[0] == 0)
+    return build_int_cst (long_integer_type_node, 0xff);
+  return NULL;
+}
+
+/* Fold the builtin for the ZAPNOT instruction.  This is essentially a 
+   specialized form of an AND operation.  Other byte manipulation instructions
+   are defined in terms of this instruction, so this is also used as a
+   subroutine for other builtins.
+
+   OP contains the tree operands; OPINT contains the extracted integer values.
+   Bit N of OP_CONST it set if OPINT[N] is valid.  OP may be null if only
+   OPINT may be considered.  */
+
+static tree
+alpha_fold_builtin_zapnot (tree *op, unsigned HOST_WIDE_INT opint[],
+                          long op_const)
+{
+  if (op_const & 2)
+    {
+      unsigned HOST_WIDE_INT mask = 0;
+      int i;
+
+      for (i = 0; i < 8; ++i)
+       if ((opint[1] >> i) & 1)
+         mask |= (unsigned HOST_WIDE_INT)0xff << (i * 8);
+
+      if (op_const & 1)
+       return build_int_cst (long_integer_type_node, opint[0] & mask);
+
+      if (op)
+       return fold (build2 (BIT_AND_EXPR, long_integer_type_node, op[0],
+                            build_int_cst (long_integer_type_node, mask)));
+    }
+  else if ((op_const & 1) && opint[0] == 0)
+    return build_int_cst (long_integer_type_node, 0);
+  return NULL;
+}
+
+/* Fold the builtins for the EXT family of instructions.  */
+
+static tree
+alpha_fold_builtin_extxx (tree op[], unsigned HOST_WIDE_INT opint[],
+                         long op_const, unsigned HOST_WIDE_INT bytemask,
+                         bool is_high)
+{
+  long zap_const = 2;
+  tree *zap_op = NULL;
+
+  if (op_const & 2)
+    {
+      unsigned HOST_WIDE_INT loc;
+
+      loc = opint[1] & 7;
+      if (BYTES_BIG_ENDIAN)
+        loc ^= 7;
+      loc *= 8;
+
+      if (loc != 0)
+       {
+         if (op_const & 1)
+           {
+             unsigned HOST_WIDE_INT temp = opint[0];
+             if (is_high)
+               temp <<= loc;
+             else
+               temp >>= loc;
+             opint[0] = temp;
+             zap_const = 3;
+           }
+       }
+      else
+       zap_op = op;
+    }
+  
+  opint[1] = bytemask;
+  return alpha_fold_builtin_zapnot (zap_op, opint, zap_const);
+}
+
+/* Fold the builtins for the INS family of instructions.  */
+
+static tree
+alpha_fold_builtin_insxx (tree op[], unsigned HOST_WIDE_INT opint[],
+                         long op_const, unsigned HOST_WIDE_INT bytemask,
+                         bool is_high)
+{
+  if ((op_const & 1) && opint[0] == 0)
+    return build_int_cst (long_integer_type_node, 0);
+
+  if (op_const & 2)
+    {
+      unsigned HOST_WIDE_INT temp, loc, byteloc;
+      tree *zap_op = NULL;
+
+      loc = opint[1] & 7;
+      if (BYTES_BIG_ENDIAN)
+        loc ^= 7;
+      bytemask <<= loc;
+
+      temp = opint[0];
+      if (is_high)
+       {
+         byteloc = (64 - (loc * 8)) & 0x3f;
+         if (byteloc == 0)
+           zap_op = op;
+         else
+           temp >>= byteloc;
+         bytemask >>= 8;
+       }
+      else
+       {
+         byteloc = loc * 8;
+         if (byteloc == 0)
+           zap_op = op;
+         else
+           temp <<= byteloc;
+       }
+
+      opint[0] = temp;
+      opint[1] = bytemask;
+      return alpha_fold_builtin_zapnot (zap_op, opint, op_const);
+    }
+
+  return NULL;
+}
+
+static tree
+alpha_fold_builtin_mskxx (tree op[], unsigned HOST_WIDE_INT opint[],
+                         long op_const, unsigned HOST_WIDE_INT bytemask,
+                         bool is_high)
+{
+  if (op_const & 2)
+    {
+      unsigned HOST_WIDE_INT loc;
+
+      loc = opint[1] & 7;
+      if (BYTES_BIG_ENDIAN)
+        loc ^= 7;
+      bytemask <<= loc;
+
+      if (is_high)
+       bytemask >>= 8;
+
+      opint[1] = bytemask ^ 0xff;
+    }
+
+  return alpha_fold_builtin_zapnot (op, opint, op_const);
+}
+
+static tree
+alpha_fold_builtin_umulh (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  switch (op_const)
+    {
+    case 3:
+      {
+       unsigned HOST_WIDE_INT l;
+       HOST_WIDE_INT h;
+
+       mul_double (opint[0], 0, opint[1], 0, &l, &h);
+
+#if HOST_BITS_PER_WIDE_INT > 64
+# error fixme
+#endif
+
+       return build_int_cst (long_integer_type_node, h);
+      }
+
+    case 1:
+      opint[1] = opint[0];
+      /* FALLTHRU */
+    case 2:
+      /* Note that (X*1) >> 64 == 0.  */
+      if (opint[1] == 0 || opint[1] == 1)
+       return build_int_cst (long_integer_type_node, 0);
+      break;
+    }
+  return NULL;
+}
+
+static tree
+alpha_fold_vector_minmax (enum tree_code code, tree op[], tree vtype)
+{
+  tree op0 = fold_convert (vtype, op[0]);
+  tree op1 = fold_convert (vtype, op[1]);
+  tree val = fold (build2 (code, vtype, op0, op1));
+  return fold_convert (long_integer_type_node, val);
+}
+
+static tree
+alpha_fold_builtin_perr (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp = 0;
+  int i;
+
+  if (op_const != 3)
+    return NULL;
+
+  for (i = 0; i < 8; ++i)
+    {
+      unsigned HOST_WIDE_INT a = (opint[0] >> (i * 8)) & 0xff;
+      unsigned HOST_WIDE_INT b = (opint[1] >> (i * 8)) & 0xff;
+      if (a >= b)
+       temp += a - b;
+      else
+       temp += b - a;
+    }
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_pklb (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] >> 24) & 0xff00;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_pkwb (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] >>  8) & 0xff00;
+  temp |= (opint[0] >> 16) & 0xff0000;
+  temp |= (opint[0] >> 24) & 0xff000000;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_unpkbl (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] & 0xff00) << 24;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_unpkbw (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] & 0x0000ff00) << 8;
+  temp |= (opint[0] & 0x00ff0000) << 16;
+  temp |= (opint[0] & 0xff000000) << 24;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_cttz (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  if (opint[0] == 0)
+    temp = 64;
+  else
+    temp = exact_log2 (opint[0] & -opint[0]);
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_ctlz (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  if (opint[0] == 0)
+    temp = 64;
+  else
+    temp = 64 - floor_log2 (opint[0]) - 1;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_ctpop (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp, op;
+
+  if (op_const == 0)
+    return NULL;
+
+  op = opint[0];
+  temp = 0;
+  while (op)
+    temp++, op &= op - 1;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+/* Fold one of our builtin functions.  */
+
+static tree
+alpha_fold_builtin (tree exp, bool ignore ATTRIBUTE_UNUSED)
+{
+  tree fndecl = get_callee_fndecl (exp);
+  tree op[MAX_ARGS], t;
+  unsigned HOST_WIDE_INT opint[MAX_ARGS];
+  long op_const = 0, arity = 0;
+
+  for (t = TREE_OPERAND (exp, 1); t ; t = TREE_CHAIN (t), ++arity)
+    {
+      tree arg = TREE_VALUE (t);
+      if (arg == error_mark_node)
+       return NULL;
+      if (arity >= MAX_ARGS)
+       return NULL;
+
+      op[arity] = arg;
+      opint[arity] = 0;
+      if (TREE_CODE (arg) == INTEGER_CST)
+       {
+          op_const |= 1L << arity;
+         opint[arity] = int_cst_value (arg);
+       }
+    }
+
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    case ALPHA_BUILTIN_CMPBGE:
+      return alpha_fold_builtin_cmpbge (opint, op_const);
+
+    case ALPHA_BUILTIN_EXTBL:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x01, false);
+    case ALPHA_BUILTIN_EXTWL:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x03, false);
+    case ALPHA_BUILTIN_EXTLL:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x0f, false);
+    case ALPHA_BUILTIN_EXTQL:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0xff, false);
+    case ALPHA_BUILTIN_EXTWH:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x03, true);
+    case ALPHA_BUILTIN_EXTLH:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x0f, true);
+    case ALPHA_BUILTIN_EXTQH:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0xff, true);
+
+    case ALPHA_BUILTIN_INSBL:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x01, false);
+    case ALPHA_BUILTIN_INSWL:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x03, false);
+    case ALPHA_BUILTIN_INSLL:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x0f, false);
+    case ALPHA_BUILTIN_INSQL:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0xff, false);
+    case ALPHA_BUILTIN_INSWH:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x03, true);
+    case ALPHA_BUILTIN_INSLH:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x0f, true);
+    case ALPHA_BUILTIN_INSQH:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0xff, true);
+
+    case ALPHA_BUILTIN_MSKBL:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x01, false);
+    case ALPHA_BUILTIN_MSKWL:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x03, false);
+    case ALPHA_BUILTIN_MSKLL:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x0f, false);
+    case ALPHA_BUILTIN_MSKQL:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0xff, false);
+    case ALPHA_BUILTIN_MSKWH:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x03, true);
+    case ALPHA_BUILTIN_MSKLH:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x0f, true);
+    case ALPHA_BUILTIN_MSKQH:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0xff, true);
+
+    case ALPHA_BUILTIN_UMULH:
+      return alpha_fold_builtin_umulh (opint, op_const);
+
+    case ALPHA_BUILTIN_ZAP:
+      opint[1] ^= 0xff;
+      /* FALLTHRU */
+    case ALPHA_BUILTIN_ZAPNOT:
+      return alpha_fold_builtin_zapnot (op, opint, op_const);
+
+    case ALPHA_BUILTIN_MINUB8:
+      return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v8qi_u);
+    case ALPHA_BUILTIN_MINSB8:
+      return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v8qi_s);
+    case ALPHA_BUILTIN_MINUW4:
+      return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v4hi_u);
+    case ALPHA_BUILTIN_MINSW4:
+      return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v4hi_s);
+    case ALPHA_BUILTIN_MAXUB8:
+      return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v8qi_u);
+    case ALPHA_BUILTIN_MAXSB8:
+      return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v8qi_s);
+    case ALPHA_BUILTIN_MAXUW4:
+      return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v4hi_u);
+    case ALPHA_BUILTIN_MAXSW4:
+      return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v4hi_s);
+
+    case ALPHA_BUILTIN_PERR:
+      return alpha_fold_builtin_perr (opint, op_const);
+    case ALPHA_BUILTIN_PKLB:
+      return alpha_fold_builtin_pklb (opint, op_const);
+    case ALPHA_BUILTIN_PKWB:
+      return alpha_fold_builtin_pkwb (opint, op_const);
+    case ALPHA_BUILTIN_UNPKBL:
+      return alpha_fold_builtin_unpkbl (opint, op_const);
+    case ALPHA_BUILTIN_UNPKBW:
+      return alpha_fold_builtin_unpkbw (opint, op_const);
+
+    case ALPHA_BUILTIN_CTTZ:
+      return alpha_fold_builtin_cttz (opint, op_const);
+    case ALPHA_BUILTIN_CTLZ:
+      return alpha_fold_builtin_ctlz (opint, op_const);
+    case ALPHA_BUILTIN_CTPOP:
+      return alpha_fold_builtin_ctpop (opint, op_const);
+
+    case ALPHA_BUILTIN_AMASK:
+    case ALPHA_BUILTIN_IMPLVER:
+    case ALPHA_BUILTIN_RPCC:
+    case ALPHA_BUILTIN_THREAD_POINTER:
+    case ALPHA_BUILTIN_SET_THREAD_POINTER:
+      /* None of these are foldable at compile-time.  */
+    default:
+      return NULL;
+    }
+}
 \f
 /* This page contains routines that are used to determine what the function
    prologue and epilogue code will do and write them out.  */
@@ -9597,6 +10088,8 @@ alpha_init_libfuncs (void)
 #define TARGET_INIT_BUILTINS alpha_init_builtins
 #undef  TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN alpha_expand_builtin
+#undef  TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN alpha_fold_builtin
 
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL alpha_function_ok_for_sibcall
index c643828acad54b0d853b5f3a8fe6b7a71932677f..5af462e3987930146f92db883cda36062a0ccb66 100644 (file)
@@ -26,7 +26,6 @@
 
 (define_constants
   [(UNSPEC_ARG_HOME    0)
-   (UNSPEC_CTTZ                1)
    (UNSPEC_INSXH       2)
    (UNSPEC_MSKXH       3)
    (UNSPEC_CVTQL       4)
@@ -56,9 +55,7 @@
    (UNSPEC_AMASK       24)
    (UNSPEC_IMPLVER     25)
    (UNSPEC_PERR                26)
-   (UNSPEC_CTLZ                27)
-   (UNSPEC_CTPOP       28)
-   (UNSPEC_COPYSIGN     29)
+   (UNSPEC_COPYSIGN     27)
   ])
 
 ;; UNSPEC_VOLATILE:
 
 (define_expand "ffsdi2"
   [(set (match_dup 2)
-       (unspec:DI [(match_operand:DI 1 "register_operand" "")] UNSPEC_CTTZ))
+       (ctz:DI (match_operand:DI 1 "register_operand" "")))
    (set (match_dup 3)
        (plus:DI (match_dup 2) (const_int 1)))
    (set (match_operand:DI 0 "register_operand" "")
   operands[3] = gen_reg_rtx (DImode);
 })
 
-(define_insn "*cttz"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-       (unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_CTTZ))]
-  "TARGET_CIX"
-  "cttz %1,%0"
-  ; EV6 calls all mvi and cttz/ctlz/popc class imisc, so just
-  ; reuse the existing type name.
-  [(set_attr "type" "mvi")])
-
 (define_insn "clzdi2"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (clz:DI (match_operand:DI 1 "register_operand" "r")))]
   "TARGET_MAX"
   "unpkbw %r1,%0"
   [(set_attr "type" "mvi")])
-
-(define_expand "builtin_cttz"
-  [(set (match_operand:DI 0 "register_operand" "")
-       (unspec:DI [(match_operand:DI 1 "register_operand" "")]
-                  UNSPEC_CTTZ))]
-  "TARGET_CIX"
-  "")
-
-(define_insn "builtin_ctlz"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-       (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
-                  UNSPEC_CTLZ))]
-  "TARGET_CIX"
-  "ctlz %1,%0"
-  [(set_attr "type" "mvi")])
-
-(define_insn "builtin_ctpop"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-       (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
-                  UNSPEC_CTPOP))]
-  "TARGET_CIX"
-  "ctpop %1,%0"
-  [(set_attr "type" "mvi")])
 \f
 ;; The call patterns are at the end of the file because their
 ;; wildcard operand0 interferes with nice recognition.