/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
is properly defined. */
#include "insn-config.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "tree-hasher.h"
#include "stor-layout.h"
#include "stringpool.h"
#include "varasm.h"
#include "tm_p.h"
#include "flags.h"
+#include "hard-reg-set.h"
#include "function.h"
#include "except.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "libfuncs.h"
#include "recog.h"
#include "reload.h"
-#include "ggc.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
#include "basic-block.h"
#include "target.h"
(this_target_libfuncs->x_libfunc_hash)
static void prepare_float_lib_cmp (rtx, rtx, enum rtx_code, rtx *,
- enum machine_mode *);
-static rtx expand_unop_direct (enum machine_mode, optab, rtx, rtx, int);
+ machine_mode *);
+static rtx expand_unop_direct (machine_mode, optab, rtx, rtx, int);
static void emit_libcall_block_1 (rtx_insn *, rtx, rtx, rtx, bool);
/* Debug facility for use in GDB. */
\f
/* Used for libfunc_hash. */
-static hashval_t
-hash_libfunc (const void *p)
+hashval_t
+libfunc_hasher::hash (libfunc_entry *e)
{
- const struct libfunc_entry *const e = (const struct libfunc_entry *) p;
return ((e->mode1 + e->mode2 * NUM_MACHINE_MODES) ^ e->op);
}
/* Used for libfunc_hash. */
-static int
-eq_libfunc (const void *p, const void *q)
+bool
+libfunc_hasher::equal (libfunc_entry *e1, libfunc_entry *e2)
{
- const struct libfunc_entry *const e1 = (const struct libfunc_entry *) p;
- const struct libfunc_entry *const e2 = (const struct libfunc_entry *) q;
return e1->op == e2->op && e1->mode1 == e2->mode1 && e1->mode2 == e2->mode2;
}
from MODE2 to MODE1. Trigger lazy initialization if needed, return NULL
if no libfunc is available. */
rtx
-convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
- enum machine_mode mode2)
+convert_optab_libfunc (convert_optab optab, machine_mode mode1,
+ machine_mode mode2)
{
struct libfunc_entry e;
struct libfunc_entry **slot;
e.op = optab;
e.mode1 = mode1;
e.mode2 = mode2;
- slot = (struct libfunc_entry **)
- htab_find_slot (libfunc_hash, &e, NO_INSERT);
+ slot = libfunc_hash->find_slot (&e, NO_INSERT);
if (!slot)
{
const struct convert_optab_libcall_d *d
return NULL;
d->libcall_gen (optab, d->libcall_basename, mode1, mode2);
- slot = (struct libfunc_entry **)
- htab_find_slot (libfunc_hash, &e, NO_INSERT);
+ slot = libfunc_hash->find_slot (&e, NO_INSERT);
if (!slot)
return NULL;
}
Trigger lazy initialization if needed, return NULL if no libfunc is
available. */
rtx
-optab_libfunc (optab optab, enum machine_mode mode)
+optab_libfunc (optab optab, machine_mode mode)
{
struct libfunc_entry e;
struct libfunc_entry **slot;
e.op = optab;
e.mode1 = mode;
e.mode2 = VOIDmode;
- slot = (struct libfunc_entry **)
- htab_find_slot (libfunc_hash, &e, NO_INSERT);
+ slot = libfunc_hash->find_slot (&e, NO_INSERT);
if (!slot)
{
const struct optab_libcall_d *d
return NULL;
d->libcall_gen (optab, d->libcall_basename, d->libcall_suffix, mode);
- slot = (struct libfunc_entry **)
- htab_find_slot (libfunc_hash, &e, NO_INSERT);
+ slot = libfunc_hash->find_slot (&e, NO_INSERT);
if (!slot)
return NULL;
}
for a widening operation would be. In most cases this would be OP0, but if
that's a constant it'll be VOIDmode, which isn't useful. */
-static enum machine_mode
-widened_mode (enum machine_mode to_mode, rtx op0, rtx op1)
+static machine_mode
+widened_mode (machine_mode to_mode, rtx op0, rtx op1)
{
- enum machine_mode m0 = GET_MODE (op0);
- enum machine_mode m1 = GET_MODE (op1);
- enum machine_mode result;
+ machine_mode m0 = GET_MODE (op0);
+ machine_mode m1 = GET_MODE (op1);
+ machine_mode result;
if (m0 == VOIDmode && m1 == VOIDmode)
return to_mode;
TO_MODE and a FROM_MODE. */
enum insn_code
-widening_optab_handler (optab op, enum machine_mode to_mode,
- enum machine_mode from_mode)
+widening_optab_handler (optab op, machine_mode to_mode,
+ machine_mode from_mode)
{
unsigned scode = (op << 16) | to_mode;
if (to_mode != from_mode && from_mode != VOIDmode)
non-widening optabs also. */
enum insn_code
-find_widening_optab_handler_and_mode (optab op, enum machine_mode to_mode,
- enum machine_mode from_mode,
+find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
+ machine_mode from_mode,
int permit_non_widening,
- enum machine_mode *found_mode)
+ machine_mode *found_mode)
{
for (; (permit_non_widening || from_mode != to_mode)
&& GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
of logical operations, but not right shifts. */
static rtx
-widen_operand (rtx op, enum machine_mode mode, enum machine_mode oldmode,
+widen_operand (rtx op, machine_mode mode, machine_mode oldmode,
int unsignedp, int no_extend)
{
rtx result;
return fma_optab;
case REDUC_MAX_EXPR:
- return TYPE_UNSIGNED (type) ? reduc_umax_optab : reduc_smax_optab;
+ return TYPE_UNSIGNED (type)
+ ? reduc_umax_scal_optab : reduc_smax_scal_optab;
case REDUC_MIN_EXPR:
- return TYPE_UNSIGNED (type) ? reduc_umin_optab : reduc_smin_optab;
+ return TYPE_UNSIGNED (type)
+ ? reduc_umin_scal_optab : reduc_smin_scal_optab;
case REDUC_PLUS_EXPR:
- return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
-
- case VEC_LSHIFT_EXPR:
- return vec_shl_optab;
-
- case VEC_RSHIFT_EXPR:
- return vec_shr_optab;
+ return reduc_plus_scal_optab;
case VEC_WIDEN_MULT_HI_EXPR:
return TYPE_UNSIGNED (type) ?
return unknown_optab;
}
}
-\f
+
+/* Given optab UNOPTAB that reduces a vector to a scalar, find instead the old
+ optab that produces a vector with the reduction result in one element,
+ for a tree with type TYPE. */
+
+optab
+scalar_reduc_to_vector (optab unoptab, const_tree type)
+{
+ switch (unoptab)
+ {
+ case reduc_plus_scal_optab:
+ return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
+
+ case reduc_smin_scal_optab: return reduc_smin_optab;
+ case reduc_umin_scal_optab: return reduc_umin_optab;
+ case reduc_smax_scal_optab: return reduc_smax_optab;
+ case reduc_umax_scal_optab: return reduc_umax_optab;
+ default: return unknown_optab;
+ }
+}
/* Expand vector widening operations.
{
struct expand_operand eops[4];
tree oprnd0, oprnd1, oprnd2;
- enum machine_mode wmode = VOIDmode, tmode0, tmode1 = VOIDmode;
+ machine_mode wmode = VOIDmode, tmode0, tmode1 = VOIDmode;
optab widen_pattern_optab;
enum insn_code icode;
int nops = TREE_CODE_LENGTH (ops->code);
this may or may not be TARGET. */
rtx
-expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
+expand_ternary_op (machine_mode mode, optab ternary_optab, rtx op0,
rtx op1, rtx op2, rtx target, int unsignedp)
{
struct expand_operand ops[4];
otherwise the same as for expand_binop. */
rtx
-simplify_expand_binop (enum machine_mode mode, optab binoptab,
+simplify_expand_binop (machine_mode mode, optab binoptab,
rtx op0, rtx op1, rtx target, int unsignedp,
enum optab_methods methods)
{
Return true if the expansion succeeded. */
bool
-force_expand_binop (enum machine_mode mode, optab binoptab,
+force_expand_binop (machine_mode mode, optab binoptab,
rtx op0, rtx op1, rtx target, int unsignedp,
enum optab_methods methods)
{
return true;
}
-/* Generate insns for VEC_LSHIFT_EXPR, VEC_RSHIFT_EXPR. */
-
-rtx
-expand_vec_shift_expr (sepops ops, rtx target)
-{
- struct expand_operand eops[3];
- enum insn_code icode;
- rtx rtx_op1, rtx_op2;
- enum machine_mode mode = TYPE_MODE (ops->type);
- tree vec_oprnd = ops->op0;
- tree shift_oprnd = ops->op1;
- optab shift_optab;
-
- switch (ops->code)
- {
- case VEC_RSHIFT_EXPR:
- shift_optab = vec_shr_optab;
- break;
- case VEC_LSHIFT_EXPR:
- shift_optab = vec_shl_optab;
- break;
- default:
- gcc_unreachable ();
- }
-
- icode = optab_handler (shift_optab, mode);
- gcc_assert (icode != CODE_FOR_nothing);
-
- rtx_op1 = expand_normal (vec_oprnd);
- rtx_op2 = expand_normal (shift_oprnd);
-
- create_output_operand (&eops[0], target, mode);
- create_input_operand (&eops[1], rtx_op1, GET_MODE (rtx_op1));
- create_convert_operand_from_type (&eops[2], rtx_op2, TREE_TYPE (shift_oprnd));
- expand_insn (icode, 3, eops);
-
- return eops[0].value;
-}
-
/* Create a new vector value in VMODE with all elements set to OP. The
mode of OP must be the element mode of VMODE. If OP is a constant,
then the return value will be a constant. */
static rtx
-expand_vector_broadcast (enum machine_mode vmode, rtx op)
+expand_vector_broadcast (machine_mode vmode, rtx op)
{
enum insn_code icode;
rtvec vec;
value are the same as for the parent routine. */
static bool
-expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
+expand_subword_shift (machine_mode op1_mode, optab binoptab,
rtx outof_input, rtx into_input, rtx op1,
rtx outof_target, rtx into_target,
int unsignedp, enum optab_methods methods,
}
-#ifdef HAVE_conditional_move
/* Try implementing expand_doubleword_shift using conditional moves.
The shift is by < BITS_PER_WORD if (CMP_CODE CMP1 CMP2) is true,
otherwise it is by >= BITS_PER_WORD. SUBWORD_OP1 and SUPERWORD_OP1
arguments are the same as the parent routine. */
static bool
-expand_doubleword_shift_condmove (enum machine_mode op1_mode, optab binoptab,
+expand_doubleword_shift_condmove (machine_mode op1_mode, optab binoptab,
enum rtx_code cmp_code, rtx cmp1, rtx cmp2,
rtx outof_input, rtx into_input,
rtx subword_op1, rtx superword_op1,
return true;
}
-#endif
/* Expand a doubleword shift (ashl, ashr or lshr) using word-mode shifts.
OUTOF_INPUT and INTO_INPUT are the two word-sized halves of the first
Return true if the shift could be successfully synthesized. */
static bool
-expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
+expand_doubleword_shift (machine_mode op1_mode, optab binoptab,
rtx outof_input, rtx into_input, rtx op1,
rtx outof_target, rtx into_target,
int unsignedp, enum optab_methods methods,
unsigned HOST_WIDE_INT shift_mask)
{
rtx superword_op1, tmp, cmp1, cmp2;
- rtx subword_label, done_label;
enum rtx_code cmp_code;
/* See if word-mode shifts by BITS_PER_WORD...BITS_PER_WORD * 2 - 1 will
unsignedp, methods, shift_mask);
}
-#ifdef HAVE_conditional_move
/* Try using conditional moves to generate straight-line code. */
- {
- rtx_insn *start = get_last_insn ();
- if (expand_doubleword_shift_condmove (op1_mode, binoptab,
- cmp_code, cmp1, cmp2,
- outof_input, into_input,
- op1, superword_op1,
- outof_target, into_target,
- unsignedp, methods, shift_mask))
- return true;
- delete_insns_since (start);
- }
-#endif
+ if (HAVE_conditional_move)
+ {
+ rtx_insn *start = get_last_insn ();
+ if (expand_doubleword_shift_condmove (op1_mode, binoptab,
+ cmp_code, cmp1, cmp2,
+ outof_input, into_input,
+ op1, superword_op1,
+ outof_target, into_target,
+ unsignedp, methods, shift_mask))
+ return true;
+ delete_insns_since (start);
+ }
/* As a last resort, use branches to select the correct alternative. */
- subword_label = gen_label_rtx ();
- done_label = gen_label_rtx ();
+ rtx_code_label *subword_label = gen_label_rtx ();
+ rtx_code_label *done_label = gen_label_rtx ();
NO_DEFER_POP;
do_compare_rtx_and_jump (cmp1, cmp2, cmp_code, false, op1_mode,
the 0 or -1. */
static rtx
-expand_doubleword_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_doubleword_mult (machine_mode mode, rtx op0, rtx op1, rtx target,
bool umulp, enum optab_methods methods)
{
int low = (WORDS_BIG_ENDIAN ? 1 : 0);
the operation to perform, not an optab pointer. All other
arguments are the same. */
rtx
-expand_simple_binop (enum machine_mode mode, enum rtx_code code, rtx op0,
+expand_simple_binop (machine_mode mode, enum rtx_code code, rtx op0,
rtx op1, rtx target, int unsignedp,
enum optab_methods methods)
{
register. Return X otherwise. UNSIGNEDP says whether X is unsigned. */
static rtx
-avoid_expensive_constant (enum machine_mode mode, optab binoptab,
+avoid_expensive_constant (machine_mode mode, optab binoptab,
int opn, rtx x, bool unsignedp)
{
bool speed = optimize_insn_for_speed_p ();
is an insn that directly implements the indicated operation.
Returns null if this is not possible. */
static rtx
-expand_binop_directly (enum machine_mode mode, optab binoptab,
+expand_binop_directly (machine_mode mode, optab binoptab,
rtx op0, rtx op1,
rtx target, int unsignedp, enum optab_methods methods,
rtx_insn *last)
{
- enum machine_mode from_mode = widened_mode (mode, op0, op1);
+ machine_mode from_mode = widened_mode (mode, op0, op1);
enum insn_code icode = find_widening_optab_handler (binoptab, mode,
from_mode, 1);
- enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
- enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
- enum machine_mode mode0, mode1, tmp_mode;
+ machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
+ machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
+ machine_mode mode0, mode1, tmp_mode;
struct expand_operand ops[3];
bool commutative_p;
- rtx pat;
+ rtx_insn *pat;
rtx xop0 = op0, xop1 = op1;
- rtx swap;
/* If it is a commutative operator and the modes would match
if we would swap the operands, we can save the conversions. */
if (commutative_p
&& GET_MODE (xop0) != xmode0 && GET_MODE (xop1) != xmode1
&& GET_MODE (xop0) == xmode1 && GET_MODE (xop1) == xmode1)
- {
- swap = xop0;
- xop0 = xop1;
- xop1 = swap;
- }
+ std::swap (xop0, xop1);
/* If we are optimizing, force expensive constants into a register. */
xop0 = avoid_expensive_constant (xmode0, binoptab, 0, xop0, unsignedp);
Also try to make the last operand a constant. */
if (commutative_p
&& swap_commutative_operands_with_target (target, xop0, xop1))
- {
- swap = xop1;
- xop1 = xop0;
- xop0 = swap;
- }
+ std::swap (xop0, xop1);
/* Now, if insn's predicates don't allow our operands, put them into
pseudo regs. */
/* If PAT is composed of more than one insn, try to add an appropriate
REG_EQUAL note to it. If we can't because TEMP conflicts with an
operand, call expand_binop again, this time without a target. */
- if (INSN_P (pat) && NEXT_INSN (as_a <rtx_insn *> (pat)) != NULL_RTX
- && ! add_equal_note (as_a <rtx_insn *> (pat), ops[0].value,
+ if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
+ && ! add_equal_note (pat, ops[0].value,
optab_to_code (binoptab),
ops[1].value, ops[2].value))
{
this may or may not be TARGET. */
rtx
-expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
+expand_binop (machine_mode mode, optab binoptab, rtx op0, rtx op1,
rtx target, int unsignedp, enum optab_methods methods)
{
enum optab_methods next_methods
= (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
? OPTAB_WIDEN : methods);
enum mode_class mclass;
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
rtx libfunc;
rtx temp;
rtx_insn *entry_last = get_last_insn ();
Also try to make the last operand a constant. */
if (commutative_optab_p (binoptab)
&& swap_commutative_operands_with_target (target, op0, op1))
- {
- temp = op1;
- op1 = op0;
- op0 = temp;
- }
+ std::swap (op0, op1);
/* These can be done a word at a time. */
if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
&& optab_handler (lshr_optab, word_mode) != CODE_FOR_nothing)
{
unsigned HOST_WIDE_INT shift_mask, double_shift_mask;
- enum machine_mode op1_mode;
+ machine_mode op1_mode;
double_shift_mask = targetm.shift_truncation_mask (mode);
shift_mask = targetm.shift_truncation_mask (word_mode);
if (optab_handler (mov_optab, mode) != CODE_FOR_nothing
|| ! rtx_equal_p (target, xtarget))
{
- rtx temp = emit_move_insn (target, xtarget);
+ rtx_insn *temp = emit_move_insn (target, xtarget);
set_dst_reg_note (temp, REG_EQUAL,
gen_rtx_fmt_ee (optab_to_code (binoptab),
{
rtx_insn *insns;
rtx op1x = op1;
- enum machine_mode op1_mode = mode;
+ machine_mode op1_mode = mode;
rtx value;
start_sequence ();
of an unsigned wider operation, since the result would be the same. */
rtx
-sign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab,
+sign_expand_binop (machine_mode mode, optab uoptab, optab soptab,
rtx op0, rtx op1, rtx target, int unsignedp,
enum optab_methods methods)
{
expand_twoval_unop (optab unoptab, rtx op0, rtx targ0, rtx targ1,
int unsignedp)
{
- enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
+ machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
enum mode_class mclass;
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
rtx_insn *entry_last = get_last_insn ();
rtx_insn *last;
expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
int unsignedp)
{
- enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
+ machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
enum mode_class mclass;
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
rtx_insn *entry_last = get_last_insn ();
rtx_insn *last;
{
struct expand_operand ops[4];
enum insn_code icode = optab_handler (binoptab, mode);
- enum machine_mode mode0 = insn_data[icode].operand[1].mode;
- enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+ machine_mode mode0 = insn_data[icode].operand[1].mode;
+ machine_mode mode1 = insn_data[icode].operand[2].mode;
rtx xop0 = op0, xop1 = op1;
/* If we are optimizing, force expensive constants into a register. */
expand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1,
rtx targ0, rtx targ1, enum rtx_code code)
{
- enum machine_mode mode;
- enum machine_mode libval_mode;
+ machine_mode mode;
+ machine_mode libval_mode;
rtx libval;
rtx_insn *insns;
rtx libfunc;
the operation to perform, not an optab pointer. All other
arguments are the same. */
rtx
-expand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0,
+expand_simple_unop (machine_mode mode, enum rtx_code code, rtx op0,
rtx target, int unsignedp)
{
optab unop = code_to_optab (code);
A similar operation can be used for clrsb. UNOPTAB says which operation
we are trying to expand. */
static rtx
-widen_leading (enum machine_mode mode, rtx op0, rtx target, optab unoptab)
+widen_leading (machine_mode mode, rtx op0, rtx target, optab unoptab)
{
enum mode_class mclass = GET_MODE_CLASS (mode);
if (CLASS_HAS_WIDER_MODES_P (mclass))
{
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
for (wider_mode = GET_MODE_WIDER_MODE (mode);
wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
/* Try calculating clz of a double-word quantity as two clz's of word-sized
quantities, choosing which based on whether the high word is nonzero. */
static rtx
-expand_doubleword_clz (enum machine_mode mode, rtx op0, rtx target)
+expand_doubleword_clz (machine_mode mode, rtx op0, rtx target)
{
rtx xop0 = force_reg (mode, op0);
rtx subhi = gen_highpart (word_mode, xop0);
as
(lshiftrt:wide (bswap:wide x) ((width wide) - (width narrow))). */
static rtx
-widen_bswap (enum machine_mode mode, rtx op0, rtx target)
+widen_bswap (machine_mode mode, rtx op0, rtx target)
{
enum mode_class mclass = GET_MODE_CLASS (mode);
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
rtx x;
rtx_insn *last;
/* Try calculating bswap as two bswaps of two word-sized operands. */
static rtx
-expand_doubleword_bswap (enum machine_mode mode, rtx op, rtx target)
+expand_doubleword_bswap (machine_mode mode, rtx op, rtx target)
{
rtx t0, t1;
/* Try calculating (parity x) as (and (popcount x) 1), where
popcount can also be done in a wider mode. */
static rtx
-expand_parity (enum machine_mode mode, rtx op0, rtx target)
+expand_parity (machine_mode mode, rtx op0, rtx target)
{
enum mode_class mclass = GET_MODE_CLASS (mode);
if (CLASS_HAS_WIDER_MODES_P (mclass))
{
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
for (wider_mode = mode; wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
less convenient for expand_ffs anyway. */
static rtx
-expand_ctz (enum machine_mode mode, rtx op0, rtx target)
+expand_ctz (machine_mode mode, rtx op0, rtx target)
{
rtx_insn *seq;
rtx temp;
may have an undefined value in that case. If they do not give us a
convenient value, we have to generate a test and branch. */
static rtx
-expand_ffs (enum machine_mode mode, rtx op0, rtx target)
+expand_ffs (machine_mode mode, rtx op0, rtx target)
{
HOST_WIDE_INT val = 0;
bool defined_at_zero = false;
register will work around the situation. */
static rtx
-lowpart_subreg_maybe_copy (enum machine_mode omode, rtx val,
- enum machine_mode imode)
+lowpart_subreg_maybe_copy (machine_mode omode, rtx val,
+ machine_mode imode)
{
rtx ret;
ret = lowpart_subreg (omode, val, imode);
logical operation on the sign bit. */
static rtx
-expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
+expand_absneg_bit (enum rtx_code code, machine_mode mode,
rtx op0, rtx target)
{
const struct real_format *fmt;
int bitpos, word, nwords, i;
- enum machine_mode imode;
+ machine_mode imode;
rtx temp;
rtx_insn *insns;
/* As expand_unop, but will fail rather than attempt the operation in a
different mode or with a libcall. */
static rtx
-expand_unop_direct (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
+expand_unop_direct (machine_mode mode, optab unoptab, rtx op0, rtx target,
int unsignedp)
{
if (optab_handler (unoptab, mode) != CODE_FOR_nothing)
struct expand_operand ops[2];
enum insn_code icode = optab_handler (unoptab, mode);
rtx_insn *last = get_last_insn ();
- rtx pat;
+ rtx_insn *pat;
create_output_operand (&ops[0], target, mode);
create_convert_operand_from (&ops[1], op0, mode, unsignedp);
pat = maybe_gen_insn (icode, 2, ops);
if (pat)
{
- if (INSN_P (pat) && NEXT_INSN (as_a <rtx_insn *> (pat)) != NULL_RTX
- && ! add_equal_note (as_a <rtx_insn *> (pat), ops[0].value,
+ if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
+ && ! add_equal_note (pat, ops[0].value,
optab_to_code (unoptab),
ops[1].value, NULL_RTX))
{
this may or may not be TARGET. */
rtx
-expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
+expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target,
int unsignedp)
{
enum mode_class mclass = GET_MODE_CLASS (mode);
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
rtx temp;
rtx libfunc;
rtx_insn *insns;
rtx value;
rtx eq_value;
- enum machine_mode outmode = mode;
+ machine_mode outmode = mode;
/* All of these functions return small values. Thus we choose to
have them return something that isn't a double-word. */
*/
rtx
-expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
+expand_abs_nojump (machine_mode mode, rtx op0, rtx target,
int result_unsignedp)
{
rtx temp;
}
rtx
-expand_abs (enum machine_mode mode, rtx op0, rtx target,
+expand_abs (machine_mode mode, rtx op0, rtx target,
int result_unsignedp, int safe)
{
rtx temp;
NO_DEFER_POP;
do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
- NULL_RTX, NULL_RTX, op1, -1);
+ NULL_RTX, NULL, op1, -1);
op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
target, target, 0);
different but can be deduced from MODE. */
rtx
-expand_one_cmpl_abs_nojump (enum machine_mode mode, rtx op0, rtx target)
+expand_one_cmpl_abs_nojump (machine_mode mode, rtx op0, rtx target)
{
rtx temp;
and not playing with subregs so much, will help the register allocator. */
static rtx
-expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_copysign_absneg (machine_mode mode, rtx op0, rtx op1, rtx target,
int bitpos, bool op0_is_abs)
{
- enum machine_mode imode;
+ machine_mode imode;
enum insn_code icode;
rtx sign;
rtx_code_label *label;
is true if op0 is known to have its sign bit clear. */
static rtx
-expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_copysign_bit (machine_mode mode, rtx op0, rtx op1, rtx target,
int bitpos, bool op0_is_abs)
{
- enum machine_mode imode;
+ machine_mode imode;
int word, nwords, i;
rtx temp;
rtx_insn *insns;
rtx
expand_copysign (rtx op0, rtx op1, rtx target)
{
- enum machine_mode mode = GET_MODE (op0);
+ machine_mode mode = GET_MODE (op0);
const struct real_format *fmt;
bool op0_is_abs;
rtx temp;
enum rtx_code code)
{
struct expand_operand ops[2];
- rtx pat;
+ rtx_insn *pat;
create_output_operand (&ops[0], target, GET_MODE (target));
create_input_operand (&ops[1], op0, GET_MODE (op0));
if (!pat)
return false;
- if (INSN_P (pat) && NEXT_INSN (as_a <rtx_insn *> (pat)) != NULL_RTX
+ if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
&& code != UNKNOWN)
- add_equal_note (as_a <rtx_insn *> (pat), ops[0].value, code, ops[1].value,
- NULL_RTX);
+ add_equal_note (pat, ops[0].value, code, ops[1].value, NULL_RTX);
emit_insn (pat);
required to implement all (or any) of the unordered bcc operations. */
int
-can_compare_p (enum rtx_code code, enum machine_mode mode,
+can_compare_p (enum rtx_code code, machine_mode mode,
enum can_compare_purpose purpose)
{
rtx test;
static void
prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
int unsignedp, enum optab_methods methods,
- rtx *ptest, enum machine_mode *pmode)
+ rtx *ptest, machine_mode *pmode)
{
- enum machine_mode mode = *pmode;
+ machine_mode mode = *pmode;
rtx libfunc, test;
- enum machine_mode cmp_mode;
+ machine_mode cmp_mode;
enum mode_class mclass;
/* The other methods are not needed. */
> COSTS_N_INSNS (1)))
y = force_reg (mode, y);
-#ifdef HAVE_cc0
+#if HAVE_cc0
/* Make sure if we have a canonical comparison. The RTL
documentation states that canonical comparisons are required only
for targets which have cc0. */
if (mode == BLKmode)
{
- enum machine_mode result_mode;
+ machine_mode result_mode;
enum insn_code cmp_code;
tree length_type;
rtx libfunc;
if (GET_MODE_CLASS (mode) == MODE_CC)
{
- gcc_assert (can_compare_p (comparison, CCmode, ccp_jump));
- *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
+ enum insn_code icode = optab_handler (cbranch_optab, CCmode);
+ test = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
+ gcc_assert (icode != CODE_FOR_nothing
+ && insn_operand_matches (icode, 0, test));
+ *ptest = test;
return;
}
if (!SCALAR_FLOAT_MODE_P (mode))
{
rtx result;
- enum machine_mode ret_mode;
+ machine_mode ret_mode;
/* Handle a libcall just for the mode we are using. */
libfunc = optab_libfunc (cmp_optab, mode);
y = const0_rtx;
}
- *pmode = word_mode;
+ *pmode = ret_mode;
prepare_cmp_insn (x, y, comparison, NULL_RTX, unsignedp, methods,
ptest, pmode);
}
that it is accepted by the operand predicate. Return the new value. */
rtx
-prepare_operand (enum insn_code icode, rtx x, int opnum, enum machine_mode mode,
- enum machine_mode wider_mode, int unsignedp)
+prepare_operand (enum insn_code icode, rtx x, int opnum, machine_mode mode,
+ machine_mode wider_mode, int unsignedp)
{
if (mode != wider_mode)
x = convert_modes (wider_mode, mode, x, unsignedp);
if (!insn_operand_matches (icode, opnum, x))
{
+ machine_mode op_mode = insn_data[(int) icode].operand[opnum].mode;
if (reload_completed)
return NULL_RTX;
- x = copy_to_mode_reg (insn_data[(int) icode].operand[opnum].mode, x);
+ if (GET_MODE (x) != op_mode && GET_MODE (x) != VOIDmode)
+ return NULL_RTX;
+ x = copy_to_mode_reg (op_mode, x);
}
return x;
we can do the branch. */
static void
-emit_cmp_and_jump_insn_1 (rtx test, enum machine_mode mode, rtx label, int prob)
+emit_cmp_and_jump_insn_1 (rtx test, machine_mode mode, rtx label, int prob)
{
- enum machine_mode optab_mode;
+ machine_mode optab_mode;
enum mode_class mclass;
enum insn_code icode;
rtx_insn *insn;
void
emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
- enum machine_mode mode, int unsignedp, rtx label,
+ machine_mode mode, int unsignedp, rtx label,
int prob)
{
rtx op0 = x, op1 = y;
static void
prepare_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison,
- rtx *ptest, enum machine_mode *pmode)
+ rtx *ptest, machine_mode *pmode)
{
enum rtx_code swapped = swap_condition (comparison);
enum rtx_code reversed = reverse_condition_maybe_unordered (comparison);
- enum machine_mode orig_mode = GET_MODE (x);
- enum machine_mode mode, cmp_mode;
+ machine_mode orig_mode = GET_MODE (x);
+ machine_mode mode, cmp_mode;
rtx true_rtx, false_rtx;
rtx value, target, equiv;
rtx_insn *insns;
if (code_to_optab (swapped)
&& (libfunc = optab_libfunc (code_to_optab (swapped), mode)))
{
- rtx tmp;
- tmp = x; x = y; y = tmp;
+ std::swap (x, y);
comparison = swapped;
break;
}
/* Generate code to indirectly jump to a location given in the rtx LOC. */
void
-emit_indirect_jump (rtx loc)
+emit_indirect_jump (rtx loc ATTRIBUTE_UNUSED)
{
+#ifndef HAVE_indirect_jump
+ sorry ("indirect jumps are not available on this target");
+#else
struct expand_operand ops[1];
-
create_address_operand (&ops[0], loc);
expand_jump_insn (CODE_FOR_indirect_jump, 1, ops);
emit_barrier ();
+#endif
}
\f
-#ifdef HAVE_conditional_move
/* Emit a conditional move instruction if the machine supports one for that
condition and machine mode.
rtx
emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
- enum machine_mode cmode, rtx op2, rtx op3,
- enum machine_mode mode, int unsignedp)
+ machine_mode cmode, rtx op2, rtx op3,
+ machine_mode mode, int unsignedp)
{
- rtx tem, comparison;
+ rtx comparison;
rtx_insn *last;
enum insn_code icode;
enum rtx_code reversed;
if (swap_commutative_operands_p (op0, op1))
{
- tem = op0;
- op0 = op1;
- op1 = tem;
+ std::swap (op0, op1);
code = swap_condition (code);
}
&& ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
!= UNKNOWN))
{
- tem = op2;
- op2 = op3;
- op3 = tem;
+ std::swap (op2, op3);
code = reversed;
}
comparisons, and vice versa. How do we handle them? */
int
-can_conditionally_move_p (enum machine_mode mode)
+can_conditionally_move_p (machine_mode mode)
{
if (direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing)
return 1;
return 0;
}
-#endif /* HAVE_conditional_move */
-
/* Emit a conditional addition instruction if the machine supports one for that
condition and machine mode.
rtx
emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
- enum machine_mode cmode, rtx op2, rtx op3,
- enum machine_mode mode, int unsignedp)
+ machine_mode cmode, rtx op2, rtx op3,
+ machine_mode mode, int unsignedp)
{
- rtx tem, comparison;
+ rtx comparison;
rtx_insn *last;
enum insn_code icode;
if (swap_commutative_operands_p (op0, op1))
{
- tem = op0;
- op0 = op1;
- op1 = tem;
+ std::swap (op0, op1);
code = swap_condition (code);
}
/* Generate and return an insn body to add Y to X. */
-rtx
+rtx_insn *
gen_add2_insn (rtx x, rtx y)
{
enum insn_code icode = optab_handler (add_optab, GET_MODE (x));
/* Generate and return an insn body to add r1 and c,
storing the result in r0. */
-rtx
+rtx_insn *
gen_add3_insn (rtx r0, rtx r1, rtx c)
{
enum insn_code icode = optab_handler (add_optab, GET_MODE (r0));
|| !insn_operand_matches (icode, 0, r0)
|| !insn_operand_matches (icode, 1, r1)
|| !insn_operand_matches (icode, 2, c))
- return NULL_RTX;
+ return NULL;
return GEN_FCN (icode) (r0, r1, c);
}
/* Generate and return an insn body to add Y to X. */
-rtx
+rtx_insn *
gen_addptr3_insn (rtx x, rtx y, rtx z)
{
enum insn_code icode = optab_handler (addptr3_optab, GET_MODE (x));
/* Generate and return an insn body to subtract Y from X. */
-rtx
+rtx_insn *
gen_sub2_insn (rtx x, rtx y)
{
enum insn_code icode = optab_handler (sub_optab, GET_MODE (x));
/* Generate and return an insn body to subtract r1 and c,
storing the result in r0. */
-rtx
+rtx_insn *
gen_sub3_insn (rtx r0, rtx r1, rtx c)
{
enum insn_code icode = optab_handler (sub_optab, GET_MODE (r0));
|| !insn_operand_matches (icode, 0, r0)
|| !insn_operand_matches (icode, 1, r1)
|| !insn_operand_matches (icode, 2, c))
- return NULL_RTX;
+ return NULL;
return GEN_FCN (icode) (r0, r1, c);
}
return 1;
}
-
-/* Generate the body of an instruction to copy Y into X.
- It may be a list of insns, if one insn isn't enough. */
-
-rtx
-gen_move_insn (rtx x, rtx y)
-{
- rtx_insn *seq;
-
- start_sequence ();
- emit_move_insn_1 (x, y);
- seq = get_insns ();
- end_sequence ();
- return seq;
-}
\f
/* Return the insn code used to extend FROM_MODE to TO_MODE.
UNSIGNEDP specifies zero-extension instead of sign-extension. If
no such operation exists, CODE_FOR_nothing will be returned. */
enum insn_code
-can_extend_p (enum machine_mode to_mode, enum machine_mode from_mode,
+can_extend_p (machine_mode to_mode, machine_mode from_mode,
int unsignedp)
{
convert_optab tab;
/* Generate the body of an insn to extend Y (with mode MFROM)
into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */
-rtx
-gen_extend_insn (rtx x, rtx y, enum machine_mode mto,
- enum machine_mode mfrom, int unsignedp)
+rtx_insn *
+gen_extend_insn (rtx x, rtx y, machine_mode mto,
+ machine_mode mfrom, int unsignedp)
{
enum insn_code icode = can_extend_p (mto, mfrom, unsignedp);
return GEN_FCN (icode) (x, y);
an explicit FTRUNC insn before the fix insn; otherwise 0. */
static enum insn_code
-can_fix_p (enum machine_mode fixmode, enum machine_mode fltmode,
+can_fix_p (machine_mode fixmode, machine_mode fltmode,
int unsignedp, int *truncp_ptr)
{
convert_optab tab;
}
enum insn_code
-can_float_p (enum machine_mode fltmode, enum machine_mode fixmode,
+can_float_p (machine_mode fltmode, machine_mode fixmode,
int unsignedp)
{
convert_optab tab;
tree vectype_out, tree vectype_in,
tree *decl, enum tree_code *code1)
{
- enum machine_mode m1,m2;
+ machine_mode m1,m2;
int truncp;
m1 = TYPE_MODE (vectype_out);
{
enum insn_code icode;
rtx target = to;
- enum machine_mode fmode, imode;
+ machine_mode fmode, imode;
bool can_do_signed = false;
/* Crash now, because we won't be able to decide which mode to use. */
rtx value;
convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
- if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
+ if (GET_MODE_PRECISION (GET_MODE (from)) < GET_MODE_PRECISION (SImode))
from = convert_to_mode (SImode, from, unsignedp);
libfunc = convert_optab_libfunc (tab, GET_MODE (to), GET_MODE (from));
{
enum insn_code icode;
rtx target = to;
- enum machine_mode fmode, imode;
+ machine_mode fmode, imode;
int must_trunc = 0;
/* We first try to find a pair of modes, one real and one integer, at
that the mode of TO is at least as wide as SImode, since those are the
only library calls we know about. */
- if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
+ if (GET_MODE_PRECISION (GET_MODE (to)) < GET_MODE_PRECISION (SImode))
{
target = gen_reg_rtx (SImode);
void
expand_fixed_convert (rtx to, rtx from, int uintp, int satp)
{
- enum machine_mode to_mode = GET_MODE (to);
- enum machine_mode from_mode = GET_MODE (from);
+ machine_mode to_mode = GET_MODE (to);
+ machine_mode from_mode = GET_MODE (from);
convert_optab tab;
enum rtx_code this_code;
enum insn_code code;
{
enum insn_code icode;
rtx target = to;
- enum machine_mode fmode, imode;
+ machine_mode fmode, imode;
/* We first try to find a pair of modes, one real and one integer, at
least as wide as FROM and TO, respectively, in which we can open-code
/* Report whether we have an instruction to perform the operation
specified by CODE on operands of mode MODE. */
int
-have_insn_for (enum rtx_code code, enum machine_mode mode)
+have_insn_for (enum rtx_code code, machine_mode mode)
{
return (code_to_optab (code)
&& (optab_handler (code_to_optab (code), mode)
static void
gen_libfunc (optab optable, const char *opname, int suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
unsigned opname_len = strlen (opname);
const char *mname = GET_MODE_NAME (mode);
void
gen_int_libfunc (optab optable, const char *opname, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
int maxsize = 2 * BITS_PER_WORD;
int minsize = BITS_PER_WORD;
void
gen_fp_libfunc (optab optable, const char *opname, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
char *dec_opname;
void
gen_fixed_libfunc (optab optable, const char *opname, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (!ALL_FIXED_POINT_MODE_P (mode))
return;
void
gen_signed_fixed_libfunc (optab optable, const char *opname, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (!SIGNED_FIXED_POINT_MODE_P (mode))
return;
void
gen_unsigned_fixed_libfunc (optab optable, const char *opname, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (!UNSIGNED_FIXED_POINT_MODE_P (mode))
return;
void
gen_int_fp_libfunc (optab optable, const char *name, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
void
gen_intv_fp_libfunc (optab optable, const char *name, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
void
gen_int_fp_fixed_libfunc (optab optable, const char *name, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
void
gen_int_fp_signed_fixed_libfunc (optab optable, const char *name, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
void
gen_int_fixed_libfunc (optab optable, const char *name, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
void
gen_int_signed_fixed_libfunc (optab optable, const char *name, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
void
gen_int_unsigned_fixed_libfunc (optab optable, const char *name, char suffix,
- enum machine_mode mode)
+ machine_mode mode)
{
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
void
gen_interclass_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
size_t opname_len = strlen (opname);
size_t mname_len = 0;
void
gen_int_to_fp_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (GET_MODE_CLASS (fmode) != MODE_INT)
return;
void
gen_ufloat_conv_libfunc (convert_optab tab,
const char *opname ATTRIBUTE_UNUSED,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (DECIMAL_FLOAT_MODE_P (tmode))
gen_int_to_fp_conv_libfunc (tab, "floatuns", tmode, fmode);
void
gen_int_to_fp_nondecimal_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (GET_MODE_CLASS (fmode) != MODE_INT)
return;
void
gen_fp_to_int_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (GET_MODE_CLASS (fmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (fmode))
return;
void
gen_intraclass_conv_libfunc (convert_optab tab, const char *opname,
- enum machine_mode tmode, enum machine_mode fmode)
+ machine_mode tmode, machine_mode fmode)
{
size_t opname_len = strlen (opname);
size_t mname_len = 0;
void
gen_trunc_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
return;
void
gen_extend_conv_libfunc (convert_optab tab,
const char *opname ATTRIBUTE_UNUSED,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
return;
void
gen_fract_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (tmode == fmode)
return;
void
gen_fractuns_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (tmode == fmode)
return;
void
gen_satfract_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (tmode == fmode)
return;
void
gen_satfractuns_conv_libfunc (convert_optab tab,
const char *opname,
- enum machine_mode tmode,
- enum machine_mode fmode)
+ machine_mode tmode,
+ machine_mode fmode)
{
if (tmode == fmode)
return;
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
}
-/* A table of previously-created libfuncs, hashed by name. */
-static GTY ((param_is (union tree_node))) htab_t libfunc_decls;
-
/* Hashtable callbacks for libfunc_decls. */
-static hashval_t
-libfunc_decl_hash (const void *entry)
+struct libfunc_decl_hasher : ggc_ptr_hash<tree_node>
{
- return IDENTIFIER_HASH_VALUE (DECL_NAME ((const_tree) entry));
-}
+ static hashval_t
+ hash (tree entry)
+ {
+ return IDENTIFIER_HASH_VALUE (DECL_NAME (entry));
+ }
-static int
-libfunc_decl_eq (const void *entry1, const void *entry2)
-{
- return DECL_NAME ((const_tree) entry1) == (const_tree) entry2;
-}
+ static bool
+ equal (tree decl, tree name)
+ {
+ return DECL_NAME (decl) == name;
+ }
+};
+
+/* A table of previously-created libfuncs, hashed by name. */
+static GTY (()) hash_table<libfunc_decl_hasher> *libfunc_decls;
/* Build a decl for a libfunc named NAME. */
init_one_libfunc (const char *name)
{
tree id, decl;
- void **slot;
hashval_t hash;
if (libfunc_decls == NULL)
- libfunc_decls = htab_create_ggc (37, libfunc_decl_hash,
- libfunc_decl_eq, NULL);
+ libfunc_decls = hash_table<libfunc_decl_hasher>::create_ggc (37);
/* See if we have already created a libfunc decl for this function. */
id = get_identifier (name);
hash = IDENTIFIER_HASH_VALUE (id);
- slot = htab_find_slot_with_hash (libfunc_decls, id, hash, INSERT);
- decl = (tree) *slot;
+ tree *slot = libfunc_decls->find_slot_with_hash (id, hash, INSERT);
+ decl = *slot;
if (decl == NULL)
{
/* Create a new decl, so that it can be passed to
set_user_assembler_libfunc (const char *name, const char *asmspec)
{
tree id, decl;
- void **slot;
hashval_t hash;
id = get_identifier (name);
hash = IDENTIFIER_HASH_VALUE (id);
- slot = htab_find_slot_with_hash (libfunc_decls, id, hash, NO_INSERT);
+ tree *slot = libfunc_decls->find_slot_with_hash (id, hash, NO_INSERT);
gcc_assert (slot);
decl = (tree) *slot;
set_user_assembler_name (decl, asmspec);
/* Call this to reset the function entry for one optab (OPTABLE) in mode
MODE to NAME, which should be either 0 or a string constant. */
void
-set_optab_libfunc (optab op, enum machine_mode mode, const char *name)
+set_optab_libfunc (optab op, machine_mode mode, const char *name)
{
rtx val;
struct libfunc_entry e;
val = init_one_libfunc (name);
else
val = 0;
- slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
+ slot = libfunc_hash->find_slot (&e, INSERT);
if (*slot == NULL)
*slot = ggc_alloc<libfunc_entry> ();
(*slot)->op = op;
(OPTABLE) from mode FMODE to mode TMODE to NAME, which should be
either 0 or a string constant. */
void
-set_conv_libfunc (convert_optab optab, enum machine_mode tmode,
- enum machine_mode fmode, const char *name)
+set_conv_libfunc (convert_optab optab, machine_mode tmode,
+ machine_mode fmode, const char *name)
{
rtx val;
struct libfunc_entry e;
val = init_one_libfunc (name);
else
val = 0;
- slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
+ slot = libfunc_hash->find_slot (&e, INSERT);
if (*slot == NULL)
*slot = ggc_alloc<libfunc_entry> ();
(*slot)->op = optab;
init_optabs (void)
{
if (libfunc_hash)
- htab_empty (libfunc_hash);
+ libfunc_hash->empty ();
else
- libfunc_hash = htab_create_ggc (10, hash_libfunc, eq_libfunc, NULL);
+ libfunc_hash = hash_table<libfunc_hasher>::create_ggc (10);
/* Fill in the optabs with the insns we support. */
init_all_optabs (this_fn_optabs);
static void
init_sync_libfuncs_1 (optab tab, const char *base, int max)
{
- enum machine_mode mode;
+ machine_mode mode;
char buf[64];
size_t len = strlen (base);
int i;
for (i = FIRST_NORM_OPTAB; i <= LAST_NORMLIB_OPTAB; ++i)
for (j = 0; j < NUM_MACHINE_MODES; ++j)
{
- rtx l = optab_libfunc ((optab) i, (enum machine_mode) j);
+ rtx l = optab_libfunc ((optab) i, (machine_mode) j);
if (l)
{
gcc_assert (GET_CODE (l) == SYMBOL_REF);
for (j = 0; j < NUM_MACHINE_MODES; ++j)
for (k = 0; k < NUM_MACHINE_MODES; ++k)
{
- rtx l = convert_optab_libfunc ((optab) i, (enum machine_mode) j,
- (enum machine_mode) k);
+ rtx l = convert_optab_libfunc ((optab) i, (machine_mode) j,
+ (machine_mode) k);
if (l)
{
gcc_assert (GET_CODE (l) == SYMBOL_REF);
/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
CODE. Return 0 on failure. */
-rtx
+rtx_insn *
gen_cond_trap (enum rtx_code code, rtx op1, rtx op2, rtx tcode)
{
- enum machine_mode mode = GET_MODE (op1);
+ machine_mode mode = GET_MODE (op1);
enum insn_code icode;
- rtx insn;
+ rtx_insn *insn;
rtx trap_rtx;
if (mode == VOIDmode)
prepare_cmp_insn (op1, op2, code, NULL_RTX, false, OPTAB_DIRECT,
&trap_rtx, &mode);
if (!trap_rtx)
- insn = NULL_RTX;
+ insn = NULL;
else
insn = GEN_FCN (icode) (trap_rtx, XEXP (trap_rtx, 0), XEXP (trap_rtx, 1),
tcode);
/* Return rtx code for TCODE. Use UNSIGNEDP to select signed
or unsigned operation code. */
-static enum rtx_code
+enum rtx_code
get_rtx_code (enum tree_code tcode, bool unsignedp)
{
enum rtx_code code;
code = LTGT;
break;
+ case BIT_AND_EXPR:
+ code = AND;
+ break;
+
+ case BIT_IOR_EXPR:
+ code = IOR;
+ break;
+
default:
gcc_unreachable ();
}
{
struct expand_operand ops[2];
rtx rtx_op0, rtx_op1;
+ machine_mode m0, m1;
enum rtx_code rcode = get_rtx_code (tcode, unsignedp);
gcc_assert (TREE_CODE_CLASS (tcode) == tcc_comparison);
- /* Expand operands. */
+ /* Expand operands. For vector types with scalar modes, e.g. where int64x1_t
+ has mode DImode, this can produce a constant RTX of mode VOIDmode; in such
+ cases, use the original mode. */
rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)),
EXPAND_STACK_PARM);
+ m0 = GET_MODE (rtx_op0);
+ if (m0 == VOIDmode)
+ m0 = TYPE_MODE (TREE_TYPE (t_op0));
+
rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)),
EXPAND_STACK_PARM);
+ m1 = GET_MODE (rtx_op1);
+ if (m1 == VOIDmode)
+ m1 = TYPE_MODE (TREE_TYPE (t_op1));
- create_input_operand (&ops[0], rtx_op0, GET_MODE (rtx_op0));
- create_input_operand (&ops[1], rtx_op1, GET_MODE (rtx_op1));
+ create_input_operand (&ops[0], rtx_op0, m0);
+ create_input_operand (&ops[1], rtx_op1, m1);
if (!maybe_legitimize_operands (icode, 4, 2, ops))
gcc_unreachable ();
return gen_rtx_fmt_ee (rcode, VOIDmode, ops[0].value, ops[1].value);
}
-/* Return true if VEC_PERM_EXPR can be expanded using SIMD extensions
- of the CPU. SEL may be NULL, which stands for an unknown constant. */
+/* Return true if VEC_PERM_EXPR of arbitrary input vectors can be expanded using
+ SIMD extensions of the CPU. SEL may be NULL, which stands for an unknown
+ constant. Note that additional permutations representing whole-vector shifts
+ may also be handled via the vec_shr optab, but only where the second input
+ vector is entirely constant zeroes; this case is not dealt with here. */
bool
-can_vec_perm_p (enum machine_mode mode, bool variable,
+can_vec_perm_p (machine_mode mode, bool variable,
const unsigned char *sel)
{
- enum machine_mode qimode;
+ machine_mode qimode;
/* If the target doesn't implement a vector mode for the vector type,
then no operations are supported. */
return true;
}
+/* Checks if vec_perm mask SEL is a constant equivalent to a shift of the first
+ vec_perm operand, assuming the second operand is a constant vector of zeroes.
+ Return the shift distance in bits if so, or NULL_RTX if the vec_perm is not a
+ shift. */
+static rtx
+shift_amt_for_vec_perm_mask (rtx sel)
+{
+ unsigned int i, first, nelt = GET_MODE_NUNITS (GET_MODE (sel));
+ unsigned int bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (sel)));
+
+ if (GET_CODE (sel) != CONST_VECTOR)
+ return NULL_RTX;
+
+ first = INTVAL (CONST_VECTOR_ELT (sel, 0));
+ if (first >= 2*nelt)
+ return NULL_RTX;
+ for (i = 1; i < nelt; i++)
+ {
+ int idx = INTVAL (CONST_VECTOR_ELT (sel, i));
+ unsigned int expected = (i + first) & (2 * nelt - 1);
+ /* Indices into the second vector are all equivalent. */
+ if (idx < 0 || (MIN (nelt, (unsigned) idx) != MIN (nelt, expected)))
+ return NULL_RTX;
+ }
+
+ return GEN_INT (first * bitsize);
+}
+
/* A subroutine of expand_vec_perm for expanding one vec_perm insn. */
static rtx
expand_vec_perm_1 (enum insn_code icode, rtx target,
rtx v0, rtx v1, rtx sel)
{
- enum machine_mode tmode = GET_MODE (target);
- enum machine_mode smode = GET_MODE (sel);
+ machine_mode tmode = GET_MODE (target);
+ machine_mode smode = GET_MODE (sel);
struct expand_operand ops[4];
create_output_operand (&ops[0], target, tmode);
else
{
create_input_operand (&ops[1], v0, tmode);
+ /* See if this can be handled with a vec_shr. We only do this if the
+ second vector is all zeroes. */
+ enum insn_code shift_code = optab_handler (vec_shr_optab, GET_MODE (v0));
+ if (v1 == CONST0_RTX (GET_MODE (v1)) && shift_code)
+ if (rtx shift_amt = shift_amt_for_vec_perm_mask (sel))
+ {
+ create_convert_operand_from_type (&ops[2], shift_amt,
+ sizetype_tab[(int) stk_sizetype]);
+ if (maybe_expand_insn (shift_code, 3, ops))
+ return ops[0].value;
+ }
create_input_operand (&ops[2], v1, tmode);
}
and three operands. */
rtx
-expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
+expand_vec_perm (machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
{
enum insn_code icode;
- enum machine_mode qimode;
+ machine_mode qimode;
unsigned int i, w, e, u;
rtx tmp, sel_qi = NULL;
rtvec vec;
if (sel_qi == NULL)
{
/* Multiply each element by its byte size. */
- enum machine_mode selmode = GET_MODE (sel);
+ machine_mode selmode = GET_MODE (sel);
if (u == 2)
sel = expand_simple_binop (selmode, PLUS, sel, sel,
- sel, 0, OPTAB_DIRECT);
+ NULL, 0, OPTAB_DIRECT);
else
sel = expand_simple_binop (selmode, ASHIFT, sel,
GEN_INT (exact_log2 (u)),
- sel, 0, OPTAB_DIRECT);
+ NULL, 0, OPTAB_DIRECT);
gcc_assert (sel != NULL);
/* Broadcast the low byte each element into each of its bytes. */
mode CMODE, unsigned if UNS is true, resulting in a value of mode VMODE. */
static inline enum insn_code
-get_vcond_icode (enum machine_mode vmode, enum machine_mode cmode, bool uns)
+get_vcond_icode (machine_mode vmode, machine_mode cmode, bool uns)
{
enum insn_code icode = CODE_FOR_nothing;
if (uns)
bool
expand_vec_cond_expr_p (tree value_type, tree cmp_op_type)
{
- enum machine_mode value_mode = TYPE_MODE (value_type);
- enum machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
+ machine_mode value_mode = TYPE_MODE (value_type);
+ machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
if (GET_MODE_SIZE (value_mode) != GET_MODE_SIZE (cmp_op_mode)
|| GET_MODE_NUNITS (value_mode) != GET_MODE_NUNITS (cmp_op_mode)
|| get_vcond_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type),
struct expand_operand ops[6];
enum insn_code icode;
rtx comparison, rtx_op1, rtx_op2;
- enum machine_mode mode = TYPE_MODE (vec_cond_type);
- enum machine_mode cmp_op_mode;
+ machine_mode mode = TYPE_MODE (vec_cond_type);
+ machine_mode cmp_op_mode;
bool unsignedp;
tree op0a, op0b;
enum tree_code tcode;
2 for even/odd widening, and 3 for hi/lo widening. */
int
-can_mult_highpart_p (enum machine_mode mode, bool uns_p)
+can_mult_highpart_p (machine_mode mode, bool uns_p)
{
optab op;
unsigned char *sel;
/* Expand a highpart multiply. */
rtx
-expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
+expand_mult_highpart (machine_mode mode, rtx op0, rtx op1,
rtx target, bool uns_p)
{
struct expand_operand eops[3];
enum insn_code icode;
int method, i, nunits;
- enum machine_mode wmode;
+ machine_mode wmode;
rtx m1, m2, perm;
optab tab1, tab2;
rtvec v;
tab1 = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
tab2 = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
if (BYTES_BIG_ENDIAN)
- {
- optab t = tab1;
- tab1 = tab2;
- tab2 = t;
- }
+ std::swap (tab1, tab2);
break;
default:
gcc_unreachable ();
/* Return true if target supports vector masked load/store for mode. */
bool
-can_vec_mask_load_store_p (enum machine_mode mode, bool is_load)
+can_vec_mask_load_store_p (machine_mode mode, bool is_load)
{
optab op = is_load ? maskload_optab : maskstore_optab;
- enum machine_mode vmode;
+ machine_mode vmode;
unsigned int vector_sizes;
/* If mode is vector mode, check it directly. */
/* Return true if there is a compare_and_swap pattern. */
bool
-can_compare_and_swap_p (enum machine_mode mode, bool allow_libcall)
+can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
{
enum insn_code icode;
/* Return true if an atomic exchange can be performed. */
bool
-can_atomic_exchange_p (enum machine_mode mode, bool allow_libcall)
+can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
{
enum insn_code icode;
static bool
expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
rtx_code_label *label;
rtx cmp_reg, success, oldval;
success = NULL_RTX;
oldval = cmp_reg;
if (!expand_atomic_compare_and_swap (&success, &oldval, mem, old_reg,
- new_reg, false, MEMMODEL_SEQ_CST,
+ new_reg, false, MEMMODEL_SYNC_SEQ_CST,
MEMMODEL_RELAXED))
return false;
static rtx
maybe_emit_atomic_exchange (rtx target, rtx mem, rtx val, enum memmodel model)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
enum insn_code icode;
/* If the target supports the exchange directly, great. */
maybe_emit_sync_lock_test_and_set (rtx target, rtx mem, rtx val,
enum memmodel model)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
enum insn_code icode;
rtx_insn *last_insn = get_last_insn ();
exists, and the memory model is stronger than acquire, add a release
barrier before the instruction. */
- if ((model & MEMMODEL_MASK) == MEMMODEL_SEQ_CST
- || (model & MEMMODEL_MASK) == MEMMODEL_RELEASE
- || (model & MEMMODEL_MASK) == MEMMODEL_ACQ_REL)
+ if (is_mm_seq_cst (model) || is_mm_release (model) || is_mm_acq_rel (model))
expand_mem_thread_fence (model);
if (icode != CODE_FOR_nothing)
static rtx
maybe_emit_compare_and_swap_exchange_loop (rtx target, rtx mem, rtx val)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
if (can_compare_and_swap_p (mode, true))
{
static rtx
maybe_emit_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
{
- enum machine_mode pat_bool_mode;
+ machine_mode pat_bool_mode;
struct expand_operand ops[3];
if (!HAVE_atomic_test_and_set)
rtx ret;
/* Try an atomic_exchange first. */
- ret = maybe_emit_atomic_exchange (target, mem, val, MEMMODEL_ACQUIRE);
+ ret = maybe_emit_atomic_exchange (target, mem, val, MEMMODEL_SYNC_ACQUIRE);
if (ret)
return ret;
- ret = maybe_emit_sync_lock_test_and_set (target, mem, val, MEMMODEL_ACQUIRE);
+ ret = maybe_emit_sync_lock_test_and_set (target, mem, val,
+ MEMMODEL_SYNC_ACQUIRE);
if (ret)
return ret;
/* If there are no other options, try atomic_test_and_set if the value
being stored is 1. */
if (val == const1_rtx)
- ret = maybe_emit_atomic_test_and_set (target, mem, MEMMODEL_ACQUIRE);
+ ret = maybe_emit_atomic_test_and_set (target, mem, MEMMODEL_SYNC_ACQUIRE);
return ret;
}
rtx
expand_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
rtx ret, trueval, subtarget;
ret = maybe_emit_atomic_test_and_set (target, mem, model);
bool is_weak, enum memmodel succ_model,
enum memmodel fail_model)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
struct expand_operand ops[8];
enum insn_code icode;
rtx target_oval, target_bool = NULL_RTX;
icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
if (icode != CODE_FOR_nothing)
{
- enum machine_mode bool_mode = insn_data[icode].operand[0].mode;
+ machine_mode bool_mode = insn_data[icode].operand[0].mode;
/* Make sure we always have a place for the bool operand. */
if (ptarget_bool == NULL
/* This routine will either emit the mem_thread_fence pattern or issue a
sync_synchronize to generate a fence for memory model MEMMODEL. */
-#ifndef HAVE_mem_thread_fence
-# define HAVE_mem_thread_fence 0
-# define gen_mem_thread_fence(x) (gcc_unreachable (), NULL_RTX)
-#endif
-#ifndef HAVE_memory_barrier
-# define HAVE_memory_barrier 0
-# define gen_memory_barrier() (gcc_unreachable (), NULL_RTX)
-#endif
-
void
expand_mem_thread_fence (enum memmodel model)
{
if (HAVE_mem_thread_fence)
emit_insn (gen_mem_thread_fence (GEN_INT (model)));
- else if ((model & MEMMODEL_MASK) != MEMMODEL_RELAXED)
+ else if (!is_mm_relaxed (model))
{
if (HAVE_memory_barrier)
emit_insn (gen_memory_barrier ());
/* This routine will either emit the mem_signal_fence pattern or issue a
sync_synchronize to generate a fence for memory model MEMMODEL. */
-#ifndef HAVE_mem_signal_fence
-# define HAVE_mem_signal_fence 0
-# define gen_mem_signal_fence(x) (gcc_unreachable (), NULL_RTX)
-#endif
-
void
expand_mem_signal_fence (enum memmodel model)
{
if (HAVE_mem_signal_fence)
emit_insn (gen_mem_signal_fence (GEN_INT (model)));
- else if ((model & MEMMODEL_MASK) != MEMMODEL_RELAXED)
+ else if (!is_mm_relaxed (model))
{
/* By default targets are coherent between a thread and the signal
handler running on the same thread. Thus this really becomes a
rtx
expand_atomic_load (rtx target, rtx mem, enum memmodel model)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
enum insn_code icode;
/* If the target supports the load directly, great. */
target = gen_reg_rtx (mode);
/* For SEQ_CST, emit a barrier before the load. */
- if ((model & MEMMODEL_MASK) == MEMMODEL_SEQ_CST)
+ if (is_mm_seq_cst (model))
expand_mem_thread_fence (model);
emit_move_insn (target, mem);
rtx
expand_atomic_store (rtx mem, rtx val, enum memmodel model, bool use_release)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
enum insn_code icode;
struct expand_operand ops[3];
if (maybe_expand_insn (icode, 2, ops))
{
/* lock_release is only a release barrier. */
- if ((model & MEMMODEL_MASK) == MEMMODEL_SEQ_CST)
+ if (is_mm_seq_cst (model))
expand_mem_thread_fence (model);
return const0_rtx;
}
emit_move_insn (mem, val);
/* For SEQ_CST, also emit a barrier after the store. */
- if ((model & MEMMODEL_MASK) == MEMMODEL_SEQ_CST)
+ if (is_mm_seq_cst (model))
expand_mem_thread_fence (model);
return const0_rtx;
maybe_emit_op (const struct atomic_op_functions *optab, rtx target, rtx mem,
rtx val, bool use_memmodel, enum memmodel model, bool after)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
struct expand_operand ops[4];
enum insn_code icode;
int op_counter = 0;
enum rtx_code code, enum memmodel model,
bool after)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
struct atomic_op_functions optab;
rtx result;
bool unused_result = (target == const0_rtx);
expand_atomic_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code,
enum memmodel model, bool after)
{
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
rtx result;
bool unused_result = (target == const0_rtx);
bool
valid_multiword_target_p (rtx target)
{
- enum machine_mode mode;
+ machine_mode mode;
int i;
mode = GET_MODE (target);
&& !side_effects_p (addr))
{
rtx_insn *last;
- enum machine_mode mode;
+ machine_mode mode;
last = get_last_insn ();
mode = get_address_mode (mem);
maybe_legitimize_operand (enum insn_code icode, unsigned int opno,
struct expand_operand *op)
{
- enum machine_mode mode, imode;
+ machine_mode mode, imode;
bool old_volatile_ok, result;
mode = op->mode;
and emit any necessary set-up code. Return null and emit no
code on failure. */
-rtx
+rtx_insn *
maybe_gen_insn (enum insn_code icode, unsigned int nops,
struct expand_operand *ops)
{
gcc_assert (nops == (unsigned int) insn_data[(int) icode].n_generator_args);
if (!maybe_legitimize_operands (icode, 0, nops, ops))
- return NULL_RTX;
+ return NULL;
switch (nops)
{
maybe_expand_insn (enum insn_code icode, unsigned int nops,
struct expand_operand *ops)
{
- rtx pat = maybe_gen_insn (icode, nops, ops);
+ rtx_insn *pat = maybe_gen_insn (icode, nops, ops);
if (pat)
{
emit_insn (pat);
maybe_expand_jump_insn (enum insn_code icode, unsigned int nops,
struct expand_operand *ops)
{
- rtx pat = maybe_gen_insn (icode, nops, ops);
+ rtx_insn *pat = maybe_gen_insn (icode, nops, ops);
if (pat)
{
emit_jump_insn (pat);
static bool
get_traditional_extraction_insn (extraction_insn *insn,
enum extraction_type type,
- enum machine_mode mode,
+ machine_mode mode,
enum insn_code icode,
int struct_op, int field_op)
{
const struct insn_data_d *data = &insn_data[icode];
- enum machine_mode struct_mode = data->operand[struct_op].mode;
+ machine_mode struct_mode = data->operand[struct_op].mode;
if (struct_mode == VOIDmode)
struct_mode = word_mode;
if (mode != struct_mode)
return false;
- enum machine_mode field_mode = data->operand[field_op].mode;
+ machine_mode field_mode = data->operand[field_op].mode;
if (field_mode == VOIDmode)
field_mode = word_mode;
- enum machine_mode pos_mode = data->operand[struct_op + 2].mode;
+ machine_mode pos_mode = data->operand[struct_op + 2].mode;
if (pos_mode == VOIDmode)
pos_mode = word_mode;
static bool
get_optab_extraction_insn (struct extraction_insn *insn,
enum extraction_type type,
- enum machine_mode mode, direct_optab reg_optab,
+ machine_mode mode, direct_optab reg_optab,
direct_optab misalign_optab, int pos_op)
{
direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
get_extraction_insn (extraction_insn *insn,
enum extraction_pattern pattern,
enum extraction_type type,
- enum machine_mode mode)
+ machine_mode mode)
{
switch (pattern)
{
enum extraction_pattern pattern,
enum extraction_type type,
unsigned HOST_WIDE_INT struct_bits,
- enum machine_mode field_mode)
+ machine_mode field_mode)
{
- enum machine_mode mode = smallest_mode_for_size (struct_bits, MODE_INT);
+ machine_mode mode = smallest_mode_for_size (struct_bits, MODE_INT);
while (mode != VOIDmode)
{
if (get_extraction_insn (insn, pattern, type, mode))
get_best_reg_extraction_insn (extraction_insn *insn,
enum extraction_pattern pattern,
unsigned HOST_WIDE_INT struct_bits,
- enum machine_mode field_mode)
+ machine_mode field_mode)
{
return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
field_mode);
get_best_mem_extraction_insn (extraction_insn *insn,
enum extraction_pattern pattern,
HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum,
- enum machine_mode field_mode)
+ machine_mode field_mode)
{
unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
+ bitsize
struct_bits, field_mode);
}
+/* Determine whether "1 << x" is relatively cheap in word_mode. */
+
+bool
+lshift_cheap_p (bool speed_p)
+{
+ /* FIXME: This should be made target dependent via this "this_target"
+ mechanism, similar to e.g. can_copy_init_p in gcse.c. */
+ static bool init[2] = { false, false };
+ static bool cheap[2] = { true, true };
+
+ /* If the targer has no lshift in word_mode, the operation will most
+ probably not be cheap. ??? Does GCC even work for such targets? */
+ if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
+ return false;
+
+ if (!init[speed_p])
+ {
+ rtx reg = gen_raw_REG (word_mode, 10000);
+ int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
+ speed_p);
+ cheap[speed_p] = cost < COSTS_N_INSNS (3);
+ init[speed_p] = true;
+ }
+
+ return cheap[speed_p];
+}
+
#include "gt-optabs.h"