static enum rtx_code get_rtx_code (enum tree_code, bool);
static rtx vector_compare_rtx (tree, bool, enum insn_code);
+/* Current libcall id. It doesn't matter what these are, as long
+ as they are unique to each libcall that is emitted. */
+static HOST_WIDE_INT libcall_id = 0;
+
#ifndef HAVE_conditional_trap
#define HAVE_conditional_trap 0
#define gen_conditional_trap(a,b) (gcc_unreachable (), NULL_RTX)
#endif
+
+/* Prefixes for the current version of decimal floating point (BID vs. DPD) */
+#if ENABLE_DECIMAL_BID_FORMAT
+#define DECIMAL_PREFIX "bid_"
+#else
+#define DECIMAL_PREFIX "dpd_"
+#endif
+
\f
/* Add a REG_EQUAL note to the last insn in INSNS. TARGET is being set to
the result of operation CODE applied to OP0 (and OP1 if it is a binary
vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
case VEC_UNPACK_HI_EXPR:
- return TYPE_UNSIGNED (type) ?
+ 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_UNPACK_FLOAT_HI_EXPR:
+ /* The signedness is determined from input operand. */
+ return TYPE_UNSIGNED (type) ?
+ vec_unpacku_float_hi_optab : vec_unpacks_float_hi_optab;
+
+ case VEC_UNPACK_FLOAT_LO_EXPR:
+ /* The signedness is determined from input operand. */
+ return TYPE_UNSIGNED (type) ?
+ vec_unpacku_float_lo_optab : vec_unpacks_float_lo_optab;
+
+ case VEC_PACK_TRUNC_EXPR:
+ return vec_pack_trunc_optab;
+
case VEC_PACK_SAT_EXPR:
return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;
-
+
+ case VEC_PACK_FIX_TRUNC_EXPR:
+ /* The signedness is determined from output operand. */
+ return TYPE_UNSIGNED (type) ?
+ vec_pack_ufix_trunc_optab : vec_pack_sfix_trunc_optab;
+
default:
break;
}
trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
switch (code)
{
+ case POINTER_PLUS_EXPR:
case PLUS_EXPR:
return trapv ? addv_optab : add_optab;
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));
mode1 = insn_data[icode].operand[1].mode;
mode2 = insn_data[icode].operand[2].mode;
- rtx_op1 = expand_expr (vec_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ rtx_op1 = expand_normal (vec_oprnd);
if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode1)
&& mode1 != VOIDmode)
rtx_op1 = force_reg (mode1, rtx_op1);
- rtx_op2 = expand_expr (shift_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ rtx_op2 = expand_normal (shift_oprnd);
if (!(*insn_data[icode].operand[2].predicate) (rtx_op2, mode2)
&& mode2 != VOIDmode)
rtx_op2 = force_reg (mode2, rtx_op2);
&& mode1 != VOIDmode)
xop1 = copy_to_mode_reg (mode1, xop1);
- if (binoptab == vec_pack_mod_optab
+ if (binoptab == vec_pack_trunc_optab
|| binoptab == vec_pack_usat_optab
- || binoptab == vec_pack_ssat_optab)
+ || binoptab == vec_pack_ssat_optab
+ || binoptab == vec_pack_ufix_trunc_optab
+ || binoptab == vec_pack_sfix_trunc_optab)
{
/* The mode of the result is different then the mode of the
arguments. */
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;
}
- /* We can't widen a bswap. */
+ /* Widening (or narrowing) bswap needs special treatment. */
if (unoptab == bswap_optab)
- goto try_libcall;
+ {
+ 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);
logically equivalent to EQUIV, so it gets manipulated as a unit if it
is possible to do so. */
-static void
+void
maybe_encapsulate_block (rtx first, rtx last, rtx equiv)
{
if (!flag_non_call_exceptions || !may_trap_p (equiv))
REG_NOTES (first));
REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
REG_NOTES (last));
+ next = NEXT_INSN (last);
+ for (insn = first; insn != next; insn = NEXT_INSN (insn))
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LIBCALL_ID,
+ GEN_INT (libcall_id),
+ REG_NOTES (insn));
+ libcall_id++;
}
}
}
remove_note (insn, note);
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
remove_note (insn, note);
+ if ((note = find_reg_note (insn, REG_LIBCALL_ID, NULL)) != NULL)
+ remove_note (insn, note);
data.target = target;
data.first = insns;
Except for the first group of insns (the ones setting pseudos), the
block is delimited by REG_RETVAL and REG_LIBCALL notes. */
-
void
emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
{
remove_note (insn, note);
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
remove_note (insn, note);
+ if ((note = find_reg_note (insn, REG_LIBCALL_ID, NULL)) != NULL)
+ remove_note (insn, note);
next = NEXT_INSN (insn);
static void
init_floating_libfuncs (optab optable, const char *opname, int suffix)
{
+ char *dec_opname = alloca (sizeof (DECIMAL_PREFIX) + strlen (opname));
+
+ /* For BID support, change the name to have either a bid_ or dpd_ prefix
+ depending on the low level floating format used. */
+ memcpy (dec_opname, DECIMAL_PREFIX, sizeof (DECIMAL_PREFIX) - 1);
+ strcpy (dec_opname + sizeof (DECIMAL_PREFIX) - 1, opname);
+
init_libfuncs (optable, MIN_MODE_FLOAT, MAX_MODE_FLOAT, opname, suffix);
init_libfuncs (optable, MIN_MODE_DECIMAL_FLOAT, MAX_MODE_DECIMAL_FLOAT,
- opname, suffix);
+ dec_opname, suffix);
}
/* Initialize the libfunc fields of an entire group of entries of an
const char *fname, *tname;
const char *q;
char *libfunc_name, *suffix;
+ char *nondec_name, *dec_name, *nondec_suffix, *dec_suffix;
char *p;
+ /* If this is a decimal conversion, add the current BID vs. DPD prefix that
+ depends on which underlying decimal floating point format is used. */
+ const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
+
for (fmode = first_from_mode;
fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
tmode = GET_MODE_WIDER_MODE (tmode))
max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode)));
- libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
- libfunc_name[0] = '_';
- libfunc_name[1] = '_';
- memcpy (&libfunc_name[2], opname, opname_len);
- suffix = libfunc_name + opname_len + 2;
+ nondec_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
+ nondec_name[0] = '_';
+ nondec_name[1] = '_';
+ memcpy (&nondec_name[2], opname, opname_len);
+ nondec_suffix = nondec_name + opname_len + 2;
+
+ dec_name = alloca (2 + dec_len + opname_len + 2*max_mname_len + 1 + 1);
+ dec_name[0] = '_';
+ dec_name[1] = '_';
+ memcpy (&dec_name[2], DECIMAL_PREFIX, dec_len);
+ memcpy (&dec_name[2+dec_len], opname, opname_len);
+ dec_suffix = dec_name + dec_len + opname_len + 2;
for (fmode = first_from_mode; fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
fname = GET_MODE_NAME (fmode);
tname = GET_MODE_NAME (tmode);
+ if (DECIMAL_FLOAT_MODE_P(fmode) || DECIMAL_FLOAT_MODE_P(tmode))
+ {
+ libfunc_name = dec_name;
+ suffix = dec_suffix;
+ }
+ else
+ {
+ libfunc_name = nondec_name;
+ suffix = nondec_suffix;
+ }
+
p = suffix;
for (q = fname; *q; p++, q++)
*p = TOLOWER (*q);
enum machine_mode nmode, wmode;
const char *nname, *wname;
const char *q;
+ char *nondec_name, *dec_name, *nondec_suffix, *dec_suffix;
char *libfunc_name, *suffix;
char *p;
+ /* If this is a decimal conversion, add the current BID vs. DPD prefix that
+ depends on which underlying decimal floating point format is used. */
+ const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
+
for (nmode = first_mode; nmode != VOIDmode;
nmode = GET_MODE_WIDER_MODE (nmode))
max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode)));
- libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
- libfunc_name[0] = '_';
- libfunc_name[1] = '_';
- memcpy (&libfunc_name[2], opname, opname_len);
- suffix = libfunc_name + opname_len + 2;
+ nondec_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
+ nondec_name[0] = '_';
+ nondec_name[1] = '_';
+ memcpy (&nondec_name[2], opname, opname_len);
+ nondec_suffix = nondec_name + opname_len + 2;
+
+ dec_name = alloca (2 + dec_len + opname_len + 2*max_mname_len + 1 + 1);
+ dec_name[0] = '_';
+ dec_name[1] = '_';
+ memcpy (&dec_name[2], DECIMAL_PREFIX, dec_len);
+ memcpy (&dec_name[2 + dec_len], opname, opname_len);
+ dec_suffix = dec_name + dec_len + opname_len + 2;
for (nmode = first_mode; nmode != VOIDmode;
nmode = GET_MODE_WIDER_MODE (nmode))
nname = GET_MODE_NAME (nmode);
wname = GET_MODE_NAME (wmode);
+ if (DECIMAL_FLOAT_MODE_P(nmode) || DECIMAL_FLOAT_MODE_P(wmode))
+ {
+ libfunc_name = dec_name;
+ suffix = dec_suffix;
+ }
+ else
+ {
+ libfunc_name = nondec_name;
+ suffix = nondec_suffix;
+ }
+
p = suffix;
for (q = widening ? nname : wname; *q; p++, q++)
*p = TOLOWER (*q);
init_optabs (void)
{
unsigned int i;
+ enum machine_mode int_mode;
/* Start by initializing all tables to contain CODE_FOR_nothing. */
smul_widen_optab = init_optab (UNKNOWN);
umul_widen_optab = init_optab (UNKNOWN);
usmul_widen_optab = init_optab (UNKNOWN);
+ smadd_widen_optab = init_optab (UNKNOWN);
+ umadd_widen_optab = init_optab (UNKNOWN);
+ smsub_widen_optab = init_optab (UNKNOWN);
+ umsub_widen_optab = init_optab (UNKNOWN);
sdiv_optab = init_optab (DIV);
sdivv_optab = init_optabv (DIV);
sdivmod_optab = init_optab (UNKNOWN);
movstrict_optab = init_optab (STRICT_LOW_PART);
cmp_optab = init_optab (COMPARE);
+ storent_optab = init_optab (UNKNOWN);
+
ucmp_optab = init_optab (UNKNOWN);
tst_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);
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_unpacks_float_hi_optab = init_optab (UNKNOWN);
+ vec_unpacks_float_lo_optab = init_optab (UNKNOWN);
+ vec_unpacku_float_hi_optab = init_optab (UNKNOWN);
+ vec_unpacku_float_lo_optab = init_optab (UNKNOWN);
+ vec_pack_trunc_optab = init_optab (UNKNOWN);
vec_pack_usat_optab = init_optab (UNKNOWN);
vec_pack_ssat_optab = init_optab (UNKNOWN);
+ vec_pack_ufix_trunc_optab = init_optab (UNKNOWN);
+ vec_pack_sfix_trunc_optab = init_optab (UNKNOWN);
powi_optab = init_optab (UNKNOWN);
/* Fill in the optabs with the insns we support. */
init_all_optabs ();
+ /* The ffs function operates on `int'. Fall back on it if we do not
+ have a libgcc2 function for that width. */
+ int_mode = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0);
+ ffs_optab->handlers[(int) int_mode].libfunc = init_one_libfunc ("ffs");
+
/* Initialize the optabs with the names of the library functions. */
init_integral_libfuncs (add_optab, "add", '3');
init_floating_libfuncs (add_optab, "add", '3');
abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc
= init_one_libfunc ("cabs");
- /* The ffs function operates on `int'. */
- ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
- = init_one_libfunc ("ffs");
-
abort_libfunc = init_one_libfunc ("abort");
memcpy_libfunc = init_one_libfunc ("memcpy");
memmove_libfunc = init_one_libfunc ("memmove");
h = &o->handlers[j];
if (h->libfunc)
{
- gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF);
+ gcc_assert (GET_CODE (h->libfunc) == SYMBOL_REF);
fprintf (stderr, "%s\t%s:\t%s\n",
GET_RTX_NAME (o->code),
GET_MODE_NAME (j),
h = &o->handlers[j][k];
if (h->libfunc)
{
- gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF);
+ gcc_assert (GET_CODE (h->libfunc) == SYMBOL_REF);
fprintf (stderr, "%s\t%s\t%s:\t%s\n",
GET_RTX_NAME (o->code),
GET_MODE_NAME (j),
t_op1 = TREE_OPERAND (cond, 1);
/* Expand operands. */
- rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)), 1);
- rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), 1);
+ rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)),
+ EXPAND_STACK_PARM);
+ rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)),
+ EXPAND_STACK_PARM);
if (!insn_data[icode].operand[4].predicate (rtx_op0, GET_MODE (rtx_op0))
&& GET_MODE (rtx_op0) != VOIDmode)
cc_op0 = XEXP (comparison, 0);
cc_op1 = XEXP (comparison, 1);
/* Expand both operands and force them in reg, if required. */
- rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1),
- NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ rtx_op1 = expand_normal (TREE_OPERAND (vec_cond_expr, 1));
if (!insn_data[icode].operand[1].predicate (rtx_op1, mode)
&& mode != VOIDmode)
rtx_op1 = force_reg (mode, rtx_op1);
- rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2),
- NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ rtx_op2 = expand_normal (TREE_OPERAND (vec_cond_expr, 2));
if (!insn_data[icode].operand[2].predicate (rtx_op2, mode)
&& mode != VOIDmode)
rtx_op2 = force_reg (mode, rtx_op2);