diff options
author | David E. O'Brien <obrien@FreeBSD.org> | 2002-05-09 20:02:13 +0000 |
---|---|---|
committer | David E. O'Brien <obrien@FreeBSD.org> | 2002-05-09 20:02:13 +0000 |
commit | 909b40107406b30c899ce55c127d8761e8b09ca8 (patch) | |
tree | 29a0f0a6c79a69ecc64f612947a0fe5904311713 /contrib/gcc/expr.c | |
parent | 1952e2e1c1be6f107fa3ce8b10025cfd1cd7943b (diff) | |
download | src-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.c | 369 |
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; } |