/* 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);
-static void emit_libcall_block_1 (rtx, rtx, rtx, rtx, bool);
+ 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. */
void debug_optab_libfuncs (void);
\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;
}
try again, ensuring that TARGET is not one of the operands. */
static int
-add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
+add_equal_note (rtx_insn *insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
{
- rtx last_insn, set;
+ rtx_insn *last_insn;
+ rtx set;
rtx note;
gcc_assert (insns && INSN_P (insns) && NEXT_INSN (insns));
return 0;
}
- set = single_set (last_insn);
+ set = set_for_reg_notes (last_insn);
if (set == NULL_RTX)
return 1;
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;
return result;
}
\f
+/* Like optab_handler, but for widening_operations that have a
+ TO_MODE and a FROM_MODE. */
+
+enum insn_code
+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)
+ {
+ /* ??? Why does find_widening_optab_handler_and_mode attempt to
+ widen things that can't be widened? E.g. add_optab... */
+ if (op > LAST_CONV_OPTAB)
+ return CODE_FOR_nothing;
+ scode |= from_mode << 8;
+ }
+ return raw_optab_handler (scode);
+}
+
/* Find a widening optab even if it doesn't widen as much as we want.
E.g. if from_mode is HImode, and to_mode is DImode, and there is no
direct HI->SI insn, then return SI->DI, if that exists.
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;
a promoted object differs from our extension. */
if (! no_extend
|| (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)
- && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp))
+ && SUBREG_CHECK_PROMOTED_SIGN (op, unsignedp)))
return convert_modes (mode, oldmode, op, unsignedp);
/* If MODE is no wider than a single word, we return a lowpart or paradoxical
case DOT_PROD_EXPR:
return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab;
+ case SAD_EXPR:
+ return TYPE_UNSIGNED (type) ? usad_optab : ssad_optab;
+
case WIDEN_MULT_PLUS_EXPR:
return (TYPE_UNSIGNED (type)
? (TYPE_SATURATING (type)
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 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 last)
+ 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. */
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 (pat) != NULL_RTX
- && ! add_equal_note (pat, ops[0].value, optab_to_code (binoptab),
+ && ! add_equal_note (pat, ops[0].value,
+ optab_to_code (binoptab),
ops[1].value, ops[2].value))
{
delete_insns_since (last);
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 entry_last = get_last_insn ();
- rtx last;
+ rtx_insn *entry_last = get_last_insn ();
+ rtx_insn *last;
mclass = GET_MODE_CLASS (mode);
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 (binoptab, word_mode) != CODE_FOR_nothing)
{
int i;
- rtx insns;
+ rtx_insn *insns;
/* If TARGET is the same as one of the operands, the REG_EQUAL note
won't be accurate, so use a new target. */
&& 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);
|| (shift_mask == BITS_PER_WORD - 1
&& double_shift_mask == BITS_PER_WORD * 2 - 1))
{
- rtx insns;
+ rtx_insn *insns;
rtx into_target, outof_target;
rtx into_input, outof_input;
int left_shift, outof_word;
&& optab_handler (ashl_optab, word_mode) != CODE_FOR_nothing
&& optab_handler (lshr_optab, word_mode) != CODE_FOR_nothing)
{
- rtx insns;
+ rtx_insn *insns;
rtx into_target, outof_target;
rtx into_input, outof_input;
rtx inter;
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),
if (libfunc
&& (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
{
- rtx insns;
+ 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;
- rtx entry_last = get_last_insn ();
- rtx last;
+ machine_mode wider_mode;
+ rtx_insn *entry_last = get_last_insn ();
+ rtx_insn *last;
mclass = GET_MODE_CLASS (mode);
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;
- rtx entry_last = get_last_insn ();
- rtx last;
+ machine_mode wider_mode;
+ rtx_insn *entry_last = get_last_insn ();
+ rtx_insn *last;
mclass = GET_MODE_CLASS (mode);
{
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 insns;
+ rtx_insn *insns;
rtx libfunc;
/* Exactly one of TARG0 or TARG1 should be non-NULL. */
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))
{
if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
{
- rtx xop0, temp, last;
+ rtx xop0, temp;
+ rtx_insn *last;
last = get_last_insn ();
/* 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);
rtx sublo = gen_lowpart (word_mode, xop0);
- rtx hi0_label = gen_label_rtx ();
- rtx after_label = gen_label_rtx ();
- rtx seq, temp, result;
+ rtx_code_label *hi0_label = gen_label_rtx ();
+ rtx_code_label *after_label = gen_label_rtx ();
+ rtx_insn *seq;
+ rtx temp, result;
/* If we were not given a target, use a word_mode register, not a
'mode' register. The result will fit, and nobody is expecting
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;
- rtx x, last;
+ machine_mode wider_mode;
+ rtx x;
+ rtx_insn *last;
if (!CLASS_HAS_WIDER_MODES_P (mclass))
return NULL_RTX;
/* 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))
{
if (optab_handler (popcount_optab, wider_mode) != CODE_FOR_nothing)
{
- rtx xop0, temp, last;
+ rtx xop0, temp;
+ rtx_insn *last;
last = get_last_insn ();
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 seq, temp;
+ rtx_insn *seq;
+ rtx temp;
if (optab_handler (clz_optab, mode) == CODE_FOR_nothing)
return 0;
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;
- rtx temp, seq;
+ rtx temp;
+ rtx_insn *seq;
if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing)
{
the operation sets condition codes that can be recycled for this.
(This is true on i386, for instance.) */
- rtx nonzero_label = gen_label_rtx ();
+ rtx_code_label *nonzero_label = gen_label_rtx ();
emit_cmp_and_jump_insns (op0, CONST0_RTX (mode), NE, 0,
mode, true, nonzero_label);
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;
- rtx temp, insns;
+ machine_mode imode;
+ rtx temp;
+ rtx_insn *insns;
/* The format has to have a simple sign bit. */
fmt = REAL_MODE_FORMAT (mode);
/* 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 last = get_last_insn ();
- rtx pat;
+ rtx_insn *last = get_last_insn ();
+ rtx_insn *pat;
create_output_operand (&ops[0], target, mode);
create_convert_operand_from (&ops[1], op0, mode, unsignedp);
if (pat)
{
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
- && ! add_equal_note (pat, ops[0].value, optab_to_code (unoptab),
+ && ! add_equal_note (pat, ops[0].value,
+ optab_to_code (unoptab),
ops[1].value, NULL_RTX))
{
delete_insns_since (last);
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;
be always more efficient than the other fallback methods. */
if (mode == HImode)
{
- rtx last, temp1, temp2;
+ rtx_insn *last;
+ rtx temp1, temp2;
if (optab_handler (rotl_optab, mode) != CODE_FOR_nothing)
{
if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
{
rtx xop0 = op0;
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
/* For certain operations, we need not actually extend
the narrow operand, as long as we will truncate the
&& optab_handler (unoptab, word_mode) != CODE_FOR_nothing)
{
int i;
- rtx insns;
+ rtx_insn *insns;
if (target == 0 || target == op0 || !valid_multiword_target_p (target))
target = gen_reg_rtx (mode);
libfunc = optab_libfunc (unoptab, mode);
if (libfunc)
{
- rtx insns;
+ 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. */
|| optab_libfunc (unoptab, wider_mode))
{
rtx xop0 = op0;
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
/* For certain operations, we need not actually extend
the narrow operand, as long as we will truncate the
*/
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;
if (optab_handler (smax_optab, mode) != CODE_FOR_nothing
&& !HONOR_SIGNED_ZEROS (mode))
{
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
temp = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
op0, NULL_RTX, 0);
}
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, op1;
+ rtx temp;
+ rtx_code_label *op1;
if (GET_MODE_CLASS (mode) != MODE_INT
|| ! flag_trapv)
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;
/* If we have a MAX insn, we can do this as MAX (x, ~x). */
if (optab_handler (smax_optab, mode) != CODE_FOR_nothing)
{
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
temp = expand_unop (mode, one_cmpl_optab, op0, NULL_RTX, 0);
if (temp != 0)
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, label;
+ rtx sign;
+ rtx_code_label *label;
if (target == op1)
target = NULL_RTX;
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, insns;
+ rtx temp;
+ rtx_insn *insns;
if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
{
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 (pat) != NULL_RTX && code != UNKNOWN)
+ if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
+ && code != UNKNOWN)
add_equal_note (pat, ops[0].value, code, ops[1].value, NULL_RTX);
emit_insn (pat);
\f
struct no_conflict_data
{
- rtx target, first, insn;
+ rtx target;
+ rtx_insn *first, *insn;
bool must_stay;
};
note with an operand of EQUIV. */
static void
-emit_libcall_block_1 (rtx insns, rtx target, rtx result, rtx equiv,
+emit_libcall_block_1 (rtx_insn *insns, rtx target, rtx result, rtx equiv,
bool equiv_may_trap)
{
rtx final_dest = target;
- rtx next, last, insn;
+ rtx_insn *next, *last, *insn;
/* If this is a reg with REG_USERVAR_P set, then it could possibly turn
into a MEM later. Protect the libcall block from this change. */
if (! data.must_stay)
{
if (PREV_INSN (insn))
- NEXT_INSN (PREV_INSN (insn)) = next;
+ SET_NEXT_INSN (PREV_INSN (insn)) = next;
else
insns = next;
if (next)
- PREV_INSN (next) = PREV_INSN (insn);
+ SET_PREV_INSN (next) = PREV_INSN (insn);
add_insn (insn);
}
void
emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
{
- emit_libcall_block_1 (insns, target, result, equiv, false);
+ emit_libcall_block_1 (safe_as_a <rtx_insn *> (insns),
+ target, result, equiv, false);
}
\f
/* Nonzero if we can perform a comparison of mode MODE straightforwardly.
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 (icode != CODE_FOR_nothing
&& insn_operand_matches (icode, 0, test))
{
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
rtx op0 = prepare_operand (icode, x, 1, mode, cmp_mode, unsignedp);
rtx op1 = prepare_operand (icode, y, 2, mode, cmp_mode, unsignedp);
if (op0 && op1
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;
+ rtx_insn *insn;
mclass = GET_MODE_CLASS (mode);
optab_mode = (mclass == MODE_CC) ? CCmode : mode;
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, insns, equiv;
+ rtx value, target, equiv;
+ rtx_insn *insns;
rtx libfunc = 0;
bool reversed_p = false;
cmp_mode = targetm.libgcc_cmp_return_mode ();
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, last;
+ 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, last;
+ rtx comparison;
+ rtx_insn *last;
enum insn_code icode;
/* If one operand is constant, make it the second one. Only do this
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 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. */
then unconditionally adjust the result. */
if (unsignedp && can_do_signed)
{
- rtx label = gen_label_rtx ();
+ rtx_code_label *label = gen_label_rtx ();
rtx temp;
REAL_VALUE_TYPE offset;
< GET_MODE_PRECISION (GET_MODE (from)))
{
rtx temp1;
- rtx neglabel = gen_label_rtx ();
+ rtx_code_label *neglabel = gen_label_rtx ();
/* Don't use TARGET if it isn't a register, is a hard register,
or is the wrong mode. */
/* No hardware instruction available; call a library routine. */
{
rtx libfunc;
- rtx insns;
+ rtx_insn *insns;
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
if (icode != CODE_FOR_nothing)
{
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
if (fmode != GET_MODE (from))
from = convert_to_mode (fmode, from, 0);
{
int bitsize;
REAL_VALUE_TYPE offset;
- rtx limit, lab1, lab2, insn;
+ rtx limit;
+ rtx_code_label *lab1, *lab2;
+ rtx_insn *insn;
bitsize = GET_MODE_PRECISION (GET_MODE (to));
real_2expN (&offset, bitsize - 1, fmode);
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);
}
else
{
- rtx insns;
+ rtx_insn *insns;
rtx value;
rtx libfunc;
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;
- rtx insns, value;
+ rtx_insn *insns;
+ rtx value;
rtx libfunc;
if (to_mode == from_mode)
{
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
icode = convert_optab_handler (tab, imode, fmode);
if (icode != CODE_FOR_nothing)
{
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
if (fmode != GET_MODE (from))
from = convert_to_mode (fmode, from, 0);
/* 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;
if (GET_MODE_CLASS (mode) != MODE_INT)
return;
if (maxsize < LONG_LONG_TYPE_SIZE)
maxsize = LONG_LONG_TYPE_SIZE;
- if (GET_MODE_CLASS (mode) != MODE_INT
- || GET_MODE_BITSIZE (mode) < BITS_PER_WORD
+ if (minsize > INT_TYPE_SIZE
+ && (trapv_binoptab_p (optable)
+ || trapv_unoptab_p (optable)))
+ minsize = INT_TYPE_SIZE;
+ if (GET_MODE_BITSIZE (mode) < minsize
|| GET_MODE_BITSIZE (mode) > maxsize)
return;
gen_libfunc (optable, opname, suffix, mode);
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);
- rtx label, cmp_reg, success, oldval;
+ machine_mode mode = GET_MODE (mem);
+ rtx_code_label *label;
+ rtx cmp_reg, success, oldval;
/* The loop we want to generate looks like
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 last_insn = get_last_insn ();
+ rtx_insn *last_insn = get_last_insn ();
icode = optab_handler (sync_lock_test_and_set_optab, mode);
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);
perform the operation. */
if (!ret)
{
- emit_move_insn (subtarget, mem);
+ /* If the result is ignored skip the move to target. */
+ if (subtarget != const0_rtx)
+ emit_move_insn (subtarget, mem);
+
emit_move_insn (mem, trueval);
ret = subtarget;
}
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);
/* If nothing else has succeeded, default to a compare and swap loop. */
if (can_compare_and_swap_p (mode, true))
{
- rtx insn;
+ rtx_insn *insn;
rtx t0 = gen_reg_rtx (mode), t1;
start_sequence ();
bool
valid_multiword_target_p (rtx target)
{
- enum machine_mode mode;
+ machine_mode mode;
int i;
mode = GET_MODE (target);
if (!(REG_P (addr) && REGNO (addr) > LAST_VIRTUAL_REGISTER)
&& !side_effects_p (addr))
{
- rtx last;
- enum machine_mode mode;
+ rtx_insn *last;
+ 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;
maybe_legitimize_operands (enum insn_code icode, unsigned int opno,
unsigned int nops, struct expand_operand *ops)
{
- rtx last;
+ rtx_insn *last;
unsigned int i;
last = get_last_insn ();
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"