/* Medium-level subroutines: convert bit-field store and extract
and shifts, multiplies and divides to rtl instructions.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
+/* Test whether a value is zero of a power of two. */
+#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
+
/* Nonzero means divides or modulus operations are relatively cheap for
powers of two, so don't use branches; emit the operation instead.
Usually, this will mean that the MD file will emit non-branch
memset (&all, 0, sizeof all);
PUT_CODE (&all.reg, REG);
- REGNO (&all.reg) = 10000;
+ /* Avoid using hard regs in ways which may be unsupported. */
+ REGNO (&all.reg) = LAST_VIRTUAL_REGISTER + 1;
PUT_CODE (&all.plus, PLUS);
XEXP (&all.plus, 0) = &all.reg;
return MAX_MACHINE_MODE;
default:
- abort ();
+ gcc_unreachable ();
}
if (opno == -1)
{
unsigned int unit
= (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
- unsigned HOST_WIDE_INT offset = bitnum / unit;
- unsigned HOST_WIDE_INT bitpos = bitnum % unit;
+ unsigned HOST_WIDE_INT offset, bitpos;
rtx op0 = str_rtx;
int byte_offset;
+ rtx orig_value;
enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
meaningful at a much higher level; when structures are copied
between memory and regs, the higher-numbered regs
always get higher addresses. */
- offset += (SUBREG_BYTE (op0) / UNITS_PER_WORD);
- /* We used to adjust BITPOS here, but now we do the whole adjustment
- right after the loop. */
+ bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
op0 = SUBREG_REG (op0);
}
+ /* No action is needed if the target is a register and if the field
+ lies completely outside that register. This can occur if the source
+ code contains an out-of-bounds access to a small array. */
+ if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
+ return value;
+
/* Use vec_set patterns for inserting parts of vectors whenever
available. */
if (VECTOR_MODE_P (GET_MODE (op0))
/* We could handle this, but we should always be called with a pseudo
for our targets and all insns should take them as outputs. */
- if (! (*insn_data[icode].operand[0].predicate) (dest, mode0)
- || ! (*insn_data[icode].operand[1].predicate) (src, mode1)
- || ! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
- abort ();
+ gcc_assert ((*insn_data[icode].operand[0].predicate) (dest, mode0)
+ && (*insn_data[icode].operand[1].predicate) (src, mode1)
+ && (*insn_data[icode].operand[2].predicate) (rtxpos, mode2));
pat = GEN_FCN (icode) (dest, src, rtxpos);
seq = get_insns ();
end_sequence ();
done with a simple store. For targets that support fast unaligned
memory, any naturally sized, unit aligned field can be done directly. */
+ offset = bitnum / unit;
+ bitpos = bitnum % unit;
byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ (offset * UNITS_PER_WORD);
{
if (GET_MODE (op0) != fieldmode)
{
- if (GET_CODE (op0) == SUBREG)
- {
- if (GET_MODE (SUBREG_REG (op0)) == fieldmode
- || GET_MODE_CLASS (fieldmode) == MODE_INT
- || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT)
- op0 = SUBREG_REG (op0);
- else
- /* Else we've got some float mode source being extracted into
- a different float mode destination -- this combination of
- subregs results in Severe Tire Damage. */
- abort ();
- }
- if (REG_P (op0))
- op0 = gen_rtx_SUBREG (fieldmode, op0, byte_offset);
- else
+ if (MEM_P (op0))
op0 = adjust_address (op0, fieldmode, offset);
+ else
+ op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
+ byte_offset);
}
emit_move_insn (op0, value);
return value;
{
if (MEM_P (op0))
op0 = adjust_address (op0, imode, 0);
- else if (imode != BLKmode)
- op0 = gen_lowpart (imode, op0);
else
- abort ();
+ {
+ gcc_assert (imode != BLKmode);
+ op0 = gen_lowpart (imode, op0);
+ }
}
}
if (GET_CODE (op0) == SUBREG)
{
- if (GET_MODE (SUBREG_REG (op0)) == fieldmode
- || GET_MODE_CLASS (fieldmode) == MODE_INT
- || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT)
- op0 = SUBREG_REG (op0);
- else
- /* Else we've got some float mode source being extracted into
- a different float mode destination -- this combination of
- subregs results in Severe Tire Damage. */
- abort ();
+ /* Else we've got some float mode source being extracted into
+ a different float mode destination -- this combination of
+ subregs results in Severe Tire Damage. */
+ gcc_assert (GET_MODE (SUBREG_REG (op0)) == fieldmode
+ || GET_MODE_CLASS (fieldmode) == MODE_INT
+ || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT);
+ op0 = SUBREG_REG (op0);
}
emit_insn (GEN_FCN (icode)
pseudo. We can trivially remove a SUBREG that does not
change the size of the operand. Such a SUBREG may have been
added above. Otherwise, abort. */
- if (GET_CODE (op0) == SUBREG
- && (GET_MODE_SIZE (GET_MODE (op0))
- == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
- op0 = SUBREG_REG (op0);
- else
- abort ();
+ gcc_assert (GET_CODE (op0) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (op0))
+ == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))));
+ op0 = SUBREG_REG (op0);
}
op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
op0, (offset * UNITS_PER_WORD));
offset = 0;
}
- /* If VALUE is a floating-point mode, access it as an integer of the
- corresponding size. This can occur on a machine with 64 bit registers
- that uses SFmode for float. This can also occur for unaligned float
- structure fields. */
- if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
+ /* If VALUE has a floating-point or complex mode, access it as an
+ integer of the corresponding size. This can occur on a machine
+ with 64 bit registers that uses SFmode for float. It can also
+ occur for unaligned float or complex fields. */
+ orig_value = value;
+ if (GET_MODE (value) != VOIDmode
+ && GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
&& GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
- value = gen_lowpart ((GET_MODE (value) == VOIDmode
- ? word_mode : int_mode_for_mode (GET_MODE (value))),
- value);
+ {
+ value = gen_reg_rtx (int_mode_for_mode (GET_MODE (value)));
+ emit_move_insn (gen_lowpart (GET_MODE (orig_value), value), orig_value);
+ }
/* Now OFFSET is nonzero only if OP0 is memory
and is therefore always measured in bytes. */
/* Fetch that unit, store the bitfield in it, then store
the unit. */
tempreg = copy_to_reg (op0);
- store_bit_field (tempreg, bitsize, bitpos, fieldmode, value);
+ store_bit_field (tempreg, bitsize, bitpos, fieldmode, orig_value);
emit_move_insn (op0, tempreg);
return value;
}
}
else if (GET_CODE (value) == CONST_INT)
value1 = gen_int_mode (INTVAL (value), maxmode);
- else if (!CONSTANT_P (value))
+ else
/* Parse phase is supposed to make VALUE's data type
match that of the component reference, which is a type
at least as wide as the field; so VALUE should have
a mode that corresponds to that type. */
- abort ();
+ gcc_assert (CONSTANT_P (value));
}
/* If this machine's insv insists on a register,
if (REG_P (op0) || GET_CODE (op0) == SUBREG)
{
- if (offset != 0)
- abort ();
+ gcc_assert (!offset);
/* Special treatment for a bit field split across two registers. */
if (bitsize + bitpos > BITS_PER_WORD)
{
NULL_RTX, 1, OPTAB_LIB_WIDEN);
if (bitpos > 0)
value = expand_shift (LSHIFT_EXPR, mode, value,
- build_int_cst (NULL_TREE,
- bitpos, 0), NULL_RTX, 1);
+ build_int_cst (NULL_TREE, bitpos), NULL_RTX, 1);
}
/* Now clear the chosen bits in OP0,
{
unsigned int unit
= (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
- unsigned HOST_WIDE_INT offset = bitnum / unit;
- unsigned HOST_WIDE_INT bitpos = bitnum % unit;
+ unsigned HOST_WIDE_INT offset, bitpos;
rtx op0 = str_rtx;
rtx spec_target = target;
rtx spec_target_subreg = 0;
while (GET_CODE (op0) == SUBREG)
{
- bitpos += SUBREG_BYTE (op0) * BITS_PER_UNIT;
- if (bitpos > unit)
- {
- offset += (bitpos / unit);
- bitpos %= unit;
- }
+ bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
op0 = SUBREG_REG (op0);
}
+ /* If we have an out-of-bounds access to a register, just return an
+ uninitialized register of the required mode. This can occur if the
+ source code contains an out-of-bounds access to a small array. */
+ if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
+ return gen_reg_rtx (tmode);
+
if (REG_P (op0)
&& mode == GET_MODE (op0)
&& bitnum == 0
/* We could handle this, but we should always be called with a pseudo
for our targets and all insns should take them as outputs. */
- if (! (*insn_data[icode].operand[0].predicate) (dest, mode0)
- || ! (*insn_data[icode].operand[1].predicate) (src, mode1)
- || ! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
- abort ();
+ gcc_assert ((*insn_data[icode].operand[0].predicate) (dest, mode0)
+ && (*insn_data[icode].operand[1].predicate) (src, mode1)
+ && (*insn_data[icode].operand[2].predicate) (rtxpos, mode2));
pat = GEN_FCN (icode) (dest, src, rtxpos);
seq = get_insns ();
{
if (MEM_P (op0))
op0 = adjust_address (op0, imode, 0);
- else if (imode != BLKmode)
- op0 = gen_lowpart (imode, op0);
else
- abort ();
+ {
+ gcc_assert (imode != BLKmode);
+ op0 = gen_lowpart (imode, op0);
+
+ /* If we got a SUBREG, force it into a register since we
+ aren't going to be able to do another SUBREG on it. */
+ if (GET_CODE (op0) == SUBREG)
+ op0 = force_reg (imode, op0);
+ }
}
}
can also be extracted with a SUBREG. For this, we need the
byte offset of the value in op0. */
+ bitpos = bitnum % unit;
+ offset = bitnum / unit;
byte_offset = bitpos / BITS_PER_UNIT + offset * UNITS_PER_WORD;
/* If OP0 is a register, BITPOS must count within a word.
{
if (mode1 != GET_MODE (op0))
{
- if (GET_CODE (op0) == SUBREG)
+ if (MEM_P (op0))
+ op0 = adjust_address (op0, mode1, offset);
+ else
{
- if (GET_MODE (SUBREG_REG (op0)) == mode1
- || GET_MODE_CLASS (mode1) == MODE_INT
- || GET_MODE_CLASS (mode1) == MODE_PARTIAL_INT)
- op0 = SUBREG_REG (op0);
- else
- /* Else we've got some float mode source being extracted into
- a different float mode destination -- this combination of
- subregs results in Severe Tire Damage. */
+ rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
+ byte_offset);
+ if (sub == NULL)
goto no_subreg_mode_swap;
+ op0 = sub;
}
- if (REG_P (op0))
- op0 = gen_rtx_SUBREG (mode1, op0, byte_offset);
- else
- op0 = adjust_address (op0, mode1, offset);
}
if (mode1 != mode)
return convert_to_mode (tmode, op0, unsignedp);
bitnum + bit_offset, 1, target_part, mode,
word_mode);
- if (target_part == 0)
- abort ();
+ gcc_assert (target_part);
if (result_part != target_part)
emit_move_insn (target_part, result_part);
/* Signed bit field: sign-extend with two arithmetic shifts. */
target = expand_shift (LSHIFT_EXPR, mode, target,
build_int_cst (NULL_TREE,
- GET_MODE_BITSIZE (mode) - bitsize,
- 0),
+ GET_MODE_BITSIZE (mode) - bitsize),
NULL_RTX, 0);
return expand_shift (RSHIFT_EXPR, mode, target,
build_int_cst (NULL_TREE,
- GET_MODE_BITSIZE (mode) - bitsize,
- 0),
+ GET_MODE_BITSIZE (mode) - bitsize),
NULL_RTX, 0);
}
int_mode = int_mode_for_mode (tmode);
if (int_mode == BLKmode)
int_mode = int_mode_for_mode (mode);
- if (int_mode == BLKmode)
- abort (); /* Should probably push op0 out to memory and then
- do a load. */
+ /* Should probably push op0 out to memory and then do a load. */
+ gcc_assert (int_mode != BLKmode);
/* OFFSET is the number of words or bytes (UNIT says which)
from STR_RTX to the first word or byte containing part of the field. */
-
if (!MEM_P (op0))
{
if (offset != 0
return spec_target;
if (GET_MODE (target) != tmode && GET_MODE (target) != mode)
{
- /* If the target mode is floating-point, first convert to the
+ /* If the target mode is not a scalar integral, first convert to the
integer mode of that size and then access it as a floating-point
value via a SUBREG. */
- if (GET_MODE_CLASS (tmode) != MODE_INT
- && GET_MODE_CLASS (tmode) != MODE_PARTIAL_INT)
+ if (!SCALAR_INT_MODE_P (tmode))
{
- target = convert_to_mode (mode_for_size (GET_MODE_BITSIZE (tmode),
- MODE_INT, 0),
- target, unsignedp);
+ enum machine_mode smode
+ = mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0);
+ target = convert_to_mode (smode, target, unsignedp);
+ target = force_reg (smode, target);
return gen_lowpart (tmode, target);
}
- else
- return convert_to_mode (tmode, target, unsignedp);
+
+ return convert_to_mode (tmode, target, unsignedp);
}
return target;
}
{
/* If the field does not already start at the lsb,
shift it so it does. */
- tree amount = build_int_cst (NULL_TREE, bitpos, 0);
+ tree amount = build_int_cst (NULL_TREE, bitpos);
/* Maybe propagate the target for the shift. */
/* But not if we will return it--could confuse integrate.c. */
rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
{
tree amount
= build_int_cst (NULL_TREE,
- GET_MODE_BITSIZE (mode) - (bitsize + bitpos), 0);
+ GET_MODE_BITSIZE (mode) - (bitsize + bitpos));
/* Maybe propagate the target for the shift. */
rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1);
return expand_shift (RSHIFT_EXPR, mode, op0,
build_int_cst (NULL_TREE,
- GET_MODE_BITSIZE (mode) - bitsize, 0),
+ GET_MODE_BITSIZE (mode) - bitsize),
target, 0);
}
\f
return immed_double_const (low, high, mode);
}
\f
+/* Extract a bit field from a memory by forcing the alignment of the
+ memory. This efficient only if the field spans at least 4 boundaries.
+
+ OP0 is the MEM.
+ BITSIZE is the field width; BITPOS is the position of the first bit.
+ UNSIGNEDP is true if the result should be zero-extended. */
+
+static rtx
+extract_force_align_mem_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
+ unsigned HOST_WIDE_INT bitpos,
+ int unsignedp)
+{
+ enum machine_mode mode, dmode;
+ unsigned int m_bitsize, m_size;
+ unsigned int sign_shift_up, sign_shift_dn;
+ rtx base, a1, a2, v1, v2, comb, shift, result, start;
+
+ /* Choose a mode that will fit BITSIZE. */
+ mode = smallest_mode_for_size (bitsize, MODE_INT);
+ m_size = GET_MODE_SIZE (mode);
+ m_bitsize = GET_MODE_BITSIZE (mode);
+
+ /* Choose a mode twice as wide. Fail if no such mode exists. */
+ dmode = mode_for_size (m_bitsize * 2, MODE_INT, false);
+ if (dmode == BLKmode)
+ return NULL;
+
+ do_pending_stack_adjust ();
+ start = get_last_insn ();
+
+ /* At the end, we'll need an additional shift to deal with sign/zero
+ extension. By default this will be a left+right shift of the
+ appropriate size. But we may be able to eliminate one of them. */
+ sign_shift_up = sign_shift_dn = m_bitsize - bitsize;
+
+ if (STRICT_ALIGNMENT)
+ {
+ base = plus_constant (XEXP (op0, 0), bitpos / BITS_PER_UNIT);
+ bitpos %= BITS_PER_UNIT;
+
+ /* We load two values to be concatenate. There's an edge condition
+ that bears notice -- an aligned value at the end of a page can
+ only load one value lest we segfault. So the two values we load
+ are at "base & -size" and "(base + size - 1) & -size". If base
+ is unaligned, the addresses will be aligned and sequential; if
+ base is aligned, the addresses will both be equal to base. */
+
+ a1 = expand_simple_binop (Pmode, AND, force_operand (base, NULL),
+ GEN_INT (-(HOST_WIDE_INT)m_size),
+ NULL, true, OPTAB_LIB_WIDEN);
+ mark_reg_pointer (a1, m_bitsize);
+ v1 = gen_rtx_MEM (mode, a1);
+ set_mem_align (v1, m_bitsize);
+ v1 = force_reg (mode, validize_mem (v1));
+
+ a2 = plus_constant (base, GET_MODE_SIZE (mode) - 1);
+ a2 = expand_simple_binop (Pmode, AND, force_operand (a2, NULL),
+ GEN_INT (-(HOST_WIDE_INT)m_size),
+ NULL, true, OPTAB_LIB_WIDEN);
+ v2 = gen_rtx_MEM (mode, a2);
+ set_mem_align (v2, m_bitsize);
+ v2 = force_reg (mode, validize_mem (v2));
+
+ /* Combine these two values into a double-word value. */
+ if (m_bitsize == BITS_PER_WORD)
+ {
+ comb = gen_reg_rtx (dmode);
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, comb));
+ emit_move_insn (gen_rtx_SUBREG (mode, comb, 0), v1);
+ emit_move_insn (gen_rtx_SUBREG (mode, comb, m_size), v2);
+ }
+ else
+ {
+ if (BYTES_BIG_ENDIAN)
+ comb = v1, v1 = v2, v2 = comb;
+ v1 = convert_modes (dmode, mode, v1, true);
+ if (v1 == NULL)
+ goto fail;
+ v2 = convert_modes (dmode, mode, v2, true);
+ v2 = expand_simple_binop (dmode, ASHIFT, v2, GEN_INT (m_bitsize),
+ NULL, true, OPTAB_LIB_WIDEN);
+ if (v2 == NULL)
+ goto fail;
+ comb = expand_simple_binop (dmode, IOR, v1, v2, NULL,
+ true, OPTAB_LIB_WIDEN);
+ if (comb == NULL)
+ goto fail;
+ }
+
+ shift = expand_simple_binop (Pmode, AND, base, GEN_INT (m_size - 1),
+ NULL, true, OPTAB_LIB_WIDEN);
+ shift = expand_mult (Pmode, shift, GEN_INT (BITS_PER_UNIT), NULL, 1);
+
+ if (bitpos != 0)
+ {
+ if (sign_shift_up <= bitpos)
+ bitpos -= sign_shift_up, sign_shift_up = 0;
+ shift = expand_simple_binop (Pmode, PLUS, shift, GEN_INT (bitpos),
+ NULL, true, OPTAB_LIB_WIDEN);
+ }
+ }
+ else
+ {
+ unsigned HOST_WIDE_INT offset = bitpos / BITS_PER_UNIT;
+ bitpos %= BITS_PER_UNIT;
+
+ /* When strict alignment is not required, we can just load directly
+ from memory without masking. If the remaining BITPOS offset is
+ small enough, we may be able to do all operations in MODE as
+ opposed to DMODE. */
+ if (bitpos + bitsize <= m_bitsize)
+ dmode = mode;
+ comb = adjust_address (op0, dmode, offset);
+
+ if (sign_shift_up <= bitpos)
+ bitpos -= sign_shift_up, sign_shift_up = 0;
+ shift = GEN_INT (bitpos);
+ }
+
+ /* Shift down the double-word such that the requested value is at bit 0. */
+ if (shift != const0_rtx)
+ comb = expand_simple_binop (dmode, unsignedp ? LSHIFTRT : ASHIFTRT,
+ comb, shift, NULL, unsignedp, OPTAB_LIB_WIDEN);
+ if (comb == NULL)
+ goto fail;
+
+ /* If the field exactly matches MODE, then all we need to do is return the
+ lowpart. Otherwise, shift to get the sign bits set properly. */
+ result = force_reg (mode, gen_lowpart (mode, comb));
+
+ if (sign_shift_up)
+ result = expand_simple_binop (mode, ASHIFT, result,
+ GEN_INT (sign_shift_up),
+ NULL_RTX, 0, OPTAB_LIB_WIDEN);
+ if (sign_shift_dn)
+ result = expand_simple_binop (mode, unsignedp ? LSHIFTRT : ASHIFTRT,
+ result, GEN_INT (sign_shift_dn),
+ NULL_RTX, 0, OPTAB_LIB_WIDEN);
+
+ return result;
+
+ fail:
+ delete_insns_since (start);
+ return NULL;
+}
+
/* Extract a bit field that is split across two words
and return an RTX for the result.
if (REG_P (op0) || GET_CODE (op0) == SUBREG)
unit = BITS_PER_WORD;
else
- unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
+ {
+ unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
+ if (0 && bitsize / unit > 2)
+ {
+ rtx tmp = extract_force_align_mem_bit_field (op0, bitsize, bitpos,
+ unsignedp);
+ if (tmp)
+ return tmp;
+ }
+ }
while (bitsdone < bitsize)
{
{
if (bitsize != bitsdone)
part = expand_shift (LSHIFT_EXPR, word_mode, part,
- build_int_cst (NULL_TREE,
- bitsize - bitsdone, 0), 0, 1);
+ build_int_cst (NULL_TREE, bitsize - bitsdone),
+ 0, 1);
}
else
{
if (bitsdone != thissize)
part = expand_shift (LSHIFT_EXPR, word_mode, part,
build_int_cst (NULL_TREE,
- bitsdone - thissize, 0), 0, 1);
+ bitsdone - thissize), 0, 1);
}
if (first)
return result;
/* Signed bit field: sign-extend with two arithmetic shifts. */
result = expand_shift (LSHIFT_EXPR, word_mode, result,
- build_int_cst (NULL_TREE,
- BITS_PER_WORD - bitsize, 0),
+ build_int_cst (NULL_TREE, BITS_PER_WORD - bitsize),
NULL_RTX, 0);
return expand_shift (RSHIFT_EXPR, word_mode, result,
- build_int_cst (NULL_TREE,
- BITS_PER_WORD - bitsize, 0), NULL_RTX, 0);
+ build_int_cst (NULL_TREE, BITS_PER_WORD - bitsize),
+ NULL_RTX, 0);
}
\f
/* Add INC into TARGET. */
tree type = TREE_TYPE (amount);
tree new_amount = make_tree (type, op1);
tree other_amount
- = fold (build2 (MINUS_EXPR, type, convert
- (type, build_int_cst
- (NULL_TREE, GET_MODE_BITSIZE (mode), 0)),
+ = fold (build2 (MINUS_EXPR, type,
+ build_int_cst (type, GET_MODE_BITSIZE (mode)),
amount));
shifted = force_reg (mode, shifted);
define_expand for lshrsi3 was added to vax.md. */
}
- if (temp == 0)
- abort ();
+ gcc_assert (temp);
return temp;
}
\f
-enum alg_code { alg_zero, alg_m, alg_shift,
+enum alg_code { alg_unknown, alg_zero, alg_m, alg_shift,
alg_add_t_m2, alg_sub_t_m2,
alg_add_factor, alg_sub_factor,
- alg_add_t2_m, alg_sub_t2_m,
- alg_add, alg_subtract, alg_factor, alg_shiftop };
+ alg_add_t2_m, alg_sub_t2_m };
+
+/* This structure holds the "cost" of a multiply sequence. The
+ "cost" field holds the total rtx_cost of every operator in the
+ synthetic multiplication sequence, hence cost(a op b) is defined
+ as rtx_cost(op) + cost(a) + cost(b), where cost(leaf) is zero.
+ The "latency" field holds the minimum possible latency of the
+ synthetic multiply, on a hypothetical infinitely parallel CPU.
+ This is the critical path, or the maximum height, of the expression
+ tree which is the sum of rtx_costs on the most expensive path from
+ any leaf to the root. Hence latency(a op b) is defined as zero for
+ leaves and rtx_cost(op) + max(latency(a), latency(b)) otherwise. */
+
+struct mult_cost {
+ short cost; /* Total rtx_cost of the multiplication sequence. */
+ short latency; /* The latency of the multiplication sequence. */
+};
+
+/* This macro is used to compare a pointer to a mult_cost against an
+ single integer "rtx_cost" value. This is equivalent to the macro
+ CHEAPER_MULT_COST(X,Z) where Z = {Y,Y}. */
+#define MULT_COST_LESS(X,Y) ((X)->cost < (Y) \
+ || ((X)->cost == (Y) && (X)->latency < (Y)))
+
+/* This macro is used to compare two pointers to mult_costs against
+ each other. The macro returns true if X is cheaper than Y.
+ Currently, the cheaper of two mult_costs is the one with the
+ lower "cost". If "cost"s are tied, the lower latency is cheaper. */
+#define CHEAPER_MULT_COST(X,Y) ((X)->cost < (Y)->cost \
+ || ((X)->cost == (Y)->cost \
+ && (X)->latency < (Y)->latency))
/* This structure records a sequence of operations.
`ops' is the number of operations recorded.
struct algorithm
{
- short cost;
+ struct mult_cost cost;
short ops;
/* The size of the OP and LOG fields are not directly related to the
word size, but the worst-case algorithms will be if we have few
char log[MAX_BITS_PER_WORD];
};
+/* The entry for our multiplication cache/hash table. */
+struct alg_hash_entry {
+ /* The number we are multiplying by. */
+ unsigned int t;
+
+ /* The mode in which we are multiplying something by T. */
+ enum machine_mode mode;
+
+ /* The best multiplication algorithm for t. */
+ enum alg_code alg;
+};
+
+/* The number of cache/hash entries. */
+#define NUM_ALG_HASH_ENTRIES 307
+
+/* Each entry of ALG_HASH caches alg_code for some integer. This is
+ actually a hash table. If we have a collision, that the older
+ entry is kicked out. */
+static struct alg_hash_entry alg_hash[NUM_ALG_HASH_ENTRIES];
+
/* Indicates the type of fixup needed after a constant multiplication.
BASIC_VARIANT means no fixup is needed, NEGATE_VARIANT means that
the result should be negated, and ADD_VARIANT means that the
enum mult_variant {basic_variant, negate_variant, add_variant};
static void synth_mult (struct algorithm *, unsigned HOST_WIDE_INT,
- int, enum machine_mode mode);
+ const struct mult_cost *, enum machine_mode mode);
static bool choose_mult_variant (enum machine_mode, HOST_WIDE_INT,
struct algorithm *, enum mult_variant *, int);
static rtx expand_mult_const (enum machine_mode, rtx, HOST_WIDE_INT, rtx,
const struct algorithm *, enum mult_variant);
static unsigned HOST_WIDE_INT choose_multiplier (unsigned HOST_WIDE_INT, int,
- int, unsigned HOST_WIDE_INT *,
- int *, int *);
+ int, rtx *, int *, int *);
static unsigned HOST_WIDE_INT invert_mod2n (unsigned HOST_WIDE_INT, int);
static rtx extract_high_half (enum machine_mode, rtx);
+static rtx expand_mult_highpart (enum machine_mode, rtx, rtx, rtx, int, int);
static rtx expand_mult_highpart_optab (enum machine_mode, rtx, rtx, rtx,
int, int);
/* Compute and return the best algorithm for multiplying by T.
static void
synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
- int cost_limit, enum machine_mode mode)
+ const struct mult_cost *cost_limit, enum machine_mode mode)
{
int m;
struct algorithm *alg_in, *best_alg;
- int cost;
+ struct mult_cost best_cost;
+ struct mult_cost new_limit;
+ int op_cost, op_latency;
unsigned HOST_WIDE_INT q;
int maxm = MIN (BITS_PER_WORD, GET_MODE_BITSIZE (mode));
+ int hash_index;
+ bool cache_hit = false;
+ enum alg_code cache_alg = alg_zero;
/* Indicate that no algorithm is yet found. If no algorithm
is found, this value will be returned and indicate failure. */
- alg_out->cost = cost_limit;
+ alg_out->cost.cost = cost_limit->cost + 1;
+ alg_out->cost.latency = cost_limit->latency + 1;
- if (cost_limit <= 0)
+ if (cost_limit->cost < 0
+ || (cost_limit->cost == 0 && cost_limit->latency <= 0))
return;
/* Restrict the bits of "t" to the multiplication's mode. */
if (t == 1)
{
alg_out->ops = 1;
- alg_out->cost = 0;
+ alg_out->cost.cost = 0;
+ alg_out->cost.latency = 0;
alg_out->op[0] = alg_m;
return;
}
fail now. */
if (t == 0)
{
- if (zero_cost >= cost_limit)
+ if (MULT_COST_LESS (cost_limit, zero_cost))
return;
else
{
alg_out->ops = 1;
- alg_out->cost = zero_cost;
+ alg_out->cost.cost = zero_cost;
+ alg_out->cost.latency = zero_cost;
alg_out->op[0] = alg_zero;
return;
}
alg_in = alloca (sizeof (struct algorithm));
best_alg = alloca (sizeof (struct algorithm));
+ best_cost = *cost_limit;
+
+ /* Compute the hash index. */
+ hash_index = (t ^ (unsigned int) mode) % NUM_ALG_HASH_ENTRIES;
+
+ /* See if we already know what to do for T. */
+ if (alg_hash[hash_index].t == t
+ && alg_hash[hash_index].mode == mode
+ && alg_hash[hash_index].alg != alg_unknown)
+ {
+ cache_hit = true;
+ cache_alg = alg_hash[hash_index].alg;
+ switch (cache_alg)
+ {
+ case alg_shift:
+ goto do_alg_shift;
+
+ case alg_add_t_m2:
+ case alg_sub_t_m2:
+ goto do_alg_addsub_t_m2;
+
+ case alg_add_factor:
+ case alg_sub_factor:
+ goto do_alg_addsub_factor;
+
+ case alg_add_t2_m:
+ goto do_alg_add_t2_m;
+
+ case alg_sub_t2_m:
+ goto do_alg_sub_t2_m;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
/* If we have a group of zero bits at the low-order part of T, try
multiplying by the remaining bits and then doing a shift. */
if ((t & 1) == 0)
{
+ do_alg_shift:
m = floor_log2 (t & -t); /* m = number of low zero bits */
if (m < maxm)
{
/* The function expand_shift will choose between a shift and
a sequence of additions, so the observed cost is given as
MIN (m * add_cost[mode], shift_cost[mode][m]). */
- cost = m * add_cost[mode];
- if (shift_cost[mode][m] < cost)
- cost = shift_cost[mode][m];
- synth_mult (alg_in, q, cost_limit - cost, mode);
-
- cost += alg_in->cost;
- if (cost < cost_limit)
+ op_cost = m * add_cost[mode];
+ if (shift_cost[mode][m] < op_cost)
+ op_cost = shift_cost[mode][m];
+ new_limit.cost = best_cost.cost - op_cost;
+ new_limit.latency = best_cost.latency - op_cost;
+ synth_mult (alg_in, q, &new_limit, mode);
+
+ alg_in->cost.cost += op_cost;
+ alg_in->cost.latency += op_cost;
+ if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
{
struct algorithm *x;
+ best_cost = alg_in->cost;
x = alg_in, alg_in = best_alg, best_alg = x;
best_alg->log[best_alg->ops] = m;
best_alg->op[best_alg->ops] = alg_shift;
- cost_limit = cost;
}
}
+ if (cache_hit)
+ goto done;
}
/* If we have an odd number, add or subtract one. */
{
unsigned HOST_WIDE_INT w;
+ do_alg_addsub_t_m2:
for (w = 1; (w & t) != 0; w <<= 1)
;
/* If T was -1, then W will be zero after the loop. This is another
{
/* T ends with ...111. Multiply by (T + 1) and subtract 1. */
- cost = add_cost[mode];
- synth_mult (alg_in, t + 1, cost_limit - cost, mode);
+ op_cost = add_cost[mode];
+ new_limit.cost = best_cost.cost - op_cost;
+ new_limit.latency = best_cost.latency - op_cost;
+ synth_mult (alg_in, t + 1, &new_limit, mode);
- cost += alg_in->cost;
- if (cost < cost_limit)
+ alg_in->cost.cost += op_cost;
+ alg_in->cost.latency += op_cost;
+ if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
{
struct algorithm *x;
+ best_cost = alg_in->cost;
x = alg_in, alg_in = best_alg, best_alg = x;
best_alg->log[best_alg->ops] = 0;
best_alg->op[best_alg->ops] = alg_sub_t_m2;
- cost_limit = cost;
}
}
else
{
/* T ends with ...01 or ...011. Multiply by (T - 1) and add 1. */
- cost = add_cost[mode];
- synth_mult (alg_in, t - 1, cost_limit - cost, mode);
+ op_cost = add_cost[mode];
+ new_limit.cost = best_cost.cost - op_cost;
+ new_limit.latency = best_cost.latency - op_cost;
+ synth_mult (alg_in, t - 1, &new_limit, mode);
- cost += alg_in->cost;
- if (cost < cost_limit)
+ alg_in->cost.cost += op_cost;
+ alg_in->cost.latency += op_cost;
+ if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
{
struct algorithm *x;
+ best_cost = alg_in->cost;
x = alg_in, alg_in = best_alg, best_alg = x;
best_alg->log[best_alg->ops] = 0;
best_alg->op[best_alg->ops] = alg_add_t_m2;
- cost_limit = cost;
}
}
+ if (cache_hit)
+ goto done;
}
/* Look for factors of t of the form
good sequence quickly, and therefore be able to prune (by decreasing
COST_LIMIT) the search. */
+ do_alg_addsub_factor:
for (m = floor_log2 (t - 1); m >= 2; m--)
{
unsigned HOST_WIDE_INT d;
d = ((unsigned HOST_WIDE_INT) 1 << m) + 1;
- if (t % d == 0 && t > d && m < maxm)
+ if (t % d == 0 && t > d && m < maxm
+ && (!cache_hit || cache_alg == alg_add_factor))
{
- cost = add_cost[mode] + shift_cost[mode][m];
- if (shiftadd_cost[mode][m] < cost)
- cost = shiftadd_cost[mode][m];
- synth_mult (alg_in, t / d, cost_limit - cost, mode);
+ /* If the target has a cheap shift-and-add instruction use
+ that in preference to a shift insn followed by an add insn.
+ Assume that the shift-and-add is "atomic" with a latency
+ equal to its cost, otherwise assume that on superscalar
+ hardware the shift may be executed concurrently with the
+ earlier steps in the algorithm. */
+ op_cost = add_cost[mode] + shift_cost[mode][m];
+ if (shiftadd_cost[mode][m] < op_cost)
+ {
+ op_cost = shiftadd_cost[mode][m];
+ op_latency = op_cost;
+ }
+ else
+ op_latency = add_cost[mode];
- cost += alg_in->cost;
- if (cost < cost_limit)
+ new_limit.cost = best_cost.cost - op_cost;
+ new_limit.latency = best_cost.latency - op_latency;
+ synth_mult (alg_in, t / d, &new_limit, mode);
+
+ alg_in->cost.cost += op_cost;
+ alg_in->cost.latency += op_latency;
+ if (alg_in->cost.latency < op_cost)
+ alg_in->cost.latency = op_cost;
+ if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
{
struct algorithm *x;
+ best_cost = alg_in->cost;
x = alg_in, alg_in = best_alg, best_alg = x;
best_alg->log[best_alg->ops] = m;
best_alg->op[best_alg->ops] = alg_add_factor;
- cost_limit = cost;
}
/* Other factors will have been taken care of in the recursion. */
break;
}
d = ((unsigned HOST_WIDE_INT) 1 << m) - 1;
- if (t % d == 0 && t > d && m < maxm)
+ if (t % d == 0 && t > d && m < maxm
+ && (!cache_hit || cache_alg == alg_sub_factor))
{
- cost = add_cost[mode] + shift_cost[mode][m];
- if (shiftsub_cost[mode][m] < cost)
- cost = shiftsub_cost[mode][m];
- synth_mult (alg_in, t / d, cost_limit - cost, mode);
+ /* If the target has a cheap shift-and-subtract insn use
+ that in preference to a shift insn followed by a sub insn.
+ Assume that the shift-and-sub is "atomic" with a latency
+ equal to it's cost, otherwise assume that on superscalar
+ hardware the shift may be executed concurrently with the
+ earlier steps in the algorithm. */
+ op_cost = add_cost[mode] + shift_cost[mode][m];
+ if (shiftsub_cost[mode][m] < op_cost)
+ {
+ op_cost = shiftsub_cost[mode][m];
+ op_latency = op_cost;
+ }
+ else
+ op_latency = add_cost[mode];
+
+ new_limit.cost = best_cost.cost - op_cost;
+ new_limit.latency = best_cost.latency - op_latency;
+ synth_mult (alg_in, t / d, &new_limit, mode);
- cost += alg_in->cost;
- if (cost < cost_limit)
+ alg_in->cost.cost += op_cost;
+ alg_in->cost.latency += op_latency;
+ if (alg_in->cost.latency < op_cost)
+ alg_in->cost.latency = op_cost;
+ if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
{
struct algorithm *x;
+ best_cost = alg_in->cost;
x = alg_in, alg_in = best_alg, best_alg = x;
best_alg->log[best_alg->ops] = m;
best_alg->op[best_alg->ops] = alg_sub_factor;
- cost_limit = cost;
}
break;
}
}
+ if (cache_hit)
+ goto done;
/* Try shift-and-add (load effective address) instructions,
i.e. do a*3, a*5, a*9. */
if ((t & 1) != 0)
{
+ do_alg_add_t2_m:
q = t - 1;
q = q & -q;
m = exact_log2 (q);
if (m >= 0 && m < maxm)
{
- cost = shiftadd_cost[mode][m];
- synth_mult (alg_in, (t - 1) >> m, cost_limit - cost, mode);
-
- cost += alg_in->cost;
- if (cost < cost_limit)
+ op_cost = shiftadd_cost[mode][m];
+ new_limit.cost = best_cost.cost - op_cost;
+ new_limit.latency = best_cost.latency - op_cost;
+ synth_mult (alg_in, (t - 1) >> m, &new_limit, mode);
+
+ alg_in->cost.cost += op_cost;
+ alg_in->cost.latency += op_cost;
+ if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
{
struct algorithm *x;
+ best_cost = alg_in->cost;
x = alg_in, alg_in = best_alg, best_alg = x;
best_alg->log[best_alg->ops] = m;
best_alg->op[best_alg->ops] = alg_add_t2_m;
- cost_limit = cost;
}
}
+ if (cache_hit)
+ goto done;
+ do_alg_sub_t2_m:
q = t + 1;
q = q & -q;
m = exact_log2 (q);
if (m >= 0 && m < maxm)
{
- cost = shiftsub_cost[mode][m];
- synth_mult (alg_in, (t + 1) >> m, cost_limit - cost, mode);
-
- cost += alg_in->cost;
- if (cost < cost_limit)
+ op_cost = shiftsub_cost[mode][m];
+ new_limit.cost = best_cost.cost - op_cost;
+ new_limit.latency = best_cost.latency - op_cost;
+ synth_mult (alg_in, (t + 1) >> m, &new_limit, mode);
+
+ alg_in->cost.cost += op_cost;
+ alg_in->cost.latency += op_cost;
+ if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
{
struct algorithm *x;
+ best_cost = alg_in->cost;
x = alg_in, alg_in = best_alg, best_alg = x;
best_alg->log[best_alg->ops] = m;
best_alg->op[best_alg->ops] = alg_sub_t2_m;
- cost_limit = cost;
}
}
+ if (cache_hit)
+ goto done;
}
- /* If cost_limit has not decreased since we stored it in alg_out->cost,
- we have not found any algorithm. */
- if (cost_limit == alg_out->cost)
+ done:
+ /* If best_cost has not decreased, we have not found any algorithm. */
+ if (!CHEAPER_MULT_COST (&best_cost, cost_limit))
return;
+ /* Cache the result. */
+ if (!cache_hit)
+ {
+ alg_hash[hash_index].t = t;
+ alg_hash[hash_index].mode = mode;
+ alg_hash[hash_index].alg = best_alg->op[best_alg->ops];
+ }
+
/* If we are getting a too long sequence for `struct algorithm'
to record, make this search fail. */
if (best_alg->ops == MAX_BITS_PER_WORD)
We avoid using structure assignment because the majority of
best_alg is normally undefined, and this is a critical function. */
alg_out->ops = best_alg->ops + 1;
- alg_out->cost = cost_limit;
+ alg_out->cost = best_cost;
memcpy (alg_out->op, best_alg->op,
alg_out->ops * sizeof *alg_out->op);
memcpy (alg_out->log, best_alg->log,
int mult_cost)
{
struct algorithm alg2;
+ struct mult_cost limit;
+ int op_cost;
*variant = basic_variant;
- synth_mult (alg, val, mult_cost, mode);
+ limit.cost = mult_cost;
+ limit.latency = mult_cost;
+ synth_mult (alg, val, &limit, mode);
/* This works only if the inverted value actually fits in an
`unsigned int' */
if (HOST_BITS_PER_INT >= GET_MODE_BITSIZE (mode))
{
- synth_mult (&alg2, -val, MIN (alg->cost, mult_cost) - neg_cost[mode],
- mode);
- alg2.cost += neg_cost[mode];
- if (alg2.cost < alg->cost)
+ op_cost = neg_cost[mode];
+ if (MULT_COST_LESS (&alg->cost, mult_cost))
+ {
+ limit.cost = alg->cost.cost - op_cost;
+ limit.latency = alg->cost.latency - op_cost;
+ }
+ else
+ {
+ limit.cost = mult_cost - op_cost;
+ limit.latency = mult_cost - op_cost;
+ }
+
+ synth_mult (&alg2, -val, &limit, mode);
+ alg2.cost.cost += op_cost;
+ alg2.cost.latency += op_cost;
+ if (CHEAPER_MULT_COST (&alg2.cost, &alg->cost))
*alg = alg2, *variant = negate_variant;
}
/* This proves very useful for division-by-constant. */
- synth_mult (&alg2, val - 1, MIN (alg->cost, mult_cost) - add_cost[mode],
- mode);
- alg2.cost += add_cost[mode];
- if (alg2.cost < alg->cost)
+ op_cost = add_cost[mode];
+ if (MULT_COST_LESS (&alg->cost, mult_cost))
+ {
+ limit.cost = alg->cost.cost - op_cost;
+ limit.latency = alg->cost.latency - op_cost;
+ }
+ else
+ {
+ limit.cost = mult_cost - op_cost;
+ limit.latency = mult_cost - op_cost;
+ }
+
+ synth_mult (&alg2, val - 1, &limit, mode);
+ alg2.cost.cost += op_cost;
+ alg2.cost.latency += op_cost;
+ if (CHEAPER_MULT_COST (&alg2.cost, &alg->cost))
*alg = alg2, *variant = add_variant;
- return alg->cost < mult_cost;
+ return MULT_COST_LESS (&alg->cost, mult_cost);
}
/* A subroutine of expand_mult, used for constant multiplications.
val_so_far = 1;
}
else
- abort ();
+ gcc_unreachable ();
for (opno = 1; opno < alg->ops; opno++)
{
{
case alg_shift:
accum = expand_shift (LSHIFT_EXPR, mode, accum,
- build_int_cst (NULL_TREE, log, 0),
+ build_int_cst (NULL_TREE, log),
NULL_RTX, 0);
val_so_far <<= log;
break;
case alg_add_t_m2:
tem = expand_shift (LSHIFT_EXPR, mode, op0,
- build_int_cst (NULL_TREE, log, 0),
+ build_int_cst (NULL_TREE, log),
NULL_RTX, 0);
accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
add_target ? add_target : accum_target);
case alg_sub_t_m2:
tem = expand_shift (LSHIFT_EXPR, mode, op0,
- build_int_cst (NULL_TREE, log, 0),
+ build_int_cst (NULL_TREE, log),
NULL_RTX, 0);
accum = force_operand (gen_rtx_MINUS (mode, accum, tem),
add_target ? add_target : accum_target);
case alg_add_t2_m:
accum = expand_shift (LSHIFT_EXPR, mode, accum,
- build_int_cst (NULL_TREE, log, 0),
+ build_int_cst (NULL_TREE, log),
shift_subtarget,
0);
accum = force_operand (gen_rtx_PLUS (mode, accum, op0),
case alg_sub_t2_m:
accum = expand_shift (LSHIFT_EXPR, mode, accum,
- build_int_cst (NULL_TREE, log, 0),
+ build_int_cst (NULL_TREE, log),
shift_subtarget, 0);
accum = force_operand (gen_rtx_MINUS (mode, accum, op0),
add_target ? add_target : accum_target);
case alg_add_factor:
tem = expand_shift (LSHIFT_EXPR, mode, accum,
- build_int_cst (NULL_TREE, log, 0),
+ build_int_cst (NULL_TREE, log),
NULL_RTX, 0);
accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
add_target ? add_target : accum_target);
case alg_sub_factor:
tem = expand_shift (LSHIFT_EXPR, mode, accum,
- build_int_cst (NULL_TREE, log, 0),
+ build_int_cst (NULL_TREE, log),
NULL_RTX, 0);
accum = force_operand (gen_rtx_MINUS (mode, tem, accum),
(add_target
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* Write a REG_EQUAL note on the last insn so that we can cse
in the result mode, to avoid sign-/zero-extension confusion. */
val &= GET_MODE_MASK (mode);
val_so_far &= GET_MODE_MASK (mode);
- if (val != val_so_far)
- abort ();
+ gcc_assert (val == val_so_far);
return accum;
}
if (const_op1 && GET_CODE (const_op1) == CONST_INT
&& (unsignedp || !flag_trapv))
{
- int mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+ HOST_WIDE_INT coeff = INTVAL (const_op1);
+ int mult_cost;
+
+ /* Special case powers of two. */
+ if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+ {
+ if (coeff == 0)
+ return const0_rtx;
+ if (coeff == 1)
+ return op0;
+ return expand_shift (LSHIFT_EXPR, mode, op0,
+ build_int_cst (NULL_TREE, floor_log2 (coeff)),
+ target, unsignedp);
+ }
- if (choose_mult_variant (mode, INTVAL (const_op1), &algorithm, &variant,
+ mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+ if (choose_mult_variant (mode, coeff, &algorithm, &variant,
mult_cost))
- return expand_mult_const (mode, op0, INTVAL (const_op1), target,
+ return expand_mult_const (mode, op0, coeff, target,
&algorithm, variant);
}
&& flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
? smulv_optab : smul_optab,
op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
- if (op0 == 0)
- abort ();
+ gcc_assert (op0);
return op0;
}
\f
static
unsigned HOST_WIDE_INT
choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
- unsigned HOST_WIDE_INT *multiplier_ptr,
- int *post_shift_ptr, int *lgup_ptr)
+ rtx *multiplier_ptr, int *post_shift_ptr, int *lgup_ptr)
{
HOST_WIDE_INT mhigh_hi, mlow_hi;
unsigned HOST_WIDE_INT mhigh_lo, mlow_lo;
/* lgup = ceil(log2(divisor)); */
lgup = ceil_log2 (d);
- if (lgup > n)
- abort ();
+ gcc_assert (lgup <= n);
pow = n + lgup;
pow2 = n + lgup - precision;
- if (pow == 2 * HOST_BITS_PER_WIDE_INT)
- {
- /* 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. */
- abort ();
- }
+ /* 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 != 2 * HOST_BITS_PER_WIDE_INT);
/* mlow = 2^(N + lgup)/d */
if (pow >= HOST_BITS_PER_WIDE_INT)
div_and_round_double (TRUNC_DIV_EXPR, 1, nl, nh, d, (HOST_WIDE_INT) 0,
&mhigh_lo, &mhigh_hi, &dummy1, &dummy2);
- if (mhigh_hi && nh - d >= d)
- abort ();
- if (mhigh_hi > 1 || mlow_hi > 1)
- abort ();
+ gcc_assert (!mhigh_hi || nh - d < d);
+ gcc_assert (mhigh_hi <= 1 && mlow_hi <= 1);
/* Assert that mlow < mhigh. */
- if (! (mlow_hi < mhigh_hi || (mlow_hi == mhigh_hi && mlow_lo < mhigh_lo)))
- abort ();
+ gcc_assert (mlow_hi < mhigh_hi
+ || (mlow_hi == mhigh_hi && mlow_lo < mhigh_lo));
/* If precision == N, then mlow, mhigh exceed 2^N
(but they do not exceed 2^(N+1)). */
if (n < HOST_BITS_PER_WIDE_INT)
{
unsigned HOST_WIDE_INT mask = ((unsigned HOST_WIDE_INT) 1 << n) - 1;
- *multiplier_ptr = mhigh_lo & mask;
+ *multiplier_ptr = GEN_INT (mhigh_lo & mask);
return mhigh_lo >= mask;
}
else
{
- *multiplier_ptr = mhigh_lo;
+ *multiplier_ptr = GEN_INT (mhigh_lo);
return mhigh_hi;
}
}
enum rtx_code adj_code = unsignedp ? PLUS : MINUS;
tem = expand_shift (RSHIFT_EXPR, mode, op0,
- build_int_cst (NULL_TREE,
- GET_MODE_BITSIZE (mode) - 1, 0),
+ build_int_cst (NULL_TREE, GET_MODE_BITSIZE (mode) - 1),
NULL_RTX, 0);
tem = expand_and (mode, tem, op1, NULL_RTX);
adj_operand
adj_operand);
tem = expand_shift (RSHIFT_EXPR, mode, op1,
- build_int_cst (NULL_TREE,
- GET_MODE_BITSIZE (mode) - 1, 0),
+ build_int_cst (NULL_TREE, GET_MODE_BITSIZE (mode) - 1),
NULL_RTX, 0);
tem = expand_and (mode, tem, op0, NULL_RTX);
target = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
wider_mode = GET_MODE_WIDER_MODE (mode);
op = expand_shift (RSHIFT_EXPR, wider_mode, op,
- build_int_cst (NULL_TREE,
- GET_MODE_BITSIZE (mode), 0), 0, 1);
+ build_int_cst (NULL_TREE, GET_MODE_BITSIZE (mode)), 0, 1);
return convert_modes (mode, wider_mode, op, 0);
}
}
/* Try widening the mode and perform a non-widening multiplication. */
- moptab = smul_optab;
if (smul_optab->handlers[wider_mode].insn_code != CODE_FOR_nothing
&& size - 1 < BITS_PER_WORD
&& mul_cost[wider_mode] + shift_cost[mode][size-1] < max_cost)
{
- tem = expand_binop (wider_mode, moptab, op0, op1, 0,
+ rtx insns, wop0, wop1;
+
+ /* We need to widen the operands, for example to ensure the
+ constant multiplier is correctly sign or zero extended.
+ Use a sequence to clean-up any instructions emitted by
+ the conversions if things don't work out. */
+ start_sequence ();
+ wop0 = convert_modes (wider_mode, mode, op0, unsignedp);
+ wop1 = convert_modes (wider_mode, mode, op1, unsignedp);
+ tem = expand_binop (wider_mode, smul_optab, wop0, wop1, 0,
unsignedp, OPTAB_WIDEN);
+ insns = get_insns ();
+ end_sequence ();
+
if (tem)
- return extract_high_half (mode, tem);
+ {
+ emit_insn (insns);
+ return extract_high_half (mode, tem);
+ }
}
/* Try widening multiplication of opposite signedness, and adjust. */
return 0;
}
-/* Emit code to multiply OP0 and CNST1, putting the high half of the result
- in TARGET if that is convenient, and return where the result is. If the
- operation can not be performed, 0 is returned.
+/* Emit code to multiply OP0 and OP1 (where OP1 is an integer constant),
+ putting the high half of the result in TARGET if that is convenient,
+ and return where the result is. If the operation can not be performed,
+ 0 is returned.
MODE is the mode of operation and result.
MAX_COST is the total allowed cost for the expanded RTL. */
-rtx
-expand_mult_highpart (enum machine_mode mode, rtx op0,
- unsigned HOST_WIDE_INT cnst1, rtx target,
- int unsignedp, int max_cost)
+static rtx
+expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
+ rtx target, int unsignedp, int max_cost)
{
enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
+ unsigned HOST_WIDE_INT cnst1;
int extra_cost;
bool sign_adjust = false;
enum mult_variant variant;
struct algorithm alg;
- rtx op1, tem;
+ rtx tem;
/* We can't support modes wider than HOST_BITS_PER_INT. */
- if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
- abort ();
+ gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT);
- op1 = gen_int_mode (cnst1, wider_mode);
- cnst1 &= GET_MODE_MASK (mode);
+ cnst1 = INTVAL (op1) & GET_MODE_MASK (mode);
/* We can't optimize modes wider than BITS_PER_WORD.
??? We might be able to perform double-word arithmetic if
{
/* See whether the specialized multiplication optabs are
cheaper than the shift/add version. */
- tem = expand_mult_highpart_optab (mode, op0, op1, target,
- unsignedp, alg.cost + extra_cost);
+ tem = expand_mult_highpart_optab (mode, op0, op1, target, unsignedp,
+ alg.cost.cost + extra_cost);
if (tem)
return tem;
static rtx
expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
{
- unsigned HOST_WIDE_INT mask;
+ unsigned HOST_WIDE_INT masklow, maskhigh;
rtx result, temp, shift, label;
int logd;
if (signmask)
{
signmask = force_reg (mode, signmask);
- mask = ((HOST_WIDE_INT) 1 << logd) - 1;
+ 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
which instruction sequence to use. If logical right shifts
are expensive the use 2 XORs, 2 SUBs and an AND, otherwise
use a LSHIFTRT, 1 ADD, 1 SUB and an AND. */
-
+
temp = gen_rtx_LSHIFTRT (mode, result, shift);
if (lshr_optab->handlers[mode].insn_code == CODE_FOR_nothing
|| rtx_cost (temp, SET) > COSTS_N_INSNS (2))
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 (mask),
+ temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
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 (mask),
+ temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, sub_optab, temp, signmask,
NULL_RTX, 1, OPTAB_LIB_WIDEN);
can avoid an explicit compare operation in the following comparison
against zero. */
- mask = (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1)
- | (((HOST_WIDE_INT) 1 << logd) - 1);
+ 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);
- temp = expand_binop (mode, and_optab, op0, GEN_INT (mask), result,
- 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, and_optab, op0,
+ immed_double_const (masklow, maskhigh, 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);
- mask = (HOST_WIDE_INT) -1 << logd;
- temp = expand_binop (mode, ior_optab, temp, GEN_INT (mask), result,
- 1, OPTAB_LIB_WIDEN);
+ masklow = (HOST_WIDE_INT) -1 << logd;
+ maskhigh = -1;
+ temp = expand_binop (mode, ior_optab, temp,
+ immed_double_const (masklow, maskhigh, mode),
+ result, 1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
0, OPTAB_LIB_WIDEN);
if (temp != result)
int logd;
logd = floor_log2 (d);
- shift = build_int_cst (NULL_TREE, logd, 0);
+ shift = build_int_cst (NULL_TREE, logd);
if (d == 2 && BRANCH_COST >= 1)
{
{
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),
NULL_RTX, 0, OPTAB_LIB_WIDEN);
else
temp = expand_shift (RSHIFT_EXPR, mode, temp,
- build_int_cst (NULL_TREE, ushift, 0),
+ build_int_cst (NULL_TREE, ushift),
NULL_RTX, 1);
temp = expand_binop (mode, add_optab, temp, op0, NULL_RTX,
0, OPTAB_LIB_WIDEN);
(x mod 12) == (((x & 1023) + ((x >> 8) & ~3)) * 0x15555558 >> 2 * 3) >> 28
*/
-#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
-
rtx
expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
rtx op0, rtx op1, rtx target, int unsignedp)
{
if (unsignedp)
{
- unsigned HOST_WIDE_INT mh, ml;
+ unsigned HOST_WIDE_INT mh;
int pre_shift, post_shift;
int dummy;
+ rtx ml;
unsigned HOST_WIDE_INT d = (INTVAL (op1)
& GET_MODE_MASK (compute_mode));
}
quotient = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_cst (NULL_TREE,
- pre_shift, 0),
+ pre_shift),
tquotient, 1);
}
else if (size <= HOST_BITS_PER_WIDE_INT)
mh = choose_multiplier (d >> pre_shift, size,
size - pre_shift,
&ml, &post_shift, &dummy);
- if (mh)
- abort ();
+ gcc_assert (!mh);
}
else
pre_shift = 0;
NULL_RTX);
t3 = expand_shift
(RSHIFT_EXPR, compute_mode, t2,
- build_int_cst (NULL_TREE, 1, 0),
+ build_int_cst (NULL_TREE, 1),
NULL_RTX,1);
t4 = force_operand (gen_rtx_PLUS (compute_mode,
t1, t3),
NULL_RTX);
quotient = expand_shift
(RSHIFT_EXPR, compute_mode, t4,
- build_int_cst (NULL_TREE,
- post_shift - 1, 0),
+ build_int_cst (NULL_TREE, post_shift - 1),
tquotient, 1);
}
else
t1 = expand_shift
(RSHIFT_EXPR, compute_mode, op0,
- build_int_cst (NULL_TREE, pre_shift, 0),
+ build_int_cst (NULL_TREE, pre_shift),
NULL_RTX, 1);
extra_cost
= (shift_cost[compute_mode][pre_shift]
goto fail1;
quotient = expand_shift
(RSHIFT_EXPR, compute_mode, t2,
- build_int_cst (NULL_TREE,
- post_shift, 0),
+ build_int_cst (NULL_TREE, post_shift),
tquotient, 1);
}
}
{
unsigned HOST_WIDE_INT ml;
int lgup, post_shift;
+ rtx mlr;
HOST_WIDE_INT d = INTVAL (op1);
unsigned HOST_WIDE_INT abs_d = d >= 0 ? d : -d;
if (remainder)
return gen_lowpart (mode, remainder);
}
- quotient = expand_sdiv_pow2 (compute_mode, op0, abs_d);
+
+ if (sdiv_pow2_cheap[compute_mode]
+ && ((sdiv_optab->handlers[compute_mode].insn_code
+ != CODE_FOR_nothing)
+ || (sdivmod_optab->handlers[compute_mode].insn_code
+ != CODE_FOR_nothing)))
+ quotient = expand_divmod (0, TRUNC_DIV_EXPR,
+ compute_mode, op0,
+ gen_int_mode (abs_d,
+ compute_mode),
+ NULL_RTX, 0);
+ else
+ quotient = expand_sdiv_pow2 (compute_mode, op0, abs_d);
/* We have computed OP0 / abs(OP1). If OP1 is negative,
negate the quotient. */
else if (size <= HOST_BITS_PER_WIDE_INT)
{
choose_multiplier (abs_d, size, size - 1,
- &ml, &post_shift, &lgup);
+ &mlr, &post_shift, &lgup);
+ ml = (unsigned HOST_WIDE_INT) INTVAL (mlr);
if (ml < (unsigned HOST_WIDE_INT) 1 << (size - 1))
{
rtx t1, t2, t3;
extra_cost = (shift_cost[compute_mode][post_shift]
+ shift_cost[compute_mode][size - 1]
+ add_cost[compute_mode]);
- t1 = expand_mult_highpart (compute_mode, op0, ml,
+ t1 = expand_mult_highpart (compute_mode, op0, mlr,
NULL_RTX, 0,
max_cost - extra_cost);
if (t1 == 0)
goto fail1;
t2 = expand_shift
(RSHIFT_EXPR, compute_mode, t1,
- build_int_cst (NULL_TREE, post_shift, 0),
+ build_int_cst (NULL_TREE, post_shift),
NULL_RTX, 0);
t3 = expand_shift
(RSHIFT_EXPR, compute_mode, op0,
- build_int_cst (NULL_TREE, size - 1, 0),
+ build_int_cst (NULL_TREE, size - 1),
NULL_RTX, 0);
if (d < 0)
quotient
goto fail1;
ml |= (~(unsigned HOST_WIDE_INT) 0) << (size - 1);
+ mlr = gen_int_mode (ml, compute_mode);
extra_cost = (shift_cost[compute_mode][post_shift]
+ shift_cost[compute_mode][size - 1]
+ 2 * add_cost[compute_mode]);
- t1 = expand_mult_highpart (compute_mode, op0, ml,
+ t1 = expand_mult_highpart (compute_mode, op0, mlr,
NULL_RTX, 0,
max_cost - extra_cost);
if (t1 == 0)
NULL_RTX);
t3 = expand_shift
(RSHIFT_EXPR, compute_mode, t2,
- build_int_cst (NULL_TREE, post_shift, 0),
+ build_int_cst (NULL_TREE, post_shift),
NULL_RTX, 0);
t4 = expand_shift
(RSHIFT_EXPR, compute_mode, op0,
- build_int_cst (NULL_TREE, size - 1, 0),
+ build_int_cst (NULL_TREE, size - 1),
NULL_RTX, 0);
if (d < 0)
quotient
/* We will come here only for signed operations. */
if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size)
{
- unsigned HOST_WIDE_INT mh, ml;
+ unsigned HOST_WIDE_INT mh;
int pre_shift, lgup, post_shift;
HOST_WIDE_INT d = INTVAL (op1);
+ rtx ml;
if (d > 0)
{
}
quotient = expand_shift
(RSHIFT_EXPR, compute_mode, op0,
- build_int_cst (NULL_TREE, pre_shift, 0),
+ build_int_cst (NULL_TREE, pre_shift),
tquotient, 0);
}
else
mh = choose_multiplier (d, size, size - 1,
&ml, &post_shift, &lgup);
- if (mh)
- abort ();
+ gcc_assert (!mh);
if (post_shift < BITS_PER_WORD
&& size - 1 < BITS_PER_WORD)
{
t1 = expand_shift
(RSHIFT_EXPR, compute_mode, op0,
- build_int_cst (NULL_TREE, size - 1, 0),
+ build_int_cst (NULL_TREE, size - 1),
NULL_RTX, 0);
t2 = expand_binop (compute_mode, xor_optab, op0, t1,
NULL_RTX, 0, OPTAB_WIDEN);
{
t4 = expand_shift
(RSHIFT_EXPR, compute_mode, t3,
- build_int_cst (NULL_TREE, post_shift, 0),
+ build_int_cst (NULL_TREE, post_shift),
NULL_RTX, 1);
quotient = expand_binop (compute_mode, xor_optab,
t4, t1, tquotient, 0,
0, OPTAB_WIDEN);
nsign = expand_shift
(RSHIFT_EXPR, compute_mode, t2,
- build_int_cst (NULL_TREE, size - 1, 0),
+ build_int_cst (NULL_TREE, size - 1),
NULL_RTX, 0);
t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
NULL_RTX);
rtx t1, t2, t3;
unsigned HOST_WIDE_INT d = INTVAL (op1);
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
- build_int_cst (NULL_TREE,
- floor_log2 (d), 0),
+ build_int_cst (NULL_TREE, floor_log2 (d)),
tquotient, 1);
t2 = expand_binop (compute_mode, and_optab, op0,
GEN_INT (d - 1),
rtx t1, t2, t3;
unsigned HOST_WIDE_INT d = INTVAL (op1);
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
- build_int_cst (NULL_TREE,
- floor_log2 (d), 0),
+ build_int_cst (NULL_TREE, floor_log2 (d)),
tquotient, 0);
t2 = expand_binop (compute_mode, and_optab, op0,
GEN_INT (d - 1),
pre_shift = floor_log2 (d & -d);
ml = invert_mod2n (d >> pre_shift, size);
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
- build_int_cst (NULL_TREE, pre_shift, 0),
+ build_int_cst (NULL_TREE, pre_shift),
NULL_RTX, unsignedp);
quotient = expand_mult (compute_mode, t1,
gen_int_mode (ml, compute_mode),
}
tem = plus_constant (op1, -1);
tem = expand_shift (RSHIFT_EXPR, compute_mode, tem,
- build_int_cst (NULL_TREE, 1, 0),
+ build_int_cst (NULL_TREE, 1),
NULL_RTX, 1);
do_cmp_and_jump (remainder, tem, LEU, compute_mode, label);
expand_inc (quotient, const1_rtx);
abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 1, 0);
abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 1, 0);
tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
- build_int_cst (NULL_TREE, 1, 0),
+ build_int_cst (NULL_TREE, 1),
NULL_RTX, 1);
do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label);
tem = expand_binop (compute_mode, xor_optab, op0, op1,
NULL_RTX, 0, OPTAB_WIDEN);
mask = expand_shift (RSHIFT_EXPR, compute_mode, tem,
- build_int_cst (NULL_TREE, size - 1, 0),
+ build_int_cst (NULL_TREE, size - 1),
NULL_RTX, 0);
tem = expand_binop (compute_mode, xor_optab, mask, const1_rtx,
NULL_RTX, 0, OPTAB_WIDEN);
return gen_lowpart (mode, rem_flag ? remainder : quotient);
default:
- abort ();
+ gcc_unreachable ();
}
if (quotient == 0)
< HOST_BITS_PER_WIDE_INT)))
hi = -1;
- t = build_int_cst (type, INTVAL (x), hi);
+ t = build_int_cst_wide (type, INTVAL (x), hi);
return t;
}
case CONST_DOUBLE:
if (GET_MODE (x) == VOIDmode)
- t = build_int_cst (type, CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
+ t = build_int_cst_wide (type,
+ CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
else
{
REAL_VALUE_TYPE d;
case LSHIFTRT:
t = lang_hooks.types.unsigned_type (type);
- return fold (convert (type,
- build2 (RSHIFT_EXPR, t,
- make_tree (t, XEXP (x, 0)),
- make_tree (type, XEXP (x, 1)))));
+ return fold_convert (type, build2 (RSHIFT_EXPR, t,
+ make_tree (t, XEXP (x, 0)),
+ make_tree (type, XEXP (x, 1))));
case ASHIFTRT:
t = lang_hooks.types.signed_type (type);
- return fold (convert (type,
- build2 (RSHIFT_EXPR, t,
- make_tree (t, XEXP (x, 0)),
- make_tree (type, XEXP (x, 1)))));
+ return fold_convert (type, build2 (RSHIFT_EXPR, t,
+ make_tree (t, XEXP (x, 0)),
+ make_tree (type, XEXP (x, 1))));
case DIV:
if (TREE_CODE (type) != REAL_TYPE)
else
t = type;
- return fold (convert (type,
- build2 (TRUNC_DIV_EXPR, t,
- make_tree (t, XEXP (x, 0)),
- make_tree (t, XEXP (x, 1)))));
+ return fold_convert (type, build2 (TRUNC_DIV_EXPR, t,
+ make_tree (t, XEXP (x, 0)),
+ make_tree (t, XEXP (x, 1))));
case UDIV:
t = lang_hooks.types.unsigned_type (type);
- return fold (convert (type,
- build2 (TRUNC_DIV_EXPR, t,
- make_tree (t, XEXP (x, 0)),
- make_tree (t, XEXP (x, 1)))));
+ return fold_convert (type, build2 (TRUNC_DIV_EXPR, t,
+ make_tree (t, XEXP (x, 0)),
+ make_tree (t, XEXP (x, 1))));
case SIGN_EXTEND:
case ZERO_EXTEND:
t = lang_hooks.types.type_for_mode (GET_MODE (XEXP (x, 0)),
GET_CODE (x) == ZERO_EXTEND);
- return fold (convert (type, make_tree (t, XEXP (x, 0))));
+ return fold_convert (type, make_tree (t, XEXP (x, 0)));
default:
t = build_decl (VAR_DECL, NULL_TREE, type);
UNSIGNEDP is nonzero to do unsigned multiplication. */
bool
-const_mult_add_overflow_p (rtx x, rtx mult, rtx add, enum machine_mode mode, int unsignedp)
+const_mult_add_overflow_p (rtx x, rtx mult, rtx add,
+ enum machine_mode mode, int unsignedp)
{
tree type, mult_type, add_type, result;
mult_type = type;
if (unsignedp)
{
- mult_type = copy_node (type);
+ /* FIXME:It would be nice if we could step directly from this
+ type to its sizetype equivalent. */
+ mult_type = build_distinct_type_copy (type);
TYPE_IS_SIZETYPE (mult_type) = 1;
}
= compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX);
if (CONSTANT_P (comparison))
{
- if (GET_CODE (comparison) == CONST_INT)
+ switch (GET_CODE (comparison))
{
+ case CONST_INT:
if (comparison == const0_rtx)
return const0_rtx;
- }
+ break;
+
#ifdef FLOAT_STORE_FLAG_VALUE
- else if (GET_CODE (comparison) == CONST_DOUBLE)
- {
+ case CONST_DOUBLE:
if (comparison == CONST0_RTX (GET_MODE (comparison)))
return const0_rtx;
- }
+ break;
#endif
- else
- abort ();
+ default:
+ gcc_unreachable ();
+ }
+
if (normalizep == 1)
return const1_rtx;
if (normalizep == -1)
op0 = expand_shift (RSHIFT_EXPR, compare_mode, op0,
size_int (GET_MODE_BITSIZE (compare_mode) - 1),
subtarget, normalizep == 1);
- else if (STORE_FLAG_VALUE & 1)
+ else
{
+ gcc_assert (STORE_FLAG_VALUE & 1);
+
op0 = expand_and (compare_mode, op0, const1_rtx, subtarget);
if (normalizep == -1)
op0 = expand_unop (compare_mode, neg_optab, op0, op0, 0);
}
- else
- abort ();
/* If we were converting to a smaller mode, do the
conversion now. */
/* do_jump_by_parts_equality_rtx compares with zero. Luckily
that's the only equality operations we do */
case EQ:
- if (arg2 != const0_rtx || mode != GET_MODE(arg1))
- abort ();
+ gcc_assert (arg2 == const0_rtx && mode == GET_MODE(arg1));
do_jump_by_parts_equality_rtx (arg1, label2, label);
break;
case NE:
- if (arg2 != const0_rtx || mode != GET_MODE(arg1))
- abort ();
+ gcc_assert (arg2 == const0_rtx && mode == GET_MODE(arg1));
do_jump_by_parts_equality_rtx (arg1, label, label2);
break;
default:
- abort ();
+ gcc_unreachable ();
}
emit_label (label2);