summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2005-03-08 12:01:17 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2005-03-08 12:01:17 +0000
commit849c7bc62a08f74e592b851ccc9017cf62855119 (patch)
treeca9d4140dfe57915b40135466a7e552e51bd84e3 /gcc
parentde455bfb742122bf2c8b7790dc23ff9985f9f311 (diff)
downloadgcc-849c7bc62a08f74e592b851ccc9017cf62855119.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@96098 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog23
-rw-r--r--gcc/config/alpha/alpha.c599
-rw-r--r--gcc/config/alpha/alpha.md39
3 files changed, 571 insertions, 90 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 192220b347a..82bd14d75fb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 037dc4ad33e..773bd0d1c15 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -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;
+ }
+}
/* 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
diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md
index c643828acad..5af462e3987 100644
--- a/gcc/config/alpha/alpha.md
+++ b/gcc/config/alpha/alpha.md
@@ -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:
@@ -1333,7 +1330,7 @@
(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" "")
@@ -1345,15 +1342,6 @@
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")))]
@@ -7716,29 +7704,6 @@
"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")])
;; The call patterns are at the end of the file because their
;; wildcard operand0 interferes with nice recognition.