/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "tree.h"
#include "tm_p.h"
#include "flags.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
#include "insn-config.h"
#include "expr.h"
#include "real.h"
meaningful at a much higher level; when structures are copied
between memory and regs, the higher-numbered regs
always get higher addresses. */
- offset += SUBREG_WORD (op0);
+ offset += (SUBREG_BYTE (op0) / UNITS_PER_WORD);
/* We used to adjust BITPOS here, but now we do the whole adjustment
right after the loop. */
op0 = SUBREG_REG (op0);
}
- /* 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));
- if (imode != GET_MODE (op0))
- {
- if (GET_CODE (op0) == MEM)
- op0 = change_address (op0, imode, NULL_RTX);
- else if (imode != BLKmode)
- op0 = gen_lowpart (imode, op0);
- else
- abort ();
- }
- }
-
/* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has.
On a bigendian machine, these are not the same, so convert. */
abort ();
}
if (GET_CODE (op0) == REG)
- op0 = gen_rtx_SUBREG (fieldmode, op0, offset);
+ op0 = gen_rtx_SUBREG (fieldmode, op0,
+ (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ + (offset * UNITS_PER_WORD));
else
op0 = change_address (op0, fieldmode,
plus_constant (XEXP (op0, 0), offset));
return value;
}
+ /* Make sure we are playing with integral modes. Pun with subregs
+ if we aren't. This must come after the entire register case above,
+ 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));
+ if (imode != GET_MODE (op0))
+ {
+ if (GET_CODE (op0) == MEM)
+ op0 = change_address (op0, imode, NULL_RTX);
+ else if (imode != BLKmode)
+ op0 = gen_lowpart (imode, op0);
+ else
+ abort ();
+ }
+ }
+
/* Storing an lsb-aligned field in a register
can be done with a movestrict instruction. */
}
emit_insn (GEN_FCN (icode)
- (gen_rtx_SUBREG (fieldmode, op0, offset), value));
+ (gen_rtx_SUBREG (fieldmode, op0,
+ (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ + (offset * UNITS_PER_WORD)),
+ value));
return value;
}
VOIDmode, because that is what store_field uses to indicate that this
is a bit field, but passing VOIDmode to operand_subword_force will
result in an abort. */
- fieldmode = mode_for_size (nwords * BITS_PER_WORD, MODE_INT, 0);
+ fieldmode = smallest_mode_for_size (nwords * BITS_PER_WORD, MODE_INT);
for (i = 0; i < nwords; i++)
{
abort ();
}
op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
- op0, offset);
+ op0, (offset * UNITS_PER_WORD));
}
offset = 0;
}
if (GET_CODE (xop0) == SUBREG)
/* We can't just change the mode, because this might clobber op0,
and we will need the original value of op0 if insv fails. */
- xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_WORD (xop0));
+ xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
else
value1 = gen_lowpart (maxmode, value1);
}
+ else if (GET_CODE (value) == CONST_INT)
+ value1 = GEN_INT (trunc_int_for_mode (INTVAL (value), maxmode));
else if (!CONSTANT_P (value))
/* Parse phase is supposed to make VALUE's data type
match that of the component reference, which is a type
the current word starting from the base register. */
if (GET_CODE (op0) == SUBREG)
{
- word = operand_subword_force (SUBREG_REG (op0),
- SUBREG_WORD (op0) + offset,
+ int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
+ word = operand_subword_force (SUBREG_REG (op0), word_offset,
GET_MODE (SUBREG_REG (op0)));
offset = 0;
}
int outer_size = GET_MODE_BITSIZE (GET_MODE (op0));
int inner_size = GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)));
- offset += SUBREG_WORD (op0);
+ offset += SUBREG_BYTE (op0) / UNITS_PER_WORD;
inner_size = MIN (inner_size, BITS_PER_WORD);
op0 = SUBREG_REG (op0);
}
+ if (GET_CODE (op0) == REG
+ && mode == GET_MODE (op0)
+ && bitnum == 0
+ && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
+ {
+ /* We're trying to extract a full register from itself. */
+ return op0;
+ }
+
/* Make sure we are playing with integral modes. Pun with subregs
if we aren't. */
{
abort ();
}
if (GET_CODE (op0) == REG)
- op0 = gen_rtx_SUBREG (mode1, op0, offset);
+ op0 = gen_rtx_SUBREG (mode1, op0,
+ (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ + (offset * UNITS_PER_WORD));
else
op0 = change_address (op0, mode1,
plus_constant (XEXP (op0, 0), offset));
if (GET_CODE (op0) != REG)
op0 = copy_to_reg (op0);
op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
- op0, offset);
+ op0, (offset * UNITS_PER_WORD));
}
offset = 0;
}
the current word starting from the base register. */
if (GET_CODE (op0) == SUBREG)
{
- word = operand_subword_force (SUBREG_REG (op0),
- SUBREG_WORD (op0) + offset,
+ int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
+ word = operand_subword_force (SUBREG_REG (op0), word_offset,
GET_MODE (SUBREG_REG (op0)));
offset = 0;
}
op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
% GET_MODE_BITSIZE (mode));
else if (GET_CODE (op1) == SUBREG
- && SUBREG_WORD (op1) == 0)
+ && SUBREG_BYTE (op1) == 0)
op1 = SUBREG_REG (op1);
}
#endif
if ((t & 1) == 0)
{
m = floor_log2 (t & -t); /* m = number of low zero bits */
- q = t >> m;
- cost = shift_cost[m];
- synth_mult (alg_in, q, cost_limit - cost);
-
- cost += alg_in->cost;
- if (cost < cost_limit)
+ if (m < BITS_PER_WORD)
{
- struct algorithm *x;
- 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;
+ q = t >> m;
+ cost = shift_cost[m];
+ synth_mult (alg_in, q, cost_limit - cost);
+
+ cost += alg_in->cost;
+ if (cost < cost_limit)
+ {
+ struct algorithm *x;
+ 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;
+ }
}
}
unsigned HOST_WIDE_INT d;
d = ((unsigned HOST_WIDE_INT) 1 << m) + 1;
- if (t % d == 0 && t > d)
+ if (t % d == 0 && t > d && m < BITS_PER_WORD)
{
cost = MIN (shiftadd_cost[m], add_cost + shift_cost[m]);
synth_mult (alg_in, t / d, cost_limit - cost);
}
d = ((unsigned HOST_WIDE_INT) 1 << m) - 1;
- if (t % d == 0 && t > d)
+ if (t % d == 0 && t > d && m < BITS_PER_WORD)
{
cost = MIN (shiftsub_cost[m], add_cost + shift_cost[m]);
synth_mult (alg_in, t / d, cost_limit - cost);
q = t - 1;
q = q & -q;
m = exact_log2 (q);
- if (m >= 0)
+ if (m >= 0 && m < BITS_PER_WORD)
{
cost = shiftadd_cost[m];
synth_mult (alg_in, (t - 1) >> m, cost_limit - cost);
q = t + 1;
q = q & -q;
m = exact_log2 (q);
- if (m >= 0)
+ if (m >= 0 && m < BITS_PER_WORD)
{
cost = shiftsub_cost[m];
synth_mult (alg_in, (t + 1) >> m, cost_limit - cost);
best_alg is normally undefined, and this is a critical function. */
alg_out->ops = best_alg->ops + 1;
alg_out->cost = cost_limit;
- bcopy ((char *) best_alg->op, (char *) alg_out->op,
- alg_out->ops * sizeof *alg_out->op);
- bcopy ((char *) best_alg->log, (char *) alg_out->log,
- alg_out->ops * sizeof *alg_out->log);
+ memcpy (alg_out->op, best_alg->op,
+ alg_out->ops * sizeof *alg_out->op);
+ memcpy (alg_out->log, best_alg->log,
+ alg_out->ops * sizeof *alg_out->log);
}
\f
/* Perform a multiplication and return an rtx for the result.
/* We found something cheaper than a multiply insn. */
int opno;
rtx accum, tem;
+ enum machine_mode nmode;
op0 = protect_from_queue (op0, 0);
}
/* Write a REG_EQUAL note on the last insn so that we can cse
- multiplication sequences. */
+ multiplication sequences. Note that if ACCUM is a SUBREG,
+ we've set the inner register and must properly indicate
+ that. */
+
+ tem = op0, nmode = mode;
+ if (GET_CODE (accum) == SUBREG)
+ {
+ nmode = GET_MODE (SUBREG_REG (accum));
+ tem = gen_lowpart (nmode, op0);
+ }
insn = get_last_insn ();
set_unique_reg_note (insn,
REG_EQUAL,
- gen_rtx_MULT (mode, op0,
+ gen_rtx_MULT (nmode, tem,
GEN_INT (val_so_far)));
}
if (size > HOST_BITS_PER_WIDE_INT)
abort ();
- op1 = GEN_INT (cnst1);
+ op1 = GEN_INT (trunc_int_for_mode (cnst1, mode));
if (GET_MODE_BITSIZE (wider_mode) <= HOST_BITS_PER_INT)
wide_op1 = op1;
/* Secondly, same as above, but use sign flavor opposite of unsignedp.
Need to adjust the result after the multiplication. */
- if (mul_highpart_cost[(int) mode] + 2 * shift_cost[size-1] + 4 * add_cost < max_cost)
+ if (size - 1 < BITS_PER_WORD
+ && (mul_highpart_cost[(int) mode] + 2 * shift_cost[size-1] + 4 * add_cost
+ < max_cost))
{
mul_highpart_optab = unsignedp ? smul_highpart_optab : umul_highpart_optab;
target = expand_binop (mode, mul_highpart_optab,
/* Try widening the mode and perform a non-widening multiplication. */
moptab = smul_optab;
if (smul_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
+ && size - 1 < BITS_PER_WORD
&& mul_cost[(int) wider_mode] + shift_cost[size-1] < max_cost)
{
op1 = wide_op1;
/* Try widening multiplication of opposite signedness, and adjust. */
moptab = unsignedp ? smul_widen_optab : umul_widen_optab;
if (moptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
+ && size - 1 < BITS_PER_WORD
&& (mul_widen_cost[(int) wider_mode]
+ 2 * shift_cost[size-1] + 4 * add_cost < max_cost))
{
{
rtx t1, t2, t3, t4;
+ if (post_shift - 1 >= BITS_PER_WORD)
+ goto fail1;
+
extra_cost = (shift_cost[post_shift - 1]
+ shift_cost[1] + 2 * add_cost);
t1 = expand_mult_highpart (compute_mode, op0, ml,
{
rtx t1, t2;
+ if (pre_shift >= BITS_PER_WORD
+ || post_shift >= BITS_PER_WORD)
+ goto fail1;
+
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_2 (pre_shift, 0),
NULL_RTX, 1);
if (rem_flag && d < 0)
{
d = abs_d;
- op1 = GEN_INT (abs_d);
+ op1 = GEN_INT (trunc_int_for_mode (abs_d, compute_mode));
}
if (d == 1)
else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d))
{
lgup = floor_log2 (abs_d);
- if (abs_d != 2 && BRANCH_COST < 3)
+ if (BRANCH_COST < 1 || (abs_d != 2 && BRANCH_COST < 3))
{
rtx label = gen_label_rtx ();
rtx t1;
t1 = copy_to_mode_reg (compute_mode, op0);
do_cmp_and_jump (t1, const0_rtx, GE,
compute_mode, label);
- expand_inc (t1, GEN_INT (abs_d - 1));
+ expand_inc (t1, GEN_INT (trunc_int_for_mode
+ (abs_d - 1, compute_mode)));
emit_label (label);
quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
build_int_2 (lgup, 0),
REG_EQUAL,
gen_rtx_DIV (compute_mode,
op0,
- GEN_INT (abs_d)));
+ GEN_INT
+ (trunc_int_for_mode
+ (abs_d,
+ compute_mode))));
quotient = expand_unop (compute_mode, neg_optab,
quotient, quotient, 0);
{
rtx t1, t2, t3;
+ if (post_shift >= BITS_PER_WORD
+ || size - 1 >= BITS_PER_WORD)
+ goto fail1;
+
extra_cost = (shift_cost[post_shift]
+ shift_cost[size - 1] + add_cost);
t1 = expand_mult_highpart (compute_mode, op0, ml,
{
rtx t1, t2, t3, t4;
+ if (post_shift >= BITS_PER_WORD
+ || size - 1 >= BITS_PER_WORD)
+ goto fail1;
+
ml |= (~(unsigned HOST_WIDE_INT) 0) << (size - 1);
extra_cost = (shift_cost[post_shift]
+ shift_cost[size - 1] + 2 * add_cost);
if (mh)
abort ();
- t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
- build_int_2 (size - 1, 0), NULL_RTX, 0);
- t2 = expand_binop (compute_mode, xor_optab, op0, t1,
- NULL_RTX, 0, OPTAB_WIDEN);
- extra_cost = (shift_cost[post_shift]
- + shift_cost[size - 1] + 2 * add_cost);
- t3 = expand_mult_highpart (compute_mode, t2, ml,
- NULL_RTX, 1,
- max_cost - extra_cost);
- if (t3 != 0)
+ if (post_shift < BITS_PER_WORD
+ && size - 1 < BITS_PER_WORD)
{
- t4 = expand_shift (RSHIFT_EXPR, compute_mode, t3,
- build_int_2 (post_shift, 0),
- NULL_RTX, 1);
- quotient = expand_binop (compute_mode, xor_optab,
- t4, t1, tquotient, 0,
- OPTAB_WIDEN);
+ t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
+ build_int_2 (size - 1, 0),
+ NULL_RTX, 0);
+ t2 = expand_binop (compute_mode, xor_optab, op0, t1,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ extra_cost = (shift_cost[post_shift]
+ + shift_cost[size - 1] + 2 * add_cost);
+ t3 = expand_mult_highpart (compute_mode, t2, ml,
+ NULL_RTX, 1,
+ max_cost - extra_cost);
+ if (t3 != 0)
+ {
+ t4 = expand_shift (RSHIFT_EXPR, compute_mode, t3,
+ build_int_2 (post_shift, 0),
+ NULL_RTX, 1);
+ quotient = expand_binop (compute_mode, xor_optab,
+ t4, t1, tquotient, 0,
+ OPTAB_WIDEN);
+ }
}
}
}
ml = invert_mod2n (d >> pre_shift, size);
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_2 (pre_shift, 0), NULL_RTX, unsignedp);
- quotient = expand_mult (compute_mode, t1, GEN_INT (ml), NULL_RTX,
- 0);
+ quotient = expand_mult (compute_mode, t1,
+ GEN_INT (trunc_int_for_mode
+ (ml, compute_mode)),
+ NULL_RTX, 0);
insn = get_last_insn ();
set_unique_reg_note (insn,
default:
t = make_node (RTL_EXPR);
TREE_TYPE (t) = type;
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+ /* If TYPE is a POINTER_TYPE, X might be Pmode with TYPE_MODE being
+ ptr_mode. So convert. */
+ if (POINTER_TYPE_P (type) && GET_MODE (x) != TYPE_MODE (type))
+ x = convert_memory_address (TYPE_MODE (type), x);
+#endif
+
RTL_EXPR_RTL (t) = x;
/* There are no insns to be output
when this rtl_expr is used. */
/* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */
- if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
- || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+ if (swap_commutative_operands_p (op0, op1))
{
tem = op0;
op0 = op1;
we can use zero-extension to the wider mode (an unsigned conversion)
as the operation. */
- /* CYGNUS LOCAL - amylaar/-ftrapv: Note that ABS doesn't yield a
- positive number for INT_MIN, but that is compensated by the
- subsequent overflow when subtracting one / negating.
- END CYGNUS LOCAL */
+ /* Note that ABS doesn't yield a positive number for INT_MIN, but
+ that is compensated by the subsequent overflow when subtracting
+ one / negating. */
if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
tem = expand_unop (mode, abs_optab, op0, subtarget, 1);