/* Medium-level subroutines: convert bit-field store and extract
and shifts, multiplies and divides to rtl instructions.
- Copyright (C) 1987-2013 Free Software Foundation, Inc.
+ Copyright (C) 1987-2014 Free Software Foundation, Inc.
This file is part of GCC.
#include "diagnostic-core.h"
#include "rtl.h"
#include "tree.h"
+#include "stor-layout.h"
#include "tm_p.h"
#include "flags.h"
#include "insn-config.h"
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "recog.h"
#include "langhooks.h"
+#include "predict.h"
+#include "basic-block.h"
#include "df.h"
#include "target.h"
#include "expmed.h"
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
rtx);
+static void store_fixed_bit_field_1 (rtx, unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT,
+ rtx);
static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
rtx);
-static rtx extract_fixed_bit_field (enum machine_mode, rtx,
+static rtx extract_fixed_bit_field (machine_mode, rtx,
unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT, rtx, int, bool);
-static rtx mask_rtx (enum machine_mode, int, int, int);
-static rtx lshift_value (enum machine_mode, rtx, int, int);
+ unsigned HOST_WIDE_INT, rtx, int);
+static rtx extract_fixed_bit_field_1 (machine_mode, rtx,
+ unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, rtx, int);
+static rtx lshift_value (machine_mode, unsigned HOST_WIDE_INT, int);
static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, int);
-static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
-static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
-static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
+static void do_cmp_and_jump (rtx, rtx, enum rtx_code, machine_mode, rtx_code_label *);
+static rtx expand_smod_pow2 (machine_mode, rtx, HOST_WIDE_INT);
+static rtx expand_sdiv_pow2 (machine_mode, rtx, HOST_WIDE_INT);
+
+/* Return a constant integer mask value of mode MODE with BITSIZE ones
+ followed by BITPOS zeros, or the complement of that if COMPLEMENT.
+ The mask is truncated if necessary to the width of mode MODE. The
+ mask is zero-extended if BITSIZE+BITPOS is too small for MODE. */
+
+static inline rtx
+mask_rtx (machine_mode mode, int bitpos, int bitsize, bool complement)
+{
+ return immed_wide_int_const
+ (wi::shifted_mask (bitpos, bitsize, complement,
+ GET_MODE_PRECISION (mode)), mode);
+}
/* Test whether a value is zero of a power of two. */
#define EXACT_POWER_OF_2_OR_ZERO_P(x) \
struct init_expmed_rtl
{
- struct rtx_def reg;
- struct rtx_def plus;
- struct rtx_def neg;
- struct rtx_def mult;
- struct rtx_def sdiv;
- struct rtx_def udiv;
- struct rtx_def sdiv_32;
- struct rtx_def smod_32;
- struct rtx_def wide_mult;
- struct rtx_def wide_lshr;
- struct rtx_def wide_trunc;
- struct rtx_def shift;
- struct rtx_def shift_mult;
- struct rtx_def shift_add;
- struct rtx_def shift_sub0;
- struct rtx_def shift_sub1;
- struct rtx_def zext;
- struct rtx_def trunc;
+ rtx reg;
+ rtx plus;
+ rtx neg;
+ rtx mult;
+ rtx sdiv;
+ rtx udiv;
+ rtx sdiv_32;
+ rtx smod_32;
+ rtx wide_mult;
+ rtx wide_lshr;
+ rtx wide_trunc;
+ rtx shift;
+ rtx shift_mult;
+ rtx shift_add;
+ rtx shift_sub0;
+ rtx shift_sub1;
+ rtx zext;
+ rtx trunc;
rtx pow2[MAX_BITS_PER_WORD];
rtx cint[MAX_BITS_PER_WORD];
};
static void
-init_expmed_one_conv (struct init_expmed_rtl *all, enum machine_mode to_mode,
- enum machine_mode from_mode, bool speed)
+init_expmed_one_conv (struct init_expmed_rtl *all, machine_mode to_mode,
+ machine_mode from_mode, bool speed)
{
int to_size, from_size;
rtx which;
- /* We're given no information about the true size of a partial integer,
- only the size of the "full" integer it requires for storage. For
- comparison purposes here, reduce the bit size by one in that case. */
- to_size = (GET_MODE_BITSIZE (to_mode)
- - (GET_MODE_CLASS (to_mode) == MODE_PARTIAL_INT));
- from_size = (GET_MODE_BITSIZE (from_mode)
- - (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT));
+ to_size = GET_MODE_PRECISION (to_mode);
+ from_size = GET_MODE_PRECISION (from_mode);
+
+ /* Most partial integers have a precision less than the "full"
+ integer it requires for storage. In case one doesn't, for
+ comparison purposes here, reduce the bit size by one in that
+ case. */
+ if (GET_MODE_CLASS (to_mode) == MODE_PARTIAL_INT
+ && exact_log2 (to_size) != -1)
+ to_size --;
+ if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT
+ && exact_log2 (from_size) != -1)
+ from_size --;
/* Assume cost of zero-extend and sign-extend is the same. */
- which = (to_size < from_size ? &all->trunc : &all->zext);
+ which = (to_size < from_size ? all->trunc : all->zext);
- PUT_MODE (&all->reg, from_mode);
+ PUT_MODE (all->reg, from_mode);
set_convert_cost (to_mode, from_mode, speed, set_src_cost (which, speed));
}
static void
init_expmed_one_mode (struct init_expmed_rtl *all,
- enum machine_mode mode, int speed)
+ machine_mode mode, int speed)
{
int m, n, mode_bitsize;
- enum machine_mode mode_from;
+ machine_mode mode_from;
mode_bitsize = GET_MODE_UNIT_BITSIZE (mode);
- PUT_MODE (&all->reg, mode);
- PUT_MODE (&all->plus, mode);
- PUT_MODE (&all->neg, mode);
- PUT_MODE (&all->mult, mode);
- PUT_MODE (&all->sdiv, mode);
- PUT_MODE (&all->udiv, mode);
- PUT_MODE (&all->sdiv_32, mode);
- PUT_MODE (&all->smod_32, mode);
- PUT_MODE (&all->wide_trunc, mode);
- PUT_MODE (&all->shift, mode);
- PUT_MODE (&all->shift_mult, mode);
- PUT_MODE (&all->shift_add, mode);
- PUT_MODE (&all->shift_sub0, mode);
- PUT_MODE (&all->shift_sub1, mode);
- PUT_MODE (&all->zext, mode);
- PUT_MODE (&all->trunc, mode);
-
- set_add_cost (speed, mode, set_src_cost (&all->plus, speed));
- set_neg_cost (speed, mode, set_src_cost (&all->neg, speed));
- set_mul_cost (speed, mode, set_src_cost (&all->mult, speed));
- set_sdiv_cost (speed, mode, set_src_cost (&all->sdiv, speed));
- set_udiv_cost (speed, mode, set_src_cost (&all->udiv, speed));
-
- set_sdiv_pow2_cheap (speed, mode, (set_src_cost (&all->sdiv_32, speed)
+ PUT_MODE (all->reg, mode);
+ PUT_MODE (all->plus, mode);
+ PUT_MODE (all->neg, mode);
+ PUT_MODE (all->mult, mode);
+ PUT_MODE (all->sdiv, mode);
+ PUT_MODE (all->udiv, mode);
+ PUT_MODE (all->sdiv_32, mode);
+ PUT_MODE (all->smod_32, mode);
+ PUT_MODE (all->wide_trunc, mode);
+ PUT_MODE (all->shift, mode);
+ PUT_MODE (all->shift_mult, mode);
+ PUT_MODE (all->shift_add, mode);
+ PUT_MODE (all->shift_sub0, mode);
+ PUT_MODE (all->shift_sub1, mode);
+ PUT_MODE (all->zext, mode);
+ PUT_MODE (all->trunc, mode);
+
+ set_add_cost (speed, mode, set_src_cost (all->plus, speed));
+ set_neg_cost (speed, mode, set_src_cost (all->neg, speed));
+ set_mul_cost (speed, mode, set_src_cost (all->mult, speed));
+ set_sdiv_cost (speed, mode, set_src_cost (all->sdiv, speed));
+ set_udiv_cost (speed, mode, set_src_cost (all->udiv, speed));
+
+ set_sdiv_pow2_cheap (speed, mode, (set_src_cost (all->sdiv_32, speed)
<= 2 * add_cost (speed, mode)));
- set_smod_pow2_cheap (speed, mode, (set_src_cost (&all->smod_32, speed)
+ set_smod_pow2_cheap (speed, mode, (set_src_cost (all->smod_32, speed)
<= 4 * add_cost (speed, mode)));
set_shift_cost (speed, mode, 0, 0);
n = MIN (MAX_BITS_PER_WORD, mode_bitsize);
for (m = 1; m < n; m++)
{
- XEXP (&all->shift, 1) = all->cint[m];
- XEXP (&all->shift_mult, 1) = all->pow2[m];
+ XEXP (all->shift, 1) = all->cint[m];
+ XEXP (all->shift_mult, 1) = all->pow2[m];
- set_shift_cost (speed, mode, m, set_src_cost (&all->shift, speed));
- set_shiftadd_cost (speed, mode, m, set_src_cost (&all->shift_add, speed));
- set_shiftsub0_cost (speed, mode, m, set_src_cost (&all->shift_sub0, speed));
- set_shiftsub1_cost (speed, mode, m, set_src_cost (&all->shift_sub1, speed));
+ set_shift_cost (speed, mode, m, set_src_cost (all->shift, speed));
+ set_shiftadd_cost (speed, mode, m, set_src_cost (all->shift_add, speed));
+ set_shiftsub0_cost (speed, mode, m, set_src_cost (all->shift_sub0, speed));
+ set_shiftsub1_cost (speed, mode, m, set_src_cost (all->shift_sub1, speed));
}
if (SCALAR_INT_MODE_P (mode))
{
for (mode_from = MIN_MODE_INT; mode_from <= MAX_MODE_INT;
- mode_from = (enum machine_mode)(mode_from + 1))
+ mode_from = (machine_mode)(mode_from + 1))
init_expmed_one_conv (all, mode, mode_from, speed);
}
if (GET_MODE_CLASS (mode) == MODE_INT)
{
- enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
+ machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
if (wider_mode != VOIDmode)
{
- PUT_MODE (&all->zext, wider_mode);
- PUT_MODE (&all->wide_mult, wider_mode);
- PUT_MODE (&all->wide_lshr, wider_mode);
- XEXP (&all->wide_lshr, 1) = GEN_INT (mode_bitsize);
+ PUT_MODE (all->zext, wider_mode);
+ PUT_MODE (all->wide_mult, wider_mode);
+ PUT_MODE (all->wide_lshr, wider_mode);
+ XEXP (all->wide_lshr, 1) = GEN_INT (mode_bitsize);
set_mul_widen_cost (speed, wider_mode,
- set_src_cost (&all->wide_mult, speed));
+ set_src_cost (all->wide_mult, speed));
set_mul_highpart_cost (speed, mode,
- set_src_cost (&all->wide_trunc, speed));
+ set_src_cost (all->wide_trunc, speed));
}
}
}
init_expmed (void)
{
struct init_expmed_rtl all;
- enum machine_mode mode;
+ machine_mode mode = QImode;
int m, speed;
memset (&all, 0, sizeof all);
all.cint[m] = GEN_INT (m);
}
- PUT_CODE (&all.reg, REG);
/* Avoid using hard regs in ways which may be unsupported. */
- SET_REGNO (&all.reg, LAST_VIRTUAL_REGISTER + 1);
-
- PUT_CODE (&all.plus, PLUS);
- XEXP (&all.plus, 0) = &all.reg;
- XEXP (&all.plus, 1) = &all.reg;
-
- PUT_CODE (&all.neg, NEG);
- XEXP (&all.neg, 0) = &all.reg;
-
- PUT_CODE (&all.mult, MULT);
- XEXP (&all.mult, 0) = &all.reg;
- XEXP (&all.mult, 1) = &all.reg;
-
- PUT_CODE (&all.sdiv, DIV);
- XEXP (&all.sdiv, 0) = &all.reg;
- XEXP (&all.sdiv, 1) = &all.reg;
-
- PUT_CODE (&all.udiv, UDIV);
- XEXP (&all.udiv, 0) = &all.reg;
- XEXP (&all.udiv, 1) = &all.reg;
-
- PUT_CODE (&all.sdiv_32, DIV);
- XEXP (&all.sdiv_32, 0) = &all.reg;
- XEXP (&all.sdiv_32, 1) = 32 < MAX_BITS_PER_WORD ? all.cint[32] : GEN_INT (32);
-
- PUT_CODE (&all.smod_32, MOD);
- XEXP (&all.smod_32, 0) = &all.reg;
- XEXP (&all.smod_32, 1) = XEXP (&all.sdiv_32, 1);
-
- PUT_CODE (&all.zext, ZERO_EXTEND);
- XEXP (&all.zext, 0) = &all.reg;
-
- PUT_CODE (&all.wide_mult, MULT);
- XEXP (&all.wide_mult, 0) = &all.zext;
- XEXP (&all.wide_mult, 1) = &all.zext;
-
- PUT_CODE (&all.wide_lshr, LSHIFTRT);
- XEXP (&all.wide_lshr, 0) = &all.wide_mult;
-
- PUT_CODE (&all.wide_trunc, TRUNCATE);
- XEXP (&all.wide_trunc, 0) = &all.wide_lshr;
-
- PUT_CODE (&all.shift, ASHIFT);
- XEXP (&all.shift, 0) = &all.reg;
-
- PUT_CODE (&all.shift_mult, MULT);
- XEXP (&all.shift_mult, 0) = &all.reg;
-
- PUT_CODE (&all.shift_add, PLUS);
- XEXP (&all.shift_add, 0) = &all.shift_mult;
- XEXP (&all.shift_add, 1) = &all.reg;
-
- PUT_CODE (&all.shift_sub0, MINUS);
- XEXP (&all.shift_sub0, 0) = &all.shift_mult;
- XEXP (&all.shift_sub0, 1) = &all.reg;
-
- PUT_CODE (&all.shift_sub1, MINUS);
- XEXP (&all.shift_sub1, 0) = &all.reg;
- XEXP (&all.shift_sub1, 1) = &all.shift_mult;
-
- PUT_CODE (&all.trunc, TRUNCATE);
- XEXP (&all.trunc, 0) = &all.reg;
+ all.reg = gen_rtx_raw_REG (mode, LAST_VIRTUAL_REGISTER + 1);
+ all.plus = gen_rtx_PLUS (mode, all.reg, all.reg);
+ all.neg = gen_rtx_NEG (mode, all.reg);
+ all.mult = gen_rtx_MULT (mode, all.reg, all.reg);
+ all.sdiv = gen_rtx_DIV (mode, all.reg, all.reg);
+ all.udiv = gen_rtx_UDIV (mode, all.reg, all.reg);
+ all.sdiv_32 = gen_rtx_DIV (mode, all.reg, all.pow2[5]);
+ all.smod_32 = gen_rtx_MOD (mode, all.reg, all.pow2[5]);
+ all.zext = gen_rtx_ZERO_EXTEND (mode, all.reg);
+ all.wide_mult = gen_rtx_MULT (mode, all.zext, all.zext);
+ all.wide_lshr = gen_rtx_LSHIFTRT (mode, all.wide_mult, all.reg);
+ all.wide_trunc = gen_rtx_TRUNCATE (mode, all.wide_lshr);
+ all.shift = gen_rtx_ASHIFT (mode, all.reg, all.reg);
+ all.shift_mult = gen_rtx_MULT (mode, all.reg, all.reg);
+ all.shift_add = gen_rtx_PLUS (mode, all.shift_mult, all.reg);
+ all.shift_sub0 = gen_rtx_MINUS (mode, all.shift_mult, all.reg);
+ all.shift_sub1 = gen_rtx_MINUS (mode, all.reg, all.shift_mult);
+ all.trunc = gen_rtx_TRUNCATE (mode, all.reg);
for (speed = 0; speed < 2; speed++)
{
set_zero_cost (speed, set_src_cost (const0_rtx, speed));
for (mode = MIN_MODE_INT; mode <= MAX_MODE_INT;
- mode = (enum machine_mode)(mode + 1))
+ mode = (machine_mode)(mode + 1))
init_expmed_one_mode (&all, mode, speed);
if (MIN_MODE_PARTIAL_INT != VOIDmode)
for (mode = MIN_MODE_PARTIAL_INT; mode <= MAX_MODE_PARTIAL_INT;
- mode = (enum machine_mode)(mode + 1))
+ mode = (machine_mode)(mode + 1))
init_expmed_one_mode (&all, mode, speed);
if (MIN_MODE_VECTOR_INT != VOIDmode)
for (mode = MIN_MODE_VECTOR_INT; mode <= MAX_MODE_VECTOR_INT;
- mode = (enum machine_mode)(mode + 1))
+ mode = (machine_mode)(mode + 1))
init_expmed_one_mode (&all, mode, speed);
}
else
set_alg_hash_used_p (true);
default_rtl_profile ();
+
+ ggc_free (all.trunc);
+ ggc_free (all.shift_sub1);
+ ggc_free (all.shift_sub0);
+ ggc_free (all.shift_add);
+ ggc_free (all.shift_mult);
+ ggc_free (all.shift);
+ ggc_free (all.wide_trunc);
+ ggc_free (all.wide_lshr);
+ ggc_free (all.wide_mult);
+ ggc_free (all.zext);
+ ggc_free (all.smod_32);
+ ggc_free (all.sdiv_32);
+ ggc_free (all.udiv);
+ ggc_free (all.sdiv);
+ ggc_free (all.mult);
+ ggc_free (all.neg);
+ ggc_free (all.plus);
+ ggc_free (all.reg);
}
/* Return an rtx representing minus the value of X.
useful if X is a CONST_INT. */
rtx
-negate_rtx (enum machine_mode mode, rtx x)
+negate_rtx (machine_mode mode, rtx x)
{
rtx result = simplify_unary_operation (NEG, mode, x, mode);
Set *NEW_BITNUM to the bit position of the field within the new memory. */
static rtx
-narrow_bit_field_mem (rtx mem, enum machine_mode mode,
+narrow_bit_field_mem (rtx mem, machine_mode mode,
unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum,
unsigned HOST_WIDE_INT *new_bitnum)
HOST_WIDE_INT bitnum,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
- enum machine_mode fieldmode,
+ machine_mode fieldmode,
unsigned HOST_WIDE_INT *new_bitnum)
{
bit_field_mode_iterator iter (bitsize, bitnum, bitregion_start,
bitregion_end, MEM_ALIGN (op0),
MEM_VOLATILE_P (op0));
- enum machine_mode best_mode;
+ machine_mode best_mode;
if (iter.next_mode (&best_mode))
{
/* We can use a memory in BEST_MODE. See whether this is true for
{
/* Limit the search to the mode required by the corresponding
register insertion or extraction instruction, if any. */
- enum machine_mode limit_mode = word_mode;
+ machine_mode limit_mode = word_mode;
extraction_insn insn;
if (get_best_reg_extraction_insn (&insn, pattern,
GET_MODE_BITSIZE (best_mode),
fieldmode))
limit_mode = insn.field_mode;
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
while (iter.next_mode (&wider_mode)
&& GET_MODE_SIZE (wider_mode) <= GET_MODE_SIZE (limit_mode))
best_mode = wider_mode;
static bool
lowpart_bit_field_p (unsigned HOST_WIDE_INT bitnum,
unsigned HOST_WIDE_INT bitsize,
- enum machine_mode struct_mode)
+ machine_mode struct_mode)
{
if (BYTES_BIG_ENDIAN)
return (bitnum % BITS_PER_UNIT == 0
return bitnum % BITS_PER_WORD == 0;
}
+/* Return true if -fstrict-volatile-bitfields applies to an access of OP0
+ containing BITSIZE bits starting at BITNUM, with field mode FIELDMODE.
+ Return false if the access would touch memory outside the range
+ BITREGION_START to BITREGION_END for conformance to the C++ memory
+ model. */
+
+static bool
+strict_volatile_bitfield_p (rtx op0, unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitnum,
+ machine_mode fieldmode,
+ unsigned HOST_WIDE_INT bitregion_start,
+ unsigned HOST_WIDE_INT bitregion_end)
+{
+ unsigned HOST_WIDE_INT modesize = GET_MODE_BITSIZE (fieldmode);
+
+ /* -fstrict-volatile-bitfields must be enabled and we must have a
+ volatile MEM. */
+ if (!MEM_P (op0)
+ || !MEM_VOLATILE_P (op0)
+ || flag_strict_volatile_bitfields <= 0)
+ return false;
+
+ /* Non-integral modes likely only happen with packed structures.
+ Punt. */
+ if (!SCALAR_INT_MODE_P (fieldmode))
+ return false;
+
+ /* The bit size must not be larger than the field mode, and
+ the field mode must not be larger than a word. */
+ if (bitsize > modesize || modesize > BITS_PER_WORD)
+ return false;
+
+ /* Check for cases of unaligned fields that must be split. */
+ if (bitnum % BITS_PER_UNIT + bitsize > modesize
+ || (STRICT_ALIGNMENT
+ && bitnum % GET_MODE_ALIGNMENT (fieldmode) + bitsize > modesize))
+ return false;
+
+ /* Check for cases where the C++ memory model applies. */
+ if (bitregion_end != 0
+ && (bitnum - bitnum % modesize < bitregion_start
+ || bitnum - bitnum % modesize + modesize - 1 > bitregion_end))
+ return false;
+
+ return true;
+}
+
/* Return true if OP is a memory and if a bitfield of size BITSIZE at
bit number BITNUM can be treated as a simple value of mode MODE. */
static bool
simple_mem_bitfield_p (rtx op0, unsigned HOST_WIDE_INT bitsize,
- unsigned HOST_WIDE_INT bitnum, enum machine_mode mode)
+ unsigned HOST_WIDE_INT bitnum, machine_mode mode)
{
return (MEM_P (op0)
&& bitnum % BITS_PER_UNIT == 0
static bool
store_bit_field_using_insv (const extraction_insn *insv, rtx op0,
unsigned HOST_WIDE_INT bitsize,
- unsigned HOST_WIDE_INT bitnum, rtx value)
+ unsigned HOST_WIDE_INT bitnum,
+ rtx value)
{
struct expand_operand ops[4];
rtx value1;
rtx xop0 = op0;
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
bool copy_back = false;
- enum machine_mode op_mode = insv->field_mode;
+ machine_mode op_mode = insv->field_mode;
unsigned int unit = GET_MODE_BITSIZE (op_mode);
if (bitsize == 0 || bitsize > unit)
return false;
unsigned HOST_WIDE_INT bitnum,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
- enum machine_mode fieldmode,
+ machine_mode fieldmode,
rtx value, bool fallback_p)
{
rtx op0 = str_rtx;
&& !(bitnum % GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
{
struct expand_operand ops[3];
- enum machine_mode outermode = GET_MODE (op0);
- enum machine_mode innermode = GET_MODE_INNER (outermode);
+ machine_mode outermode = GET_MODE (op0);
+ machine_mode innermode = GET_MODE_INNER (outermode);
enum insn_code icode = optab_handler (vec_set_optab, outermode);
int pos = bitnum / GET_MODE_BITSIZE (innermode);
|| (bitsize % BITS_PER_WORD == 0 && bitnum % BITS_PER_WORD == 0)))
{
/* Use the subreg machinery either to narrow OP0 to the required
- words or to cope with mode punning between equal-sized modes. */
- rtx sub = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
- bitnum / BITS_PER_UNIT);
- if (sub)
+ words or to cope with mode punning between equal-sized modes.
+ In the latter case, use subreg on the rhs side, not lhs. */
+ rtx sub;
+
+ if (bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
{
- emit_move_insn (sub, value);
- return true;
+ sub = simplify_gen_subreg (GET_MODE (op0), value, fieldmode, 0);
+ if (sub)
+ {
+ emit_move_insn (op0, sub);
+ return true;
+ }
+ }
+ else
+ {
+ sub = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
+ bitnum / BITS_PER_UNIT);
+ if (sub)
+ {
+ emit_move_insn (sub, value);
+ return true;
+ }
}
}
since that case is valid for any mode. The following cases are only
valid for integral modes. */
{
- enum machine_mode imode = int_mode_for_mode (GET_MODE (op0));
+ machine_mode imode = int_mode_for_mode (GET_MODE (op0));
if (imode != GET_MODE (op0))
{
if (MEM_P (op0))
unsigned int backwards = WORDS_BIG_ENDIAN && fieldmode != BLKmode;
unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
unsigned int i;
- rtx last;
+ rtx_insn *last;
/* This is the mode we must force value to, so that there will be enough
subwords to extract. Note that fieldmode will often (always?) be
cheap register alternative is available. */
if (MEM_P (op0))
{
- /* Do not use unaligned memory insvs for volatile bitfields when
- -fstrict-volatile-bitfields is in effect. */
- if (!(MEM_VOLATILE_P (op0)
- && flag_strict_volatile_bitfields > 0)
- && get_best_mem_extraction_insn (&insv, EP_insv, bitsize, bitnum,
- fieldmode)
+ if (get_best_mem_extraction_insn (&insv, EP_insv, bitsize, bitnum,
+ fieldmode)
&& store_bit_field_using_insv (&insv, op0, bitsize, bitnum, value))
return true;
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
/* Try loading part of OP0 into a register, inserting the bitfield
into that, and then copying the result back to OP0. */
unsigned HOST_WIDE_INT bitnum,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
- enum machine_mode fieldmode,
+ machine_mode fieldmode,
rtx value)
{
+ /* Handle -fstrict-volatile-bitfields in the cases where it applies. */
+ if (strict_volatile_bitfield_p (str_rtx, bitsize, bitnum, fieldmode,
+ bitregion_start, bitregion_end))
+ {
+ /* Storing any naturally aligned field can be done with a simple
+ store. For targets that support fast unaligned memory, any
+ naturally sized, unit aligned field can be done directly. */
+ if (simple_mem_bitfield_p (str_rtx, bitsize, bitnum, fieldmode))
+ {
+ str_rtx = adjust_bitfield_address (str_rtx, fieldmode,
+ bitnum / BITS_PER_UNIT);
+ emit_move_insn (str_rtx, value);
+ }
+ else
+ {
+ str_rtx = narrow_bit_field_mem (str_rtx, fieldmode, bitsize, bitnum,
+ &bitnum);
+ /* Explicitly override the C/C++ memory model; ignore the
+ bit range so that we can do the access in the mode mandated
+ by -fstrict-volatile-bitfields instead. */
+ store_fixed_bit_field_1 (str_rtx, bitsize, bitnum, value);
+ }
+
+ return;
+ }
+
/* Under the C++0x memory model, we must not touch bits outside the
bit region. Adjust the address to start at the beginning of the
bit region. */
if (MEM_P (str_rtx) && bitregion_start > 0)
{
- enum machine_mode bestmode;
+ machine_mode bestmode;
HOST_WIDE_INT offset, size;
gcc_assert ((bitregion_start % BITS_PER_UNIT) == 0);
unsigned HOST_WIDE_INT bitregion_end,
rtx value)
{
- enum machine_mode mode;
- rtx temp;
- int all_zero = 0;
- int all_one = 0;
-
/* There is a case not handled here:
a structure with a known alignment of just a halfword
and a field split across two aligned halfwords within the structure.
if (MEM_P (op0))
{
- unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE;
-
- if (bitregion_end)
- maxbits = bitregion_end - bitregion_start + 1;
-
- /* Get the proper mode to use for this field. We want a mode that
- includes the entire field. If such a mode would be larger than
- a word, we won't be doing the extraction the normal way.
- We don't want a mode bigger than the destination. */
-
- mode = GET_MODE (op0);
+ machine_mode mode = GET_MODE (op0);
if (GET_MODE_BITSIZE (mode) == 0
|| GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode))
mode = word_mode;
-
- if (MEM_VOLATILE_P (op0)
- && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
- && GET_MODE_BITSIZE (GET_MODE (op0)) <= maxbits
- && flag_strict_volatile_bitfields > 0)
- mode = GET_MODE (op0);
- else
- mode = get_best_mode (bitsize, bitnum, bitregion_start, bitregion_end,
- MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
+ mode = get_best_mode (bitsize, bitnum, bitregion_start, bitregion_end,
+ MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
if (mode == VOIDmode)
{
op0 = narrow_bit_field_mem (op0, mode, bitsize, bitnum, &bitnum);
}
+ store_fixed_bit_field_1 (op0, bitsize, bitnum, value);
+}
+
+/* Helper function for store_fixed_bit_field, stores
+ the bit field always using the MODE of OP0. */
+
+static void
+store_fixed_bit_field_1 (rtx op0, unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitnum,
+ rtx value)
+{
+ machine_mode mode;
+ rtx temp;
+ int all_zero = 0;
+ int all_one = 0;
+
mode = GET_MODE (op0);
gcc_assert (SCALAR_INT_MODE_P (mode));
if (CONST_INT_P (value))
{
- HOST_WIDE_INT v = INTVAL (value);
+ unsigned HOST_WIDE_INT v = UINTVAL (value);
if (bitsize < HOST_BITS_PER_WIDE_INT)
- v &= ((HOST_WIDE_INT) 1 << bitsize) - 1;
+ v &= ((unsigned HOST_WIDE_INT) 1 << bitsize) - 1;
if (v == 0)
all_zero = 1;
else if ((bitsize < HOST_BITS_PER_WIDE_INT
- && v == ((HOST_WIDE_INT) 1 << bitsize) - 1)
- || (bitsize == HOST_BITS_PER_WIDE_INT && v == -1))
+ && v == ((unsigned HOST_WIDE_INT) 1 << bitsize) - 1)
+ || (bitsize == HOST_BITS_PER_WIDE_INT
+ && v == (unsigned HOST_WIDE_INT) -1))
all_one = 1;
- value = lshift_value (mode, value, bitnum, bitsize);
+ value = lshift_value (mode, v, bitnum);
}
else
{
else
unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
+ /* If OP0 is a memory with a mode, then UNIT must not be larger than
+ OP0's mode as well. Otherwise, store_fixed_bit_field will call us
+ again, and we will mutually recurse forever. */
+ if (MEM_P (op0) && GET_MODE_BITSIZE (GET_MODE (op0)) > 0)
+ unit = MIN (unit, GET_MODE_BITSIZE (GET_MODE (op0)));
+
/* If VALUE is a constant other than a CONST_INT, get it into a register in
WORD_MODE. If we can do this using gen_lowpart_common, do so. Note
that VALUE might be a floating-point constant. */
endianness compensation) to fetch the piece we want. */
part = extract_fixed_bit_field (word_mode, value, thissize,
total_bits - bitsize + bitsdone,
- NULL_RTX, 1, false);
+ NULL_RTX, 1);
}
}
else
& (((HOST_WIDE_INT) 1 << thissize) - 1));
else
part = extract_fixed_bit_field (word_mode, value, thissize,
- bitsdone, NULL_RTX, 1, false);
+ bitsdone, NULL_RTX, 1);
}
/* If OP0 is a register, then handle OFFSET here.
{
int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD)
+ (offset * unit / BITS_PER_WORD);
- enum machine_mode sub_mode = GET_MODE (SUBREG_REG (op0));
+ machine_mode sub_mode = GET_MODE (SUBREG_REG (op0));
if (sub_mode != BLKmode && GET_MODE_SIZE (sub_mode) < UNITS_PER_WORD)
word = word_offset ? const0_rtx : op0;
else
}
else if (REG_P (op0))
{
- enum machine_mode op0_mode = GET_MODE (op0);
+ machine_mode op0_mode = GET_MODE (op0);
if (op0_mode != BLKmode && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD)
word = offset ? const0_rtx : op0;
else
to extract_bit_field. */
static rtx
-convert_extracted_bit_field (rtx x, enum machine_mode mode,
- enum machine_mode tmode, bool unsignedp)
+convert_extracted_bit_field (rtx x, machine_mode mode,
+ machine_mode tmode, bool unsignedp)
{
if (GET_MODE (x) == tmode || GET_MODE (x) == mode)
return x;
value via a SUBREG. */
if (!SCALAR_INT_MODE_P (tmode))
{
- enum machine_mode smode;
+ machine_mode smode;
smode = mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0);
x = convert_to_mode (smode, x, unsignedp);
unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum,
int unsignedp, rtx target,
- enum machine_mode mode, enum machine_mode tmode)
+ machine_mode mode, machine_mode tmode)
{
struct expand_operand ops[4];
rtx spec_target = target;
rtx spec_target_subreg = 0;
- enum machine_mode ext_mode = extv->field_mode;
+ machine_mode ext_mode = extv->field_mode;
unsigned unit = GET_MODE_BITSIZE (ext_mode);
if (bitsize == 0 || unit < bitsize)
static rtx
extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
- unsigned HOST_WIDE_INT bitnum,
- int unsignedp, bool packedp, rtx target,
- enum machine_mode mode, enum machine_mode tmode,
+ unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
+ machine_mode mode, machine_mode tmode,
bool fallback_p)
{
rtx op0 = str_rtx;
- enum machine_mode int_mode;
- enum machine_mode mode1;
+ machine_mode int_mode;
+ machine_mode mode1;
if (tmode == VOIDmode)
tmode = mode;
&& !MEM_P (op0)
&& GET_MODE_INNER (GET_MODE (op0)) != tmode)
{
- enum machine_mode new_mode;
+ machine_mode new_mode;
if (GET_MODE_CLASS (tmode) == MODE_FLOAT)
new_mode = MIN_MODE_VECTOR_FLOAT;
== bitnum / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
{
struct expand_operand ops[3];
- enum machine_mode outermode = GET_MODE (op0);
- enum machine_mode innermode = GET_MODE_INNER (outermode);
+ machine_mode outermode = GET_MODE (op0);
+ machine_mode innermode = GET_MODE_INNER (outermode);
enum insn_code icode = optab_handler (vec_extract_optab, outermode);
unsigned HOST_WIDE_INT pos = bitnum / GET_MODE_BITSIZE (innermode);
/* Make sure we are playing with integral modes. Pun with subregs
if we aren't. */
{
- enum machine_mode imode = int_mode_for_mode (GET_MODE (op0));
+ machine_mode imode = int_mode_for_mode (GET_MODE (op0));
if (imode != GET_MODE (op0))
{
if (MEM_P (op0))
If that's wrong, the solution is to test for it and set TARGET to 0
if needed. */
- /* If the bitfield is volatile, we need to make sure the access
- remains on a type-aligned boundary. */
- if (GET_CODE (op0) == MEM
- && MEM_VOLATILE_P (op0)
- && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
- && flag_strict_volatile_bitfields > 0)
- goto no_subreg_mode_swap;
-
- /* Only scalar integer modes can be converted via subregs. There is an
- additional problem for FP modes here in that they can have a precision
- which is different from the size. mode_for_size uses precision, but
- we want a mode based on the size, so we must avoid calling it for FP
- modes. */
+ /* Get the mode of the field to use for atomic access or subreg
+ conversion. */
mode1 = mode;
if (SCALAR_INT_MODE_P (tmode))
{
- enum machine_mode try_mode = mode_for_size (bitsize,
+ machine_mode try_mode = mode_for_size (bitsize,
GET_MODE_CLASS (tmode), 0);
if (try_mode != BLKmode)
mode1 = try_mode;
return convert_extracted_bit_field (op0, mode, tmode, unsignedp);
}
- no_subreg_mode_swap:
-
/* Handle fields bigger than a word. */
if (bitsize > BITS_PER_WORD)
This is because the most significant word is the one which may
be less than full. */
+ unsigned int backwards = WORDS_BIG_ENDIAN;
unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
unsigned int i;
- rtx last;
+ rtx_insn *last;
if (target == 0 || !REG_P (target) || !valid_multiword_target_p (target))
target = gen_reg_rtx (mode);
if I is 1, use the next to lowest word; and so on. */
/* Word number in TARGET to use. */
unsigned int wordnum
- = (WORDS_BIG_ENDIAN
+ = (backwards
? GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD - i - 1
: i);
/* Offset from start of field in OP0. */
- unsigned int bit_offset = (WORDS_BIG_ENDIAN
- ? MAX (0, ((int) bitsize - ((int) i + 1)
- * (int) BITS_PER_WORD))
+ unsigned int bit_offset = (backwards
+ ? MAX ((int) bitsize - ((int) i + 1)
+ * BITS_PER_WORD,
+ 0)
: (int) i * BITS_PER_WORD);
rtx target_part = operand_subword (target, wordnum, 1, VOIDmode);
rtx result_part
= extract_bit_field_1 (op0, MIN (BITS_PER_WORD,
bitsize - i * BITS_PER_WORD),
- bitnum + bit_offset, 1, false, target_part,
+ bitnum + bit_offset, 1, target_part,
mode, word_mode, fallback_p);
gcc_assert (target_part);
for (i = nwords; i < total_words; i++)
emit_move_insn
(operand_subword (target,
- WORDS_BIG_ENDIAN ? total_words - i - 1 : i,
+ backwards ? total_words - i - 1 : i,
1, VOIDmode),
const0_rtx);
}
cheap register alternative is available. */
if (MEM_P (op0))
{
- /* Do not use extv/extzv for volatile bitfields when
- -fstrict-volatile-bitfields is in effect. */
- if (!(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0)
- && get_best_mem_extraction_insn (&extv, pattern, bitsize, bitnum,
- tmode))
+ if (get_best_mem_extraction_insn (&extv, pattern, bitsize, bitnum,
+ tmode))
{
rtx result = extract_bit_field_using_extv (&extv, op0, bitsize,
bitnum, unsignedp,
return result;
}
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
/* Try loading part of OP0 into a register and extracting the
bitfield from that. */
{
xop0 = copy_to_reg (xop0);
rtx result = extract_bit_field_1 (xop0, bitsize, bitpos,
- unsignedp, packedp, target,
+ unsignedp, target,
mode, tmode, false);
if (result)
return result;
gcc_assert (int_mode != BLKmode);
target = extract_fixed_bit_field (int_mode, op0, bitsize, bitnum,
- target, unsignedp, packedp);
+ target, unsignedp);
return convert_extracted_bit_field (target, mode, tmode, unsignedp);
}
STR_RTX is the structure containing the byte (a REG or MEM).
UNSIGNEDP is nonzero if this is an unsigned bit field.
- PACKEDP is nonzero if the field has the packed attribute.
MODE is the natural mode of the field value once extracted.
TMODE is the mode the caller would like the value to have;
but the value may be returned with type MODE instead.
rtx
extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
- unsigned HOST_WIDE_INT bitnum, int unsignedp, bool packedp,
- rtx target, enum machine_mode mode, enum machine_mode tmode)
+ unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
+ machine_mode mode, machine_mode tmode)
{
- return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp, packedp,
+ machine_mode mode1;
+
+ /* Handle -fstrict-volatile-bitfields in the cases where it applies. */
+ if (GET_MODE_BITSIZE (GET_MODE (str_rtx)) > 0)
+ mode1 = GET_MODE (str_rtx);
+ else if (target && GET_MODE_BITSIZE (GET_MODE (target)) > 0)
+ mode1 = GET_MODE (target);
+ else
+ mode1 = tmode;
+
+ if (strict_volatile_bitfield_p (str_rtx, bitsize, bitnum, mode1, 0, 0))
+ {
+ rtx result;
+
+ /* Extraction of a full MODE1 value can be done with a load as long as
+ the field is on a byte boundary and is sufficiently aligned. */
+ if (simple_mem_bitfield_p (str_rtx, bitsize, bitnum, mode1))
+ result = adjust_bitfield_address (str_rtx, mode1,
+ bitnum / BITS_PER_UNIT);
+ else
+ {
+ str_rtx = narrow_bit_field_mem (str_rtx, mode1, bitsize, bitnum,
+ &bitnum);
+ result = extract_fixed_bit_field_1 (mode, str_rtx, bitsize, bitnum,
+ target, unsignedp);
+ }
+
+ return convert_extracted_bit_field (result, mode, tmode, unsignedp);
+ }
+
+ return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp,
target, mode, tmode, true);
}
\f
from bit BITNUM of OP0.
UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value).
- PACKEDP is true if the field has the packed attribute.
-
If TARGET is nonzero, attempts to store the value there
and return TARGET, but this is not guaranteed.
If TARGET is not used, create a pseudo-reg of mode TMODE for the value. */
static rtx
-extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
+extract_fixed_bit_field (machine_mode tmode, rtx op0,
unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitnum, rtx target,
- int unsignedp, bool packedp)
+ int unsignedp)
{
- enum machine_mode mode;
-
if (MEM_P (op0))
{
- /* Get the proper mode to use for this field. We want a mode that
- includes the entire field. If such a mode would be larger than
- a word, we won't be doing the extraction the normal way. */
-
- if (MEM_VOLATILE_P (op0)
- && flag_strict_volatile_bitfields > 0)
- {
- if (GET_MODE_BITSIZE (GET_MODE (op0)) > 0)
- mode = GET_MODE (op0);
- else if (target && GET_MODE_BITSIZE (GET_MODE (target)) > 0)
- mode = GET_MODE (target);
- else
- mode = tmode;
- }
- else
- mode = get_best_mode (bitsize, bitnum, 0, 0,
- MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0));
+ machine_mode mode
+ = get_best_mode (bitsize, bitnum, 0, 0, MEM_ALIGN (op0), word_mode,
+ MEM_VOLATILE_P (op0));
if (mode == VOIDmode)
/* The only way this should occur is if the field spans word
boundaries. */
return extract_split_bit_field (op0, bitsize, bitnum, unsignedp);
- unsigned int total_bits = GET_MODE_BITSIZE (mode);
- HOST_WIDE_INT bit_offset = bitnum - bitnum % total_bits;
-
- /* If we're accessing a volatile MEM, we can't apply BIT_OFFSET
- if it results in a multi-word access where we otherwise wouldn't
- have one. So, check for that case here. */
- if (MEM_P (op0)
- && MEM_VOLATILE_P (op0)
- && flag_strict_volatile_bitfields > 0
- && bitnum % BITS_PER_UNIT + bitsize <= total_bits
- && bitnum % GET_MODE_BITSIZE (mode) + bitsize > total_bits)
- {
- if (STRICT_ALIGNMENT)
- {
- static bool informed_about_misalignment = false;
+ op0 = narrow_bit_field_mem (op0, mode, bitsize, bitnum, &bitnum);
+ }
- if (packedp)
- {
- if (bitsize == total_bits)
- warning_at (input_location, OPT_fstrict_volatile_bitfields,
- "multiple accesses to volatile structure"
- " member because of packed attribute");
- else
- warning_at (input_location, OPT_fstrict_volatile_bitfields,
- "multiple accesses to volatile structure"
- " bitfield because of packed attribute");
-
- return extract_split_bit_field (op0, bitsize, bitnum,
- unsignedp);
- }
+ return extract_fixed_bit_field_1 (tmode, op0, bitsize, bitnum,
+ target, unsignedp);
+}
- if (bitsize == total_bits)
- warning_at (input_location, OPT_fstrict_volatile_bitfields,
- "mis-aligned access used for structure member");
- else
- warning_at (input_location, OPT_fstrict_volatile_bitfields,
- "mis-aligned access used for structure bitfield");
+/* Helper function for extract_fixed_bit_field, extracts
+ the bit field always using the MODE of OP0. */
- if (! informed_about_misalignment)
- {
- informed_about_misalignment = true;
- inform (input_location,
- "when a volatile object spans multiple type-sized"
- " locations, the compiler must choose between using"
- " a single mis-aligned access to preserve the"
- " volatility, or using multiple aligned accesses"
- " to avoid runtime faults; this code may fail at"
- " runtime if the hardware does not allow this"
- " access");
- }
- }
- bit_offset = bitnum - bitnum % BITS_PER_UNIT;
- }
- op0 = adjust_bitfield_address (op0, mode, bit_offset / BITS_PER_UNIT);
- bitnum -= bit_offset;
- }
-
- mode = GET_MODE (op0);
+static rtx
+extract_fixed_bit_field_1 (machine_mode tmode, rtx op0,
+ unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitnum, rtx target,
+ int unsignedp)
+{
+ machine_mode mode = GET_MODE (op0);
gcc_assert (SCALAR_INT_MODE_P (mode));
/* Note that bitsize + bitnum can be greater than GET_MODE_BITSIZE (mode)
return expand_shift (RSHIFT_EXPR, mode, op0,
GET_MODE_BITSIZE (mode) - bitsize, target, 0);
}
-\f
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
- of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
- complement of that if COMPLEMENT. The mask is truncated if
- necessary to the width of mode MODE. The mask is zero-extended if
- BITSIZE+BITPOS is too small for MODE. */
-
-static rtx
-mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
-{
- double_int mask;
-
- mask = double_int::mask (bitsize);
- mask = mask.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
- if (complement)
- mask = ~mask;
-
- return immed_double_int_const (mask, mode);
-}
/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
- VALUE truncated to BITSIZE bits and then shifted left BITPOS bits. */
+ VALUE << BITPOS. */
static rtx
-lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
+lshift_value (machine_mode mode, unsigned HOST_WIDE_INT value,
+ int bitpos)
{
- double_int val;
-
- val = double_int::from_uhwi (INTVAL (value)).zext (bitsize);
- val = val.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
- return immed_double_int_const (val, mode);
+ return immed_wide_int_const (wi::lshift (value, bitpos), mode);
}
\f
/* Extract a bit field that is split across two words
whose meaning is determined by BYTES_PER_UNIT.
OFFSET is in UNITs, and UNIT is in bits. */
part = extract_fixed_bit_field (word_mode, word, thissize,
- offset * unit + thispos, 0, 1, false);
+ offset * unit + thispos, 0, 1);
bitsdone += thissize;
/* Shift this part into place for the result. */
operations. */
rtx
-extract_low_bits (enum machine_mode mode, enum machine_mode src_mode, rtx src)
+extract_low_bits (machine_mode mode, machine_mode src_mode, rtx src)
{
- enum machine_mode int_mode, src_int_mode;
+ machine_mode int_mode, src_int_mode;
if (mode == src_mode)
return src;
Return the rtx for where the value is. */
static rtx
-expand_shift_1 (enum tree_code code, enum machine_mode mode, rtx shifted,
+expand_shift_1 (enum tree_code code, machine_mode mode, rtx shifted,
rtx amount, rtx target, int unsignedp)
{
rtx op1, temp = 0;
optab rshift_uns_optab = lshr_optab;
optab lrotate_optab = rotl_optab;
optab rrotate_optab = rotr_optab;
- enum machine_mode op1_mode;
+ machine_mode op1_mode;
+ machine_mode scalar_mode = mode;
int attempt;
bool speed = optimize_insn_for_speed_p ();
+ if (VECTOR_MODE_P (mode))
+ scalar_mode = GET_MODE_INNER (mode);
op1 = amount;
op1_mode = GET_MODE (op1);
{
if (CONST_INT_P (op1)
&& ((unsigned HOST_WIDE_INT) INTVAL (op1) >=
- (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode)))
+ (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (scalar_mode)))
op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
- % GET_MODE_BITSIZE (mode));
+ % GET_MODE_BITSIZE (scalar_mode));
else if (GET_CODE (op1) == SUBREG
&& subreg_lowpart_p (op1)
&& SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (op1)))
amount instead. */
if (rotate
&& CONST_INT_P (op1)
- && IN_RANGE (INTVAL (op1), GET_MODE_BITSIZE (mode) / 2 + left,
- GET_MODE_BITSIZE (mode) - 1))
+ && IN_RANGE (INTVAL (op1), GET_MODE_BITSIZE (scalar_mode) / 2 + left,
+ GET_MODE_BITSIZE (scalar_mode) - 1))
{
- op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1));
+ op1 = GEN_INT (GET_MODE_BITSIZE (scalar_mode) - INTVAL (op1));
left = !left;
code = left ? LROTATE_EXPR : RROTATE_EXPR;
}
+ /* Rotation of 16bit values by 8 bits is effectively equivalent to a bswaphi.
+ Note that this is not the case for bigger values. For instance a rotation
+ of 0x01020304 by 16 bits gives 0x03040102 which is different from
+ 0x04030201 (bswapsi). */
+ if (rotate
+ && CONST_INT_P (op1)
+ && INTVAL (op1) == BITS_PER_UNIT
+ && GET_MODE_SIZE (scalar_mode) == 2
+ && optab_handler (bswap_optab, HImode) != CODE_FOR_nothing)
+ return expand_unop (HImode, bswap_optab, shifted, NULL_RTX,
+ unsignedp);
+
if (op1 == const0_rtx)
return shifted;
if (code == LSHIFT_EXPR
&& CONST_INT_P (op1)
&& INTVAL (op1) > 0
- && INTVAL (op1) < GET_MODE_PRECISION (mode)
+ && INTVAL (op1) < GET_MODE_PRECISION (scalar_mode)
&& INTVAL (op1) < MAX_BITS_PER_WORD
&& (shift_cost (speed, mode, INTVAL (op1))
> INTVAL (op1) * add_cost (speed, mode))
if (op1 == const0_rtx)
return shifted;
else if (CONST_INT_P (op1))
- other_amount = GEN_INT (GET_MODE_BITSIZE (mode)
+ other_amount = GEN_INT (GET_MODE_BITSIZE (scalar_mode)
- INTVAL (op1));
else
{
other_amount
= simplify_gen_unary (NEG, GET_MODE (op1),
op1, GET_MODE (op1));
+ HOST_WIDE_INT mask = GET_MODE_PRECISION (scalar_mode) - 1;
other_amount
- = simplify_gen_binary (AND, GET_MODE (op1),
- other_amount,
- GEN_INT (GET_MODE_PRECISION (mode)
- - 1));
+ = simplify_gen_binary (AND, GET_MODE (op1), other_amount,
+ gen_int_mode (mask, GET_MODE (op1)));
}
shifted = force_reg (mode, shifted);
Return the rtx for where the value is. */
rtx
-expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
+expand_shift (enum tree_code code, machine_mode mode, rtx shifted,
int amount, rtx target, int unsignedp)
{
return expand_shift_1 (code, mode,
Return the rtx for where the value is. */
rtx
-expand_variable_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
+expand_variable_shift (enum tree_code code, machine_mode mode, rtx shifted,
tree amount, rtx target, int unsignedp)
{
return expand_shift_1 (code, mode,
enum mult_variant {basic_variant, negate_variant, add_variant};
static void synth_mult (struct algorithm *, unsigned HOST_WIDE_INT,
- const struct mult_cost *, enum machine_mode mode);
-static bool choose_mult_variant (enum machine_mode, HOST_WIDE_INT,
+ const struct mult_cost *, machine_mode mode);
+static bool choose_mult_variant (machine_mode, HOST_WIDE_INT,
struct algorithm *, enum mult_variant *, int);
-static rtx expand_mult_const (enum machine_mode, rtx, HOST_WIDE_INT, rtx,
+static rtx expand_mult_const (machine_mode, rtx, HOST_WIDE_INT, rtx,
const struct algorithm *, enum mult_variant);
static unsigned HOST_WIDE_INT invert_mod2n (unsigned HOST_WIDE_INT, int);
-static rtx extract_high_half (enum machine_mode, rtx);
-static rtx expmed_mult_highpart (enum machine_mode, rtx, rtx, rtx, int, int);
-static rtx expmed_mult_highpart_optab (enum machine_mode, rtx, rtx, rtx,
+static rtx extract_high_half (machine_mode, rtx);
+static rtx expmed_mult_highpart (machine_mode, rtx, rtx, rtx, int, int);
+static rtx expmed_mult_highpart_optab (machine_mode, rtx, rtx, rtx,
int, int);
/* Compute and return the best algorithm for multiplying by T.
The algorithm must cost less than cost_limit
static void
synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
- const struct mult_cost *cost_limit, enum machine_mode mode)
+ const struct mult_cost *cost_limit, machine_mode mode)
{
int m;
struct algorithm *alg_in, *best_alg;
bool cache_hit = false;
enum alg_code cache_alg = alg_zero;
bool speed = optimize_insn_for_speed_p ();
- enum machine_mode imode;
+ machine_mode imode;
struct alg_hash_entry *entry_ptr;
/* Indicate that no algorithm is yet found. If no algorithm
describing the algorithm in *ALG and final fixup in *VARIANT. */
static bool
-choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
+choose_mult_variant (machine_mode mode, HOST_WIDE_INT val,
struct algorithm *alg, enum mult_variant *variant,
int mult_cost)
{
`unsigned int' */
if (HOST_BITS_PER_INT >= GET_MODE_UNIT_BITSIZE (mode))
{
- op_cost = neg_cost(speed, mode);
+ op_cost = neg_cost (speed, mode);
if (MULT_COST_LESS (&alg->cost, mult_cost))
{
limit.cost = alg->cost.cost - op_cost;
the final fixup specified by VARIANT. */
static rtx
-expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
+expand_mult_const (machine_mode mode, rtx op0, HOST_WIDE_INT val,
rtx target, const struct algorithm *alg,
enum mult_variant variant)
{
HOST_WIDE_INT val_so_far;
- rtx insn, accum, tem;
+ rtx_insn *insn;
+ rtx accum, tem;
int opno;
- enum machine_mode nmode;
+ machine_mode nmode;
/* Avoid referencing memory over and over and invalid sharing
on SUBREGs. */
insn = get_last_insn ();
set_dst_reg_note (insn, REG_EQUAL,
- gen_rtx_MULT (nmode, tem, GEN_INT (val_so_far)),
+ gen_rtx_MULT (nmode, tem,
+ gen_int_mode (val_so_far, nmode)),
accum_inner);
}
}
you should swap the two operands if OP0 would be constant. */
rtx
-expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_mult (machine_mode mode, rtx op0, rtx op1, rtx target,
int unsignedp)
{
enum mult_variant variant;
if (do_trapv)
goto skip_synth;
+ /* If mode is integer vector mode, check if the backend supports
+ vector lshift (by scalar or vector) at all. If not, we can't use
+ synthetized multiply. */
+ if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+ && optab_handler (vashl_optab, mode) == CODE_FOR_nothing
+ && optab_handler (ashl_optab, mode) == CODE_FOR_nothing)
+ goto skip_synth;
+
/* These are the operations that are potentially turned into
a sequence of shifts and additions. */
mode_bitsize = GET_MODE_UNIT_BITSIZE (mode);
only if the constant value exactly fits in an `unsigned int' without
any truncation. This means that multiplying by negative values does
not work; results are off by 2^32 on a 32 bit machine. */
-
if (CONST_INT_P (scalar_op1))
{
coeff = INTVAL (scalar_op1);
is_neg = coeff < 0;
}
+#if TARGET_SUPPORTS_WIDE_INT
+ else if (CONST_WIDE_INT_P (scalar_op1))
+#else
else if (CONST_DOUBLE_AS_INT_P (scalar_op1))
+#endif
{
- /* If we are multiplying in DImode, it may still be a win
- to try to work with shifts and adds. */
- if (CONST_DOUBLE_HIGH (scalar_op1) == 0
- && (CONST_DOUBLE_LOW (scalar_op1) > 0
- || (CONST_DOUBLE_LOW (scalar_op1) < 0
- && EXACT_POWER_OF_2_OR_ZERO_P
- (CONST_DOUBLE_LOW (scalar_op1)))))
- {
- coeff = CONST_DOUBLE_LOW (scalar_op1);
- is_neg = false;
- }
- else if (CONST_DOUBLE_LOW (scalar_op1) == 0)
- {
- coeff = CONST_DOUBLE_HIGH (scalar_op1);
- if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
- {
- int shift = floor_log2 (coeff) + HOST_BITS_PER_WIDE_INT;
- if (shift < HOST_BITS_PER_DOUBLE_INT - 1
- || mode_bitsize <= HOST_BITS_PER_DOUBLE_INT)
- return expand_shift (LSHIFT_EXPR, mode, op0,
- shift, target, unsignedp);
- }
- goto skip_synth;
- }
+ int shift = wi::exact_log2 (std::make_pair (scalar_op1, mode));
+ /* Perfect power of 2 (other than 1, which is handled above). */
+ if (shift > 0)
+ return expand_shift (LSHIFT_EXPR, mode, op0,
+ shift, target, unsignedp);
else
goto skip_synth;
}
calculation of the synth_mult. */
coeff = -(unsigned HOST_WIDE_INT) coeff;
max_cost = (set_src_cost (gen_rtx_MULT (mode, fake_reg, op1), speed)
- - neg_cost(speed, mode));
+ - neg_cost (speed, mode));
if (max_cost <= 0)
goto skip_synth;
COEFFicient in the given MODE and SPEED. */
int
-mult_by_coeff_cost (HOST_WIDE_INT coeff, enum machine_mode mode, bool speed)
+mult_by_coeff_cost (HOST_WIDE_INT coeff, machine_mode mode, bool speed)
{
int max_cost;
struct algorithm algorithm;
and adds. */
rtx
-expand_widening_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_widening_mult (machine_mode mode, rtx op0, rtx op1, rtx target,
int unsignedp, optab this_optab)
{
bool speed = optimize_insn_for_speed_p ();
unsigned HOST_WIDE_INT *multiplier_ptr,
int *post_shift_ptr, int *lgup_ptr)
{
- double_int mhigh, mlow;
int lgup, post_shift;
int pow, pow2;
pow = n + lgup;
pow2 = n + lgup - precision;
- /* We could handle this with some effort, but this case is much
- better handled directly with a scc insn, so rely on caller using
- that. */
- gcc_assert (pow != HOST_BITS_PER_DOUBLE_INT);
-
/* mlow = 2^(N + lgup)/d */
- double_int val = double_int_zero.set_bit (pow);
- mlow = val.div (double_int::from_uhwi (d), true, TRUNC_DIV_EXPR);
+ wide_int val = wi::set_bit_in_zero (pow, HOST_BITS_PER_DOUBLE_INT);
+ wide_int mlow = wi::udiv_trunc (val, d);
/* mhigh = (2^(N + lgup) + 2^(N + lgup - precision))/d */
- val |= double_int_zero.set_bit (pow2);
- mhigh = val.div (double_int::from_uhwi (d), true, TRUNC_DIV_EXPR);
-
- gcc_assert (!mhigh.high || val.high - d < d);
- gcc_assert (mhigh.high <= 1 && mlow.high <= 1);
- /* Assert that mlow < mhigh. */
- gcc_assert (mlow.ult (mhigh));
+ val |= wi::set_bit_in_zero (pow2, HOST_BITS_PER_DOUBLE_INT);
+ wide_int mhigh = wi::udiv_trunc (val, d);
/* If precision == N, then mlow, mhigh exceed 2^N
(but they do not exceed 2^(N+1)). */
/* Reduce to lowest terms. */
for (post_shift = lgup; post_shift > 0; post_shift--)
{
- int shft = HOST_BITS_PER_WIDE_INT - 1;
- unsigned HOST_WIDE_INT ml_lo = (mlow.high << shft) | (mlow.low >> 1);
- unsigned HOST_WIDE_INT mh_lo = (mhigh.high << shft) | (mhigh.low >> 1);
+ unsigned HOST_WIDE_INT ml_lo = wi::extract_uhwi (mlow, 1,
+ HOST_BITS_PER_WIDE_INT);
+ unsigned HOST_WIDE_INT mh_lo = wi::extract_uhwi (mhigh, 1,
+ HOST_BITS_PER_WIDE_INT);
if (ml_lo >= mh_lo)
break;
- mlow = double_int::from_uhwi (ml_lo);
- mhigh = double_int::from_uhwi (mh_lo);
+ mlow = wi::uhwi (ml_lo, HOST_BITS_PER_DOUBLE_INT);
+ mhigh = wi::uhwi (mh_lo, HOST_BITS_PER_DOUBLE_INT);
}
*post_shift_ptr = post_shift;
if (n < HOST_BITS_PER_WIDE_INT)
{
unsigned HOST_WIDE_INT mask = ((unsigned HOST_WIDE_INT) 1 << n) - 1;
- *multiplier_ptr = mhigh.low & mask;
- return mhigh.low >= mask;
+ *multiplier_ptr = mhigh.to_uhwi () & mask;
+ return mhigh.to_uhwi () >= mask;
}
else
{
- *multiplier_ptr = mhigh.low;
- return mhigh.high;
+ *multiplier_ptr = mhigh.to_uhwi ();
+ return wi::extract_uhwi (mhigh, HOST_BITS_PER_WIDE_INT, 1);
}
}
MODE is the mode of operation. */
rtx
-expand_mult_highpart_adjust (enum machine_mode mode, rtx adj_operand, rtx op0,
+expand_mult_highpart_adjust (machine_mode mode, rtx adj_operand, rtx op0,
rtx op1, rtx target, int unsignedp)
{
rtx tem;
/* Subroutine of expmed_mult_highpart. Return the MODE high part of OP. */
static rtx
-extract_high_half (enum machine_mode mode, rtx op)
+extract_high_half (machine_mode mode, rtx op)
{
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
if (mode == word_mode)
return gen_highpart (mode, op);
optab. OP1 is an rtx for the constant operand. */
static rtx
-expmed_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
+expmed_mult_highpart_optab (machine_mode mode, rtx op0, rtx op1,
rtx target, int unsignedp, int max_cost)
{
rtx narrow_op1 = gen_int_mode (INTVAL (op1), mode);
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
optab moptab;
rtx tem;
int size;
&& (mul_cost (speed, wider_mode) + shift_cost (speed, mode, size-1)
< max_cost))
{
- rtx insns, wop0, wop1;
+ rtx_insn *insns;
+ rtx wop0, wop1;
/* We need to widen the operands, for example to ensure the
constant multiplier is correctly sign or zero extended.
MAX_COST is the total allowed cost for the expanded RTL. */
static rtx
-expmed_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
+expmed_mult_highpart (machine_mode mode, rtx op0, rtx op1,
rtx target, int unsignedp, int max_cost)
{
- enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
+ machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
unsigned HOST_WIDE_INT cnst1;
int extra_cost;
bool sign_adjust = false;
/* Expand signed modulus of OP0 by a power of two D in mode MODE. */
static rtx
-expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
+expand_smod_pow2 (machine_mode mode, rtx op0, HOST_WIDE_INT d)
{
- unsigned HOST_WIDE_INT masklow, maskhigh;
- rtx result, temp, shift, label;
+ rtx result, temp, shift;
+ rtx_code_label *label;
int logd;
+ int prec = GET_MODE_PRECISION (mode);
logd = floor_log2 (d);
result = gen_reg_rtx (mode);
mode, 0, -1);
if (signmask)
{
+ HOST_WIDE_INT masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
signmask = force_reg (mode, signmask);
- masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
/* Use the rtx_cost of a LSHIFTRT instruction to determine
NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, sub_optab, temp, signmask,
NULL_RTX, 1, OPTAB_LIB_WIDEN);
- temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
+ temp = expand_binop (mode, and_optab, temp,
+ gen_int_mode (masklow, mode),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, xor_optab, temp, signmask,
NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, add_optab, op0, signmask,
NULL_RTX, 1, OPTAB_LIB_WIDEN);
- temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
+ temp = expand_binop (mode, and_optab, temp,
+ gen_int_mode (masklow, mode),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, sub_optab, temp, signmask,
NULL_RTX, 1, OPTAB_LIB_WIDEN);
modulus. By including the signbit in the operation, many targets
can avoid an explicit compare operation in the following comparison
against zero. */
-
- masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
- {
- masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
- maskhigh = -1;
- }
- else
- maskhigh = (HOST_WIDE_INT) -1
- << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
+ wide_int mask = wi::mask (logd, false, prec);
+ mask = wi::set_bit (mask, prec - 1);
temp = expand_binop (mode, and_optab, op0,
- immed_double_const (masklow, maskhigh, mode),
+ immed_wide_int_const (mask, mode),
result, 1, OPTAB_LIB_WIDEN);
if (temp != result)
emit_move_insn (result, temp);
temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
0, OPTAB_LIB_WIDEN);
- masklow = (HOST_WIDE_INT) -1 << logd;
- maskhigh = -1;
+
+ mask = wi::mask (logd, true, prec);
temp = expand_binop (mode, ior_optab, temp,
- immed_double_const (masklow, maskhigh, mode),
+ immed_wide_int_const (mask, mode),
result, 1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
0, OPTAB_LIB_WIDEN);
This routine is only called for positive values of D. */
static rtx
-expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
+expand_sdiv_pow2 (machine_mode mode, rtx op0, HOST_WIDE_INT d)
{
- rtx temp, label;
+ rtx temp;
+ rtx_code_label *label;
int logd;
logd = floor_log2 (d);
{
rtx temp2;
- /* ??? emit_conditional_move forces a stack adjustment via
- compare_from_rtx so, if the sequence is discarded, it will
- be lost. Do it now instead. */
- do_pending_stack_adjust ();
-
start_sequence ();
temp2 = copy_to_mode_reg (mode, op0);
- temp = expand_binop (mode, add_optab, temp2, GEN_INT (d-1),
+ temp = expand_binop (mode, add_optab, temp2, gen_int_mode (d - 1, mode),
NULL_RTX, 0, OPTAB_LIB_WIDEN);
temp = force_reg (mode, temp);
mode, temp, temp2, mode, 0);
if (temp2)
{
- rtx seq = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
emit_insn (seq);
return expand_shift (RSHIFT_EXPR, mode, temp2, logd, NULL_RTX, 0);
temp = gen_reg_rtx (mode);
temp = emit_store_flag (temp, LT, op0, const0_rtx, mode, 0, -1);
- if (shift_cost (optimize_insn_for_speed_p (), mode, ushift)
- > COSTS_N_INSNS (1))
- temp = expand_binop (mode, and_optab, temp, GEN_INT (d - 1),
+ if (GET_MODE_BITSIZE (mode) >= BITS_PER_WORD
+ || shift_cost (optimize_insn_for_speed_p (), mode, ushift)
+ > COSTS_N_INSNS (1))
+ temp = expand_binop (mode, and_optab, temp, gen_int_mode (d - 1, mode),
NULL_RTX, 0, OPTAB_LIB_WIDEN);
else
temp = expand_shift (RSHIFT_EXPR, mode, temp,
label = gen_label_rtx ();
temp = copy_to_mode_reg (mode, op0);
do_cmp_and_jump (temp, const0_rtx, GE, mode, label);
- expand_inc (temp, GEN_INT (d - 1));
+ expand_inc (temp, gen_int_mode (d - 1, mode));
emit_label (label);
return expand_shift (RSHIFT_EXPR, mode, temp, logd, NULL_RTX, 0);
}
*/
rtx
-expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
+expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
rtx op0, rtx op1, rtx target, int unsignedp)
{
- enum machine_mode compute_mode;
+ machine_mode compute_mode;
rtx tquotient;
rtx quotient = 0, remainder = 0;
- rtx last;
+ rtx_insn *last;
int size;
- rtx insn;
+ rtx_insn *insn;
optab optab1, optab2;
int op1_is_constant, op1_is_pow2 = 0;
int max_cost, extra_cost;
{
if (rem_flag)
return const0_rtx;
- return expand_unop (mode, flag_trapv && GET_MODE_CLASS(mode) == MODE_INT
+ return expand_unop (mode, flag_trapv && GET_MODE_CLASS (mode) == MODE_INT
? negv_optab : neg_optab, op0, target, 0);
}
pre_shift = floor_log2 (d);
if (rem_flag)
{
+ unsigned HOST_WIDE_INT mask
+ = ((unsigned HOST_WIDE_INT) 1 << pre_shift) - 1;
remainder
= expand_binop (compute_mode, and_optab, op0,
- GEN_INT (((HOST_WIDE_INT) 1 << pre_shift) - 1),
+ gen_int_mode (mask, compute_mode),
remainder, 1,
OPTAB_LIB_WIDEN);
if (remainder)
= (shift_cost (speed, compute_mode, post_shift - 1)
+ shift_cost (speed, compute_mode, 1)
+ 2 * add_cost (speed, compute_mode));
- t1 = expmed_mult_highpart (compute_mode, op0,
- GEN_INT (ml),
- NULL_RTX, 1,
- max_cost - extra_cost);
+ t1 = expmed_mult_highpart
+ (compute_mode, op0,
+ gen_int_mode (ml, compute_mode),
+ NULL_RTX, 1, max_cost - extra_cost);
if (t1 == 0)
goto fail1;
t2 = force_operand (gen_rtx_MINUS (compute_mode,
extra_cost
= (shift_cost (speed, compute_mode, pre_shift)
+ shift_cost (speed, compute_mode, post_shift));
- t2 = expmed_mult_highpart (compute_mode, t1,
- GEN_INT (ml),
- NULL_RTX, 1,
- max_cost - extra_cost);
+ t2 = expmed_mult_highpart
+ (compute_mode, t1,
+ gen_int_mode (ml, compute_mode),
+ NULL_RTX, 1, max_cost - extra_cost);
if (t2 == 0)
goto fail1;
quotient = expand_shift
extra_cost = (shift_cost (speed, compute_mode, post_shift)
+ shift_cost (speed, compute_mode, size - 1)
+ add_cost (speed, compute_mode));
- t1 = expmed_mult_highpart (compute_mode, op0,
- GEN_INT (ml), NULL_RTX, 0,
- max_cost - extra_cost);
+ t1 = expmed_mult_highpart
+ (compute_mode, op0, gen_int_mode (ml, compute_mode),
+ NULL_RTX, 0, max_cost - extra_cost);
if (t1 == 0)
goto fail1;
t2 = expand_shift
pre_shift = floor_log2 (d);
if (rem_flag)
{
- remainder = expand_binop (compute_mode, and_optab, op0,
- GEN_INT (((HOST_WIDE_INT) 1 << pre_shift) - 1),
- remainder, 0, OPTAB_LIB_WIDEN);
+ unsigned HOST_WIDE_INT mask
+ = ((unsigned HOST_WIDE_INT) 1 << pre_shift) - 1;
+ remainder = expand_binop
+ (compute_mode, and_optab, op0,
+ gen_int_mode (mask, compute_mode),
+ remainder, 0, OPTAB_LIB_WIDEN);
if (remainder)
return gen_lowpart (mode, remainder);
}
extra_cost = (shift_cost (speed, compute_mode, post_shift)
+ shift_cost (speed, compute_mode, size - 1)
+ 2 * add_cost (speed, compute_mode));
- t3 = expmed_mult_highpart (compute_mode, t2,
- GEN_INT (ml), NULL_RTX, 1,
- max_cost - extra_cost);
+ t3 = expmed_mult_highpart
+ (compute_mode, t2, gen_int_mode (ml, compute_mode),
+ NULL_RTX, 1, max_cost - extra_cost);
if (t3 != 0)
{
t4 = expand_shift
/* This could be computed with a branch-less sequence.
Save that for later. */
rtx tem;
- rtx label = gen_label_rtx ();
+ rtx_code_label *label = gen_label_rtx ();
do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, label);
tem = expand_binop (compute_mode, xor_optab, op0, op1,
NULL_RTX, 0, OPTAB_WIDEN);
/* No luck with division elimination or divmod. Have to do it
by conditionally adjusting op0 *and* the result. */
{
- rtx label1, label2, label3, label4, label5;
+ rtx_code_label *label1, *label2, *label3, *label4, *label5;
rtx adjusted_op0;
rtx tem;
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
floor_log2 (d), tquotient, 1);
t2 = expand_binop (compute_mode, and_optab, op0,
- GEN_INT (d - 1),
+ gen_int_mode (d - 1, compute_mode),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
t3 = gen_reg_rtx (compute_mode);
t3 = emit_store_flag (t3, NE, t2, const0_rtx,
compute_mode, 1, 1);
if (t3 == 0)
{
- rtx lab;
+ rtx_code_label *lab;
lab = gen_label_rtx ();
do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
expand_inc (t1, const1_rtx);
{
/* This could be computed with a branch-less sequence.
Save that for later. */
- rtx label = gen_label_rtx ();
+ rtx_code_label *label = gen_label_rtx ();
do_cmp_and_jump (remainder, const0_rtx, EQ,
compute_mode, label);
expand_inc (quotient, const1_rtx);
/* No luck with division elimination or divmod. Have to do it
by conditionally adjusting op0 *and* the result. */
{
- rtx label1, label2;
+ rtx_code_label *label1, *label2;
rtx adjusted_op0, tem;
quotient = gen_reg_rtx (compute_mode);
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
floor_log2 (d), tquotient, 0);
t2 = expand_binop (compute_mode, and_optab, op0,
- GEN_INT (d - 1),
+ gen_int_mode (d - 1, compute_mode),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
t3 = gen_reg_rtx (compute_mode);
t3 = emit_store_flag (t3, NE, t2, const0_rtx,
compute_mode, 1, 1);
if (t3 == 0)
{
- rtx lab;
+ rtx_code_label *lab;
lab = gen_label_rtx ();
do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
expand_inc (t1, const1_rtx);
/* This could be computed with a branch-less sequence.
Save that for later. */
rtx tem;
- rtx label = gen_label_rtx ();
+ rtx_code_label *label = gen_label_rtx ();
do_cmp_and_jump (remainder, const0_rtx, EQ,
compute_mode, label);
tem = expand_binop (compute_mode, xor_optab, op0, op1,
/* No luck with division elimination or divmod. Have to do it
by conditionally adjusting op0 *and* the result. */
{
- rtx label1, label2, label3, label4, label5;
+ rtx_code_label *label1, *label2, *label3, *label4, *label5;
rtx adjusted_op0;
rtx tem;
if (unsignedp)
{
rtx tem;
- rtx label;
+ rtx_code_label *label;
label = gen_label_rtx ();
quotient = gen_reg_rtx (compute_mode);
remainder = gen_reg_rtx (compute_mode);
else
{
rtx abs_rem, abs_op1, tem, mask;
- rtx label;
+ rtx_code_label *label;
label = gen_label_rtx ();
quotient = gen_reg_rtx (compute_mode);
remainder = gen_reg_rtx (compute_mode);
switch (GET_CODE (x))
{
case CONST_INT:
- {
- HOST_WIDE_INT hi = 0;
-
- if (INTVAL (x) < 0
- && !(TYPE_UNSIGNED (type)
- && (GET_MODE_BITSIZE (TYPE_MODE (type))
- < HOST_BITS_PER_WIDE_INT)))
- hi = -1;
-
- t = build_int_cst_wide (type, INTVAL (x), hi);
-
- return t;
- }
+ case CONST_WIDE_INT:
+ t = wide_int_to_tree (type, std::make_pair (x, TYPE_MODE (type)));
+ return t;
case CONST_DOUBLE:
- if (GET_MODE (x) == VOIDmode)
- t = build_int_cst_wide (type,
- CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
+ STATIC_ASSERT (HOST_BITS_PER_WIDE_INT * 2 <= MAX_BITSIZE_MODE_ANY_INT);
+ if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
+ t = wide_int_to_tree (type,
+ wide_int::from_array (&CONST_DOUBLE_LOW (x), 2,
+ HOST_BITS_PER_WIDE_INT * 2));
else
{
REAL_VALUE_TYPE d;
If TARGET is 0, a pseudo-register or constant is returned. */
rtx
-expand_and (enum machine_mode mode, rtx op0, rtx op1, rtx target)
+expand_and (machine_mode mode, rtx op0, rtx op1, rtx target)
{
rtx tem = 0;
}
/* Helper function for emit_store_flag. */
-static rtx
+rtx
emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
- enum machine_mode mode, enum machine_mode compare_mode,
+ machine_mode mode, machine_mode compare_mode,
int unsignedp, rtx x, rtx y, int normalizep,
- enum machine_mode target_mode)
+ machine_mode target_mode)
{
struct expand_operand ops[4];
- rtx op0, last, comparison, subtarget;
- enum machine_mode result_mode = targetm.cstore_mode (icode);
+ rtx op0, comparison, subtarget;
+ rtx_insn *last;
+ machine_mode result_mode = targetm.cstore_mode (icode);
last = get_last_insn ();
x = prepare_operand (icode, x, 2, mode, compare_mode, unsignedp);
static rtx
emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
- enum machine_mode mode, int unsignedp, int normalizep,
- enum machine_mode target_mode)
+ machine_mode mode, int unsignedp, int normalizep,
+ machine_mode target_mode)
{
rtx subtarget;
enum insn_code icode;
- enum machine_mode compare_mode;
+ machine_mode compare_mode;
enum mode_class mclass;
enum rtx_code scode;
rtx tem;
for (compare_mode = mode; compare_mode != VOIDmode;
compare_mode = GET_MODE_WIDER_MODE (compare_mode))
{
- enum machine_mode optab_mode = mclass == MODE_CC ? CCmode : compare_mode;
+ machine_mode optab_mode = mclass == MODE_CC ? CCmode : compare_mode;
icode = optab_handler (cstore_optab, optab_mode);
if (icode != CODE_FOR_nothing)
{
rtx
emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
- enum machine_mode mode, int unsignedp, int normalizep)
+ machine_mode mode, int unsignedp, int normalizep)
{
- enum machine_mode target_mode = target ? GET_MODE (target) : VOIDmode;
+ machine_mode target_mode = target ? GET_MODE (target) : VOIDmode;
enum rtx_code rcode;
rtx subtarget;
- rtx tem, last, trueval;
+ rtx tem, trueval;
+ rtx_insn *last;
+
+ /* If we compare constants, we shouldn't use a store-flag operation,
+ but a constant load. We can get there via the vanilla route that
+ usually generates a compare-branch sequence, but will in this case
+ fold the comparison to a constant, and thus elide the branch. */
+ if (CONSTANT_P (op0) && CONSTANT_P (op1))
+ return NULL_RTX;
tem = emit_store_flag_1 (target, code, op0, op1, mode, unsignedp, normalizep,
target_mode);
STORE_FLAG_VALUE, target_mode);
if (tem)
return expand_binop (target_mode, add_optab, tem,
- GEN_INT (normalizep),
+ gen_int_mode (normalizep, target_mode),
target, 0, OPTAB_WIDEN);
}
else if (!want_add
STORE_FLAG_VALUE, target_mode);
if (tem != 0)
tem = expand_binop (target_mode, add_optab, tem,
- GEN_INT (normalizep), target, 0, OPTAB_WIDEN);
+ gen_int_mode (normalizep, target_mode),
+ target, 0, OPTAB_WIDEN);
}
else if (!want_add
&& rtx_cost (trueval, XOR, 1,
rtx
emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
- enum machine_mode mode, int unsignedp, int normalizep)
+ machine_mode mode, int unsignedp, int normalizep)
{
- rtx tem, label;
+ rtx tem;
+ rtx_code_label *label;
rtx trueval, falseval;
/* First see if emit_store_flag can do the job. */
now a thin wrapper around do_compare_rtx_and_jump. */
static void
-do_cmp_and_jump (rtx arg1, rtx arg2, enum rtx_code op, enum machine_mode mode,
- rtx label)
+do_cmp_and_jump (rtx arg1, rtx arg2, enum rtx_code op, machine_mode mode,
+ rtx_code_label *label)
{
int unsignedp = (op == LTU || op == LEU || op == GTU || op == GEU);
do_compare_rtx_and_jump (arg1, arg2, op, unsignedp, mode,