/* 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.
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;
{
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;
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))
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);
{
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
enum machine_mode imode = int_mode_for_mode (GET_MODE (op0));
if (imode != GET_MODE (op0))
{
- op0 = gen_lowpart (imode, op0);
+ if (MEM_P (op0))
+ op0 = adjust_address (op0, imode, 0);
+ else
+ {
+ 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);
+ /* 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.
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))),
+ = fold (build2 (MINUS_EXPR, type,
+ build_int_cst (type, GET_MODE_BITSIZE (mode)),
amount));
shifted = force_reg (mode, shifted);
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
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;
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;
}
}
}
/* 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. */
{
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));
= (shift_cost[compute_mode][post_shift - 1]
+ shift_cost[compute_mode][1]
+ 2 * add_cost[compute_mode]);
- t1 = gen_int_mode (ml, compute_mode);
- t1 = expand_mult_highpart (compute_mode, op0, t1,
+ t1 = expand_mult_highpart (compute_mode, op0, ml,
NULL_RTX, 1,
max_cost - extra_cost);
if (t1 == 0)
extra_cost
= (shift_cost[compute_mode][pre_shift]
+ shift_cost[compute_mode][post_shift]);
- t2 = gen_int_mode (ml, compute_mode);
- t2 = expand_mult_highpart (compute_mode, t1, t2,
+ t2 = expand_mult_highpart (compute_mode, t1, ml,
NULL_RTX, 1,
max_cost - extra_cost);
if (t2 == 0)
{
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;
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 = gen_int_mode (ml, compute_mode);
- t1 = expand_mult_highpart (compute_mode, op0, t1,
+ t1 = expand_mult_highpart (compute_mode, op0, mlr,
NULL_RTX, 0,
max_cost - extra_cost);
if (t1 == 0)
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 = gen_int_mode (ml, compute_mode);
- t1 = expand_mult_highpart (compute_mode, op0, t1,
+ t1 = expand_mult_highpart (compute_mode, op0, mlr,
NULL_RTX, 0,
max_cost - extra_cost);
if (t1 == 0)
/* 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)
{
extra_cost = (shift_cost[compute_mode][post_shift]
+ shift_cost[compute_mode][size - 1]
+ 2 * add_cost[compute_mode]);
- t3 = gen_int_mode (ml, compute_mode);
- t3 = expand_mult_highpart (compute_mode, t2, t3,
+ t3 = expand_mult_highpart (compute_mode, t2, ml,
NULL_RTX, 1,
max_cost - extra_cost);
if (t3 != 0)
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);