aboutsummaryrefslogtreecommitdiff
path: root/contrib/gcc/expr.c
diff options
context:
space:
mode:
authorDavid E. O'Brien <obrien@FreeBSD.org>2002-05-09 20:02:13 +0000
committerDavid E. O'Brien <obrien@FreeBSD.org>2002-05-09 20:02:13 +0000
commit909b40107406b30c899ce55c127d8761e8b09ca8 (patch)
tree29a0f0a6c79a69ecc64f612947a0fe5904311713 /contrib/gcc/expr.c
parent1952e2e1c1be6f107fa3ce8b10025cfd1cd7943b (diff)
downloadsrc-909b40107406b30c899ce55c127d8761e8b09ca8.tar.gz
src-909b40107406b30c899ce55c127d8761e8b09ca8.zip
Gcc 3.1.0 pre-release from the FSF anoncvs repo on 9-May-2002 15:57:15 EDT.
Notes
Notes: svn path=/vendor/gcc/dist/; revision=96263
Diffstat (limited to 'contrib/gcc/expr.c')
-rw-r--r--contrib/gcc/expr.c369
1 files changed, 266 insertions, 103 deletions
diff --git a/contrib/gcc/expr.c b/contrib/gcc/expr.c
index 2b8b0856b46f..a6ec5466c8f5 100644
--- a/contrib/gcc/expr.c
+++ b/contrib/gcc/expr.c
@@ -147,6 +147,8 @@ static rtx store_field PARAMS ((rtx, HOST_WIDE_INT,
int));
static rtx var_rtx PARAMS ((tree));
static HOST_WIDE_INT highest_pow2_factor PARAMS ((tree));
+static HOST_WIDE_INT highest_pow2_factor_for_type PARAMS ((tree, tree));
+static int is_aligning_offset PARAMS ((tree, tree));
static rtx expand_increment PARAMS ((tree, int, int));
static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
static void do_jump_by_parts_equality PARAMS ((tree, rtx, rtx));
@@ -2004,12 +2006,17 @@ emit_group_load (dst, orig_src, ssize)
}
else if (GET_CODE (src) == CONCAT)
{
- if (bytepos == 0
- && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
- tmps[i] = XEXP (src, 0);
- else if (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
- && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1))))
- tmps[i] = XEXP (src, 1);
+ if ((bytepos == 0
+ && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
+ || (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
+ && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1)))))
+ {
+ tmps[i] = XEXP (src, bytepos != 0);
+ if (! CONSTANT_P (tmps[i])
+ && (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode))
+ tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
+ 0, 1, NULL_RTX, mode, mode, ssize);
+ }
else if (bytepos == 0)
{
rtx mem = assign_stack_temp (GET_MODE (src),
@@ -2095,7 +2102,7 @@ emit_group_store (orig_dst, src, ssize)
emit_group_load (dst, temp, ssize);
return;
}
- else if (GET_CODE (dst) != MEM)
+ else if (GET_CODE (dst) != MEM && GET_CODE (dst) != CONCAT)
{
dst = gen_reg_rtx (GET_MODE (orig_dst));
/* Make life a bit easier for combine. */
@@ -2108,6 +2115,7 @@ emit_group_store (orig_dst, src, ssize)
HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
enum machine_mode mode = GET_MODE (tmps[i]);
unsigned int bytelen = GET_MODE_SIZE (mode);
+ rtx dest = dst;
/* Handle trailing fragments that run over the size of the struct. */
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
@@ -2121,14 +2129,27 @@ emit_group_store (orig_dst, src, ssize)
bytelen = ssize - bytepos;
}
+ if (GET_CODE (dst) == CONCAT)
+ {
+ if (bytepos + bytelen <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+ dest = XEXP (dst, 0);
+ else if (bytepos >= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+ {
+ bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
+ dest = XEXP (dst, 1);
+ }
+ else
+ abort ();
+ }
+
/* Optimize the access just a bit. */
- if (GET_CODE (dst) == MEM
- && MEM_ALIGN (dst) >= GET_MODE_ALIGNMENT (mode)
+ if (GET_CODE (dest) == MEM
+ && MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode)
&& bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
&& bytelen == GET_MODE_SIZE (mode))
- emit_move_insn (adjust_address (dst, mode, bytepos), tmps[i]);
+ emit_move_insn (adjust_address (dest, mode, bytepos), tmps[i]);
else
- store_bit_field (dst, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
+ store_bit_field (dest, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
mode, tmps[i], ssize);
}
@@ -3659,17 +3680,17 @@ expand_assignment (to, from, want_value, suggest_reg)
if (offset != 0)
{
- rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+ rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
if (GET_CODE (to_rtx) != MEM)
abort ();
- if (GET_MODE (offset_rtx) != ptr_mode)
- offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (offset_rtx) != Pmode)
offset_rtx = convert_memory_address (Pmode, offset_rtx);
+#else
+ if (GET_MODE (offset_rtx) != ptr_mode)
+ offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
#endif
/* A constant address in TO_RTX can have VOIDmode, we must not try
@@ -3682,20 +3703,13 @@ expand_assignment (to, from, want_value, suggest_reg)
&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
&& MEM_ALIGN (to_rtx) == GET_MODE_ALIGNMENT (mode1))
{
- rtx temp
- = adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
-
- if (GET_CODE (XEXP (temp, 0)) == REG)
- to_rtx = temp;
- else
- to_rtx = (replace_equiv_address
- (to_rtx, force_reg (GET_MODE (XEXP (temp, 0)),
- XEXP (temp, 0))));
+ to_rtx = adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
bitpos = 0;
}
to_rtx = offset_address (to_rtx, offset_rtx,
- highest_pow2_factor (offset));
+ highest_pow2_factor_for_type (TREE_TYPE (to),
+ offset));
}
if (GET_CODE (to_rtx) == MEM)
@@ -3997,6 +4011,8 @@ store_expr (exp, target, want_value)
and then convert to the wider mode. Our value is the computed
expression. */
{
+ rtx inner_target = 0;
+
/* If we don't want a value, we can do the conversion inside EXP,
which will often result in some optimizations. Do the conversion
in two steps: first change the signedness, if needed, then
@@ -4017,9 +4033,11 @@ store_expr (exp, target, want_value)
exp = convert (type_for_mode (GET_MODE (SUBREG_REG (target)),
SUBREG_PROMOTED_UNSIGNED_P (target)),
exp);
+
+ inner_target = SUBREG_REG (target);
}
- temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+ temp = expand_expr (exp, inner_target, VOIDmode, 0);
/* If TEMP is a volatile MEM and we want a result value, make
the access now so it gets done only once. Likewise if
@@ -4110,7 +4128,12 @@ store_expr (exp, target, want_value)
|| (temp != target && (side_effects_p (temp)
|| side_effects_p (target))))
&& TREE_CODE (exp) != ERROR_MARK
- && ! dont_store_target)
+ && ! dont_store_target
+ /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET,
+ but TARGET is not valid memory reference, TEMP will differ
+ from TARGET although it is really the same location. */
+ && (TREE_CODE_CLASS (TREE_CODE (exp)) != 'd'
+ || target != DECL_RTL_IF_SET (exp)))
{
target = protect_from_queue (target, 1);
if (GET_MODE (temp) != GET_MODE (target)
@@ -4165,7 +4188,7 @@ store_expr (exp, target, want_value)
}
else
{
- size = expand_binop (ptr_mode, sub_optab, size,
+ size = expand_binop (TYPE_MODE (sizetype), sub_optab, size,
copy_size_rtx, NULL_RTX, 0,
OPTAB_LIB_WIDEN);
@@ -4244,6 +4267,14 @@ is_zeros_p (exp)
case REAL_CST:
return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0);
+ case VECTOR_CST:
+ for (elt = TREE_VECTOR_CST_ELTS (exp); elt;
+ elt = TREE_CHAIN (elt))
+ if (!is_zeros_p (TREE_VALUE (elt)))
+ return 0;
+
+ return 1;
+
case CONSTRUCTOR:
if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
@@ -4466,12 +4497,12 @@ store_constructor (exp, target, cleared, size)
if (GET_CODE (to_rtx) != MEM)
abort ();
- if (GET_MODE (offset_rtx) != ptr_mode)
- offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (offset_rtx) != Pmode)
offset_rtx = convert_memory_address (Pmode, offset_rtx);
+#else
+ if (GET_MODE (offset_rtx) != ptr_mode)
+ offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
#endif
to_rtx = offset_address (to_rtx, offset_rtx,
@@ -4528,20 +4559,34 @@ store_constructor (exp, target, cleared, size)
get_alias_set (TREE_TYPE (field)));
}
}
- else if (TREE_CODE (type) == ARRAY_TYPE)
+ else if (TREE_CODE (type) == ARRAY_TYPE
+ || TREE_CODE (type) == VECTOR_TYPE)
{
tree elt;
int i;
int need_to_clear;
tree domain = TYPE_DOMAIN (type);
tree elttype = TREE_TYPE (type);
- int const_bounds_p = (TYPE_MIN_VALUE (domain)
- && TYPE_MAX_VALUE (domain)
- && host_integerp (TYPE_MIN_VALUE (domain), 0)
- && host_integerp (TYPE_MAX_VALUE (domain), 0));
+ int const_bounds_p;
HOST_WIDE_INT minelt = 0;
HOST_WIDE_INT maxelt = 0;
+ /* Vectors are like arrays, but the domain is stored via an array
+ type indirectly. */
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ /* Note that although TYPE_DEBUG_REPRESENTATION_TYPE uses
+ the same field as TYPE_DOMAIN, we are not guaranteed that
+ it always will. */
+ domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
+ domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
+ }
+
+ const_bounds_p = (TYPE_MIN_VALUE (domain)
+ && TYPE_MAX_VALUE (domain)
+ && host_integerp (TYPE_MIN_VALUE (domain), 0)
+ && host_integerp (TYPE_MAX_VALUE (domain), 0));
+
/* If we have constant bounds for the range of the type, get them. */
if (const_bounds_p)
{
@@ -4602,7 +4647,12 @@ store_constructor (exp, target, cleared, size)
if (need_to_clear && size > 0)
{
if (! cleared)
- clear_storage (target, GEN_INT (size));
+ {
+ if (REG_P (target))
+ emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
+ else
+ clear_storage (target, GEN_INT (size));
+ }
cleared = 1;
}
else if (REG_P (target))
@@ -4665,6 +4715,7 @@ store_constructor (exp, target, cleared, size)
if (GET_CODE (target) == MEM
&& !MEM_KEEP_ALIAS_SET_P (target)
+ && TREE_CODE (type) == ARRAY_TYPE
&& TYPE_NONALIASED_COMPONENT (type))
{
target = copy_rtx (target);
@@ -4762,6 +4813,7 @@ store_constructor (exp, target, cleared, size)
bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
if (GET_CODE (target) == MEM && !MEM_KEEP_ALIAS_SET_P (target)
+ && TREE_CODE (type) == ARRAY_TYPE
&& TYPE_NONALIASED_COMPONENT (type))
{
target = copy_rtx (target);
@@ -5114,18 +5166,16 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
tree count;
enum machine_mode tmode;
- if (unsignedp)
- return expand_and (temp,
- GEN_INT
- (trunc_int_for_mode
- (width_mask,
- GET_MODE (temp) == VOIDmode
- ? value_mode
- : GET_MODE (temp))), NULL_RTX);
-
tmode = GET_MODE (temp);
if (tmode == VOIDmode)
tmode = value_mode;
+
+ if (unsignedp)
+ return expand_and (tmode, temp,
+ GEN_INT (trunc_int_for_mode (width_mask,
+ tmode)),
+ NULL_RTX);
+
count = build_int_2 (GET_MODE_BITSIZE (tmode) - bitsize, 0);
temp = expand_shift (LSHIFT_EXPR, tmode, temp, count, 0, 0);
return expand_shift (RSHIFT_EXPR, tmode, temp, count, 0, 0);
@@ -5555,7 +5605,7 @@ safe_from_p (x, exp, top_p)
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
case 'd':
- exp_rtl = DECL_RTL_SET_P (exp) ? DECL_RTL (exp) : NULL_RTX;
+ exp_rtl = DECL_RTL_IF_SET (exp);
break;
case 'c':
@@ -5711,7 +5761,7 @@ safe_from_p (x, exp, top_p)
are memory and they conflict. */
return ! (rtx_equal_p (x, exp_rtl)
|| (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
- && true_dependence (exp_rtl, GET_MODE (x), x,
+ && true_dependence (exp_rtl, VOIDmode, x,
rtx_addr_varies_p)));
}
@@ -5804,20 +5854,21 @@ highest_pow2_factor (exp)
switch (TREE_CODE (exp))
{
case INTEGER_CST:
- /* If the integer is expressable in a HOST_WIDE_INT, we can find the
- lowest bit that's a one. If the result is zero, return
- BIGGEST_ALIGNMENT. We need to handle this case since we can find it
- in a COND_EXPR, a MIN_EXPR, or a MAX_EXPR. If the constant overlows,
- we have an erroneous program, so return BIGGEST_ALIGNMENT to avoid any
+ /* We can find the lowest bit that's a one. If the low
+ HOST_BITS_PER_WIDE_INT bits are zero, return BIGGEST_ALIGNMENT.
+ We need to handle this case since we can find it in a COND_EXPR,
+ a MIN_EXPR, or a MAX_EXPR. If the constant overlows, we have an
+ erroneous program, so return BIGGEST_ALIGNMENT to avoid any
later ICE. */
- if (TREE_CONSTANT_OVERFLOW (exp)
- || integer_zerop (exp))
+ if (TREE_CONSTANT_OVERFLOW (exp))
return BIGGEST_ALIGNMENT;
- else if (host_integerp (exp, 0))
+ else
{
- c0 = tree_low_cst (exp, 0);
- c0 = c0 < 0 ? - c0 : c0;
- return c0 & -c0;
+ /* Note: tree_low_cst is intentionally not used here,
+ we don't care about the upper bits. */
+ c0 = TREE_INT_CST_LOW (exp);
+ c0 &= -c0;
+ return c0 ? c0 : BIGGEST_ALIGNMENT;
}
break;
@@ -5860,6 +5911,21 @@ highest_pow2_factor (exp)
return 1;
}
+
+/* Similar, except that it is known that the expression must be a multiple
+ of the alignment of TYPE. */
+
+static HOST_WIDE_INT
+highest_pow2_factor_for_type (type, exp)
+ tree type;
+ tree exp;
+{
+ HOST_WIDE_INT type_align, factor;
+
+ factor = highest_pow2_factor (exp);
+ type_align = TYPE_ALIGN (type) / BITS_PER_UNIT;
+ return MAX (factor, type_align);
+}
/* Return an object on the placeholder list that matches EXP, a
PLACEHOLDER_EXPR. An object "matches" if it is of the type of the
@@ -6261,7 +6327,8 @@ expand_expr (exp, target, tmode, modifier)
/* Get the signedness used for this variable. Ensure we get the
same mode we got when the variable was declared. */
if (GET_MODE (DECL_RTL (exp))
- != promote_mode (type, DECL_MODE (exp), &unsignedp, 0))
+ != promote_mode (type, DECL_MODE (exp), &unsignedp,
+ (TREE_CODE (exp) == RESULT_DECL ? 1 : 0)))
abort ();
temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
@@ -6273,9 +6340,20 @@ expand_expr (exp, target, tmode, modifier)
return DECL_RTL (exp);
case INTEGER_CST:
- return immed_double_const (TREE_INT_CST_LOW (exp),
+ temp = immed_double_const (TREE_INT_CST_LOW (exp),
TREE_INT_CST_HIGH (exp), mode);
+ /* ??? If overflow is set, fold will have done an incomplete job,
+ which can result in (plus xx (const_int 0)), which can get
+ simplified by validate_replace_rtx during virtual register
+ instantiation, which can result in unrecognizable insns.
+ Avoid this by forcing all overflows into registers. */
+ if (TREE_CONSTANT_OVERFLOW (exp)
+ && modifier != EXPAND_INITIALIZER)
+ temp = force_reg (mode, temp);
+
+ return temp;
+
case CONST_DECL:
return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
@@ -6603,7 +6681,8 @@ expand_expr (exp, target, tmode, modifier)
&& GET_MODE_SIZE (mode) == 1
&& modifier != EXPAND_WRITE)
return
- GEN_INT (TREE_STRING_POINTER (string)[TREE_INT_CST_LOW (index)]);
+ GEN_INT (trunc_int_for_mode (TREE_STRING_POINTER (string)
+ [TREE_INT_CST_LOW (index)], mode));
op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
op0 = memory_address (mode, op0);
@@ -6653,7 +6732,8 @@ expand_expr (exp, target, tmode, modifier)
&& GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == 1)
return
- GEN_INT (TREE_STRING_POINTER (array)[TREE_INT_CST_LOW (index)]);
+ GEN_INT (trunc_int_for_mode (TREE_STRING_POINTER (array)
+ [TREE_INT_CST_LOW (index)], mode));
/* If this is a constant index into a constant array,
just get the value from the array. Handle both the cases when
@@ -6713,9 +6793,9 @@ expand_expr (exp, target, tmode, modifier)
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == 1)
- return (GEN_INT
- (TREE_STRING_POINTER
- (init)[TREE_INT_CST_LOW (index)]));
+ return GEN_INT (trunc_int_for_mode
+ (TREE_STRING_POINTER (init)
+ [TREE_INT_CST_LOW (index)], mode));
}
}
}
@@ -6756,16 +6836,16 @@ expand_expr (exp, target, tmode, modifier)
{
HOST_WIDE_INT bitsize
= TREE_INT_CST_LOW (DECL_SIZE (TREE_PURPOSE (elt)));
+ enum machine_mode imode
+ = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
{
op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
- op0 = expand_and (op0, op1, target);
+ op0 = expand_and (imode, op0, op1, target);
}
else
{
- enum machine_mode imode
- = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
tree count
= build_int_2 (GET_MODE_BITSIZE (imode) - bitsize,
0);
@@ -6825,7 +6905,7 @@ expand_expr (exp, target, tmode, modifier)
if (offset != 0)
{
- rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+ rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
/* If this object is in a register, put it into memory.
This case can't occur in C, but can in Ada if we have
@@ -6857,12 +6937,12 @@ expand_expr (exp, target, tmode, modifier)
if (GET_CODE (op0) != MEM)
abort ();
- if (GET_MODE (offset_rtx) != ptr_mode)
- offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (offset_rtx) != Pmode)
offset_rtx = convert_memory_address (Pmode, offset_rtx);
+#else
+ if (GET_MODE (offset_rtx) != ptr_mode)
+ offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
#endif
/* A constant address in OP0 can have VOIDmode, we must not try
@@ -6875,15 +6955,7 @@ expand_expr (exp, target, tmode, modifier)
&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
&& MEM_ALIGN (op0) == GET_MODE_ALIGNMENT (mode1))
{
- rtx temp = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
-
- if (GET_CODE (XEXP (temp, 0)) == REG)
- op0 = temp;
- else
- op0 = (replace_equiv_address
- (op0,
- force_reg (GET_MODE (XEXP (temp, 0)),
- XEXP (temp, 0))));
+ op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
bitpos = 0;
}
@@ -6891,6 +6963,12 @@ expand_expr (exp, target, tmode, modifier)
highest_pow2_factor (offset));
}
+ /* If OFFSET is making OP0 more aligned than BIGGEST_ALIGNMENT,
+ record its alignment as BIGGEST_ALIGNMENT. */
+ if (GET_CODE (op0) == MEM && bitpos == 0 && offset != 0
+ && is_aligning_offset (offset, tem))
+ set_mem_align (op0, BIGGEST_ALIGNMENT);
+
/* Don't forget about volatility even if this is a bitfield. */
if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
{
@@ -6900,6 +6978,16 @@ expand_expr (exp, target, tmode, modifier)
MEM_VOLATILE_P (op0) = 1;
}
+ /* The following code doesn't handle CONCAT.
+ Assume only bitpos == 0 can be used for CONCAT, due to
+ one element arrays having the same mode as its element. */
+ if (GET_CODE (op0) == CONCAT)
+ {
+ if (bitpos != 0 || bitsize != GET_MODE_BITSIZE (GET_MODE (op0)))
+ abort ();
+ return op0;
+ }
+
/* In cases where an aligned union has an unaligned object
as a field, we might be extracting a BLKmode value from
an integer-mode (e.g., SImode) object. Handle this case
@@ -7274,15 +7362,24 @@ expand_expr (exp, target, tmode, modifier)
return op0;
}
- op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, 0);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
if (GET_MODE (op0) == mode)
return op0;
/* If OP0 is a constant, just convert it into the proper mode. */
if (CONSTANT_P (op0))
- return
- convert_modes (mode, TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
- op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+ {
+ tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+ enum machine_mode inner_mode = TYPE_MODE (inner_type);
+
+ if (modifier == EXPAND_INITIALIZER)
+ return simplify_gen_subreg (mode, op0, inner_mode,
+ subreg_lowpart_offset (mode,
+ inner_mode));
+ else
+ return convert_modes (mode, inner_mode, op0,
+ TREE_UNSIGNED (inner_type));
+ }
if (modifier == EXPAND_INITIALIZER)
return gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
@@ -7440,7 +7537,8 @@ expand_expr (exp, target, tmode, modifier)
rtx constant_part;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
- EXPAND_SUM);
+ (modifier == EXPAND_INITIALIZER
+ ? EXPAND_INITIALIZER : EXPAND_SUM));
if (! CONSTANT_P (op0))
{
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
@@ -7586,23 +7684,20 @@ expand_expr (exp, target, tmode, modifier)
indexed address, for machines that support that. */
if (modifier == EXPAND_SUM && mode == ptr_mode
- && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
- && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ && host_integerp (TREE_OPERAND (exp, 1), 0))
{
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
EXPAND_SUM);
- /* Apply distributive law if OP0 is x+c. */
- if (GET_CODE (op0) == PLUS
- && GET_CODE (XEXP (op0, 1)) == CONST_INT)
- return
- gen_rtx_PLUS
- (mode,
- gen_rtx_MULT
- (mode, XEXP (op0, 0),
- GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))),
- GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
- * INTVAL (XEXP (op0, 1))));
+ /* If we knew for certain that this is arithmetic for an array
+ reference, and we knew the bounds of the array, then we could
+ apply the distributive law across (PLUS X C) for constant C.
+ Without such knowledge, we risk overflowing the computation
+ when both X and C are large, but X+C isn't. */
+ /* ??? Could perhaps special-case EXP being unsigned and C being
+ positive. In that case we are certain that X+C is no smaller
+ than X and so the transformed expression will overflow iff the
+ original would have. */
if (GET_CODE (op0) != REG)
op0 = force_operand (op0, NULL_RTX);
@@ -7611,7 +7706,7 @@ expand_expr (exp, target, tmode, modifier)
return
gen_rtx_MULT (mode, op0,
- GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
+ GEN_INT (tree_low_cst (TREE_OPERAND (exp, 1), 0)));
}
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
@@ -7712,6 +7807,7 @@ expand_expr (exp, target, tmode, modifier)
expensive divide. If not, combine will rebuild the original
computation. */
if (flag_unsafe_math_optimizations && optimize && !optimize_size
+ && TREE_CODE (type) == REAL_TYPE
&& !real_onep (TREE_OPERAND (exp, 0)))
return expand_expr (build (MULT_EXPR, type, TREE_OPERAND (exp, 0),
build (RDIV_EXPR, type,
@@ -7921,8 +8017,25 @@ expand_expr (exp, target, tmode, modifier)
temp = expand_expr (TREE_OPERAND (exp, 0), original_target,
VOIDmode, 0);
+ /* If temp is constant, we can just compute the result. */
+ if (GET_CODE (temp) == CONST_INT)
+ {
+ if (INTVAL (temp) != 0)
+ emit_move_insn (target, const1_rtx);
+ else
+ emit_move_insn (target, const0_rtx);
+
+ return target;
+ }
+
if (temp != original_target)
- temp = copy_to_reg (temp);
+ {
+ enum machine_mode mode1 = GET_MODE (temp);
+ if (mode1 == VOIDmode)
+ mode1 = tmode != VOIDmode ? tmode : mode;
+
+ temp = copy_to_mode_reg (mode1, temp);
+ }
op1 = gen_label_rtx ();
emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
@@ -8758,6 +8871,56 @@ expand_expr (exp, target, tmode, modifier)
return temp;
}
+/* Subroutine of above: returns 1 if OFFSET corresponds to an offset that
+ when applied to the address of EXP produces an address known to be
+ aligned more than BIGGEST_ALIGNMENT. */
+
+static int
+is_aligning_offset (offset, exp)
+ tree offset;
+ tree exp;
+{
+ /* Strip off any conversions and WITH_RECORD_EXPR nodes. */
+ while (TREE_CODE (offset) == NON_LVALUE_EXPR
+ || TREE_CODE (offset) == NOP_EXPR
+ || TREE_CODE (offset) == CONVERT_EXPR
+ || TREE_CODE (offset) == WITH_RECORD_EXPR)
+ offset = TREE_OPERAND (offset, 0);
+
+ /* We must now have a BIT_AND_EXPR with a constant that is one less than
+ power of 2 and which is larger than BIGGEST_ALIGNMENT. */
+ if (TREE_CODE (offset) != BIT_AND_EXPR
+ || !host_integerp (TREE_OPERAND (offset, 1), 1)
+ || compare_tree_int (TREE_OPERAND (offset, 1), BIGGEST_ALIGNMENT) <= 0
+ || !exact_log2 (tree_low_cst (TREE_OPERAND (offset, 1), 1) + 1) < 0)
+ return 0;
+
+ /* Look at the first operand of BIT_AND_EXPR and strip any conversion.
+ It must be NEGATE_EXPR. Then strip any more conversions. */
+ offset = TREE_OPERAND (offset, 0);
+ while (TREE_CODE (offset) == NON_LVALUE_EXPR
+ || TREE_CODE (offset) == NOP_EXPR
+ || TREE_CODE (offset) == CONVERT_EXPR)
+ offset = TREE_OPERAND (offset, 0);
+
+ if (TREE_CODE (offset) != NEGATE_EXPR)
+ return 0;
+
+ offset = TREE_OPERAND (offset, 0);
+ while (TREE_CODE (offset) == NON_LVALUE_EXPR
+ || TREE_CODE (offset) == NOP_EXPR
+ || TREE_CODE (offset) == CONVERT_EXPR)
+ offset = TREE_OPERAND (offset, 0);
+
+ /* This must now be the address either of EXP or of a PLACEHOLDER_EXPR
+ whose type is the same as EXP. */
+ return (TREE_CODE (offset) == ADDR_EXPR
+ && (TREE_OPERAND (offset, 0) == exp
+ || (TREE_CODE (TREE_OPERAND (offset, 0)) == PLACEHOLDER_EXPR
+ && (TREE_TYPE (TREE_OPERAND (offset, 0))
+ == TREE_TYPE (exp)))));
+}
+
/* Return the tree node if a ARG corresponds to a string constant or zero
if it doesn't. If we return non-zero, set *PTR_OFFSET to the offset
in bytes within the string that ARG is accessing. The type of the
@@ -10184,7 +10347,7 @@ do_store_flag (exp, target, mode, only_cheap)
/* Put the AND last so it can combine with more things. */
if (bitnum != TYPE_PRECISION (type) - 1)
- op0 = expand_and (op0, const1_rtx, subtarget);
+ op0 = expand_and (mode, op0, const1_rtx, subtarget);
return op0;
}