/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of GCC.
case VEC_RSHIFT_EXPR:
return vec_shr_optab;
+ case VEC_WIDEN_MULT_HI_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
+
+ case VEC_WIDEN_MULT_LO_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
+
+ case VEC_UNPACK_HI_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_unpacku_hi_optab : vec_unpacks_hi_optab;
+
+ case VEC_UNPACK_LO_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_unpacku_lo_optab : vec_unpacks_lo_optab;
+
+ case VEC_PACK_MOD_EXPR:
+ return vec_pack_mod_optab;
+
+ case VEC_PACK_SAT_EXPR:
+ return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;
+
default:
break;
}
- trapv = flag_trapv && INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type);
+ trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
switch (code)
{
case PLUS_EXPR:
case ABS_EXPR:
return trapv ? absv_optab : abs_optab;
+ case VEC_EXTRACT_EVEN_EXPR:
+ return vec_extract_even_optab;
+
+ case VEC_EXTRACT_ODD_EXPR:
+ return vec_extract_odd_optab;
+
+ case VEC_INTERLEAVE_HIGH_EXPR:
+ return vec_interleave_high_optab;
+
+ case VEC_INTERLEAVE_LOW_EXPR:
+ return vec_interleave_low_optab;
+
default:
return NULL;
}
rtx temp;
rtx pat;
rtx xop0, xop1, wxop;
- int nops = TREE_CODE_LENGTH (TREE_CODE (exp));
+ int nops = TREE_OPERAND_LENGTH (exp);
oprnd0 = TREE_OPERAND (exp, 0);
tmode0 = TYPE_MODE (TREE_TYPE (oprnd0));
int icode = (int) binoptab->handlers[(int) mode].insn_code;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+ enum machine_mode tmp_mode;
rtx pat;
rtx xop0 = op0, xop1 = op1;
&& mode1 != VOIDmode)
xop1 = copy_to_mode_reg (mode1, xop1);
- if (!insn_data[icode].operand[0].predicate (temp, mode))
- temp = gen_reg_rtx (mode);
+ if (binoptab == vec_pack_mod_optab
+ || binoptab == vec_pack_usat_optab
+ || binoptab == vec_pack_ssat_optab)
+ {
+ /* The mode of the result is different then the mode of the
+ arguments. */
+ tmp_mode = insn_data[icode].operand[0].mode;
+ if (GET_MODE_NUNITS (tmp_mode) != 2 * GET_MODE_NUNITS (mode))
+ return 0;
+ }
+ else
+ tmp_mode = mode;
+
+ if (!insn_data[icode].operand[0].predicate (temp, tmp_mode))
+ temp = gen_reg_rtx (tmp_mode);
pat = GEN_FCN (icode) (temp, xop0, xop1);
if (pat)
return 0;
}
+/* Try calculating
+ (bswap:narrow x)
+ as
+ (lshiftrt:wide (bswap:wide x) ((width wide) - (width narrow))). */
+static rtx
+widen_bswap (enum machine_mode mode, rtx op0, rtx target)
+{
+ enum mode_class class = GET_MODE_CLASS (mode);
+ enum machine_mode wider_mode;
+ rtx x, last;
+
+ if (!CLASS_HAS_WIDER_MODES_P (class))
+ return NULL_RTX;
+
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ wider_mode != VOIDmode;
+ wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+ if (bswap_optab->handlers[wider_mode].insn_code != CODE_FOR_nothing)
+ goto found;
+ return NULL_RTX;
+
+ found:
+ last = get_last_insn ();
+
+ x = widen_operand (op0, wider_mode, mode, true, true);
+ x = expand_unop (wider_mode, bswap_optab, x, NULL_RTX, true);
+
+ if (x != 0)
+ x = expand_shift (RSHIFT_EXPR, wider_mode, x,
+ size_int (GET_MODE_BITSIZE (wider_mode)
+ - GET_MODE_BITSIZE (mode)),
+ NULL_RTX, true);
+
+ if (x != 0)
+ {
+ if (target == 0)
+ target = gen_reg_rtx (mode);
+ emit_move_insn (target, gen_lowpart (mode, x));
+ }
+ else
+ delete_insns_since (last);
+
+ return target;
+}
+
+/* Try calculating bswap as two bswaps of two word-sized operands. */
+
+static rtx
+expand_doubleword_bswap (enum machine_mode mode, rtx op, rtx target)
+{
+ rtx t0, t1;
+
+ t1 = expand_unop (word_mode, bswap_optab,
+ operand_subword_force (op, 0, mode), NULL_RTX, true);
+ t0 = expand_unop (word_mode, bswap_optab,
+ operand_subword_force (op, 1, mode), NULL_RTX, true);
+
+ if (target == 0)
+ target = gen_reg_rtx (mode);
+ if (REG_P (target))
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+ emit_move_insn (operand_subword (target, 0, 1, mode), t0);
+ emit_move_insn (operand_subword (target, 1, 1, mode), t1);
+
+ return target;
+}
+
/* Try calculating (parity x) as (and (popcount x) 1), where
popcount can also be done in a wider mode. */
static rtx
goto try_libcall;
}
+ /* Widening (or narrowing) bswap needs special treatment. */
+ if (unoptab == bswap_optab)
+ {
+ temp = widen_bswap (mode, op0, target);
+ if (temp)
+ return temp;
+
+ if (GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
+ && unoptab->handlers[word_mode].insn_code != CODE_FOR_nothing)
+ {
+ temp = expand_doubleword_bswap (mode, op0, target);
+ if (temp)
+ return temp;
+ }
+
+ goto try_libcall;
+ }
+
if (CLASS_HAS_WIDER_MODES_P (class))
for (wider_mode = GET_MODE_WIDER_MODE (mode);
wider_mode != VOIDmode;
absv_optab = init_optabv (ABS);
addcc_optab = init_optab (UNKNOWN);
one_cmpl_optab = init_optab (NOT);
+ bswap_optab = init_optab (BSWAP);
ffs_optab = init_optab (FFS);
clz_optab = init_optab (CLZ);
ctz_optab = init_optab (CTZ);
parity_optab = init_optab (PARITY);
sqrt_optab = init_optab (SQRT);
floor_optab = init_optab (UNKNOWN);
- lfloor_optab = init_optab (UNKNOWN);
ceil_optab = init_optab (UNKNOWN);
- lceil_optab = init_optab (UNKNOWN);
round_optab = init_optab (UNKNOWN);
btrunc_optab = init_optab (UNKNOWN);
nearbyint_optab = init_optab (UNKNOWN);
exp2_optab = init_optab (UNKNOWN);
expm1_optab = init_optab (UNKNOWN);
ldexp_optab = init_optab (UNKNOWN);
+ scalb_optab = init_optab (UNKNOWN);
logb_optab = init_optab (UNKNOWN);
ilogb_optab = init_optab (UNKNOWN);
log_optab = init_optab (UNKNOWN);
atan_optab = init_optab (UNKNOWN);
copysign_optab = init_optab (UNKNOWN);
+ isinf_optab = init_optab (UNKNOWN);
+
strlen_optab = init_optab (UNKNOWN);
cbranch_optab = init_optab (UNKNOWN);
cmov_optab = init_optab (UNKNOWN);
udot_prod_optab = init_optab (UNKNOWN);
vec_extract_optab = init_optab (UNKNOWN);
+ vec_extract_even_optab = init_optab (UNKNOWN);
+ vec_extract_odd_optab = init_optab (UNKNOWN);
+ vec_interleave_high_optab = init_optab (UNKNOWN);
+ vec_interleave_low_optab = init_optab (UNKNOWN);
vec_set_optab = init_optab (UNKNOWN);
vec_init_optab = init_optab (UNKNOWN);
vec_shl_optab = init_optab (UNKNOWN);
vec_shr_optab = init_optab (UNKNOWN);
vec_realign_load_optab = init_optab (UNKNOWN);
movmisalign_optab = init_optab (UNKNOWN);
+ vec_widen_umult_hi_optab = init_optab (UNKNOWN);
+ vec_widen_umult_lo_optab = init_optab (UNKNOWN);
+ vec_widen_smult_hi_optab = init_optab (UNKNOWN);
+ vec_widen_smult_lo_optab = init_optab (UNKNOWN);
+ vec_unpacks_hi_optab = init_optab (UNKNOWN);
+ vec_unpacks_lo_optab = init_optab (UNKNOWN);
+ vec_unpacku_hi_optab = init_optab (UNKNOWN);
+ vec_unpacku_lo_optab = init_optab (UNKNOWN);
+ vec_pack_mod_optab = init_optab (UNKNOWN);
+ vec_pack_usat_optab = init_optab (UNKNOWN);
+ vec_pack_ssat_optab = init_optab (UNKNOWN);
powi_optab = init_optab (UNKNOWN);
ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
lrint_optab = init_convert_optab (UNKNOWN);
lround_optab = init_convert_optab (UNKNOWN);
+ lfloor_optab = init_convert_optab (UNKNOWN);
+ lceil_optab = init_convert_optab (UNKNOWN);
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
MODE_INT, MODE_FLOAT);
init_interclass_conv_libfuncs (lround_optab, "lround",
MODE_INT, MODE_FLOAT);
+ init_interclass_conv_libfuncs (lfloor_optab, "lfloor",
+ MODE_INT, MODE_FLOAT);
+ init_interclass_conv_libfuncs (lceil_optab, "lceil",
+ MODE_INT, MODE_FLOAT);
/* sext_optab is also used for FLOAT_EXTEND. */
init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);
init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, MODE_DECIMAL_FLOAT);
init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, MODE_FLOAT);
+ /* Explicitly initialize the bswap libfuncs since we need them to be
+ valid for things other than word_mode. */
+ set_optab_libfunc (bswap_optab, SImode, "__bswapsi2");
+ set_optab_libfunc (bswap_optab, DImode, "__bswapdi2");
+
/* Use cabs for double complex abs, since systems generally have cabs.
Don't define any libcall for float complex, so that cabs will be used. */
if (complex_double_type_node)