From 360139876e080a505c41ad40e7fec7383a93fc8f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 8 Mar 2005 04:01:17 -0800 Subject: [PATCH] alpha.c (code_for_builtin): Replace special-case builtin codes with ctzdi2, clzdi2, popcountdi2. * 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 | 23 ++ gcc/config/alpha/alpha.c | 599 ++++++++++++++++++++++++++++++++++---- gcc/config/alpha/alpha.md | 39 +-- 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 + + * 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 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. -- 2.30.2