X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fexpr.c;h=943a4c44caa4040e7a215ec065184cd6ae31419e;hb=baab3ea2c32aaac44a3f03bc51988ef4f07a659d;hp=537ce1ef83ef81335d18227341107b16837563d7;hpb=63bf54cf778c9f182a9fcaf64b8bfbad4399a6d8;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/expr.c b/gcc/expr.c index 537ce1ef83e..943a4c44caa 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -127,7 +127,6 @@ static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode, struct move_by_pieces *); static bool block_move_libcall_safe_for_call_parm (void); static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned); -static rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool); static tree emit_block_move_libcall_fn (int); static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned); static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode); @@ -135,7 +134,6 @@ static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int); static void store_by_pieces_1 (struct store_by_pieces *, unsigned int); static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode, struct store_by_pieces *); -static rtx clear_storage_via_libcall (rtx, rtx, bool); static tree clear_storage_libcall_fn (int); static rtx compress_float_constant (rtx, rtx); static rtx get_subtarget (rtx); @@ -1336,7 +1334,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align) /* A subroutine of emit_block_move. Expand a call to memcpy. Return the return value from memcpy, 0 otherwise. */ -static rtx +rtx emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall) { rtx dst_addr, src_addr; @@ -1409,6 +1407,8 @@ init_block_move_fn (const char *asmspec) TREE_PUBLIC (fn) = 1; DECL_ARTIFICIAL (fn) = 1; TREE_NOTHROW (fn) = 1; + DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT; + DECL_VISIBILITY_SPECIFIED (fn) = 1; block_move_fn = fn; } @@ -1855,7 +1855,7 @@ void emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize) { rtx *tmps, dst; - int start, i; + int start, finish, i; enum machine_mode m = GET_MODE (orig_dst); gcc_assert (GET_CODE (src) == PARALLEL); @@ -1881,15 +1881,21 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize) start = 0; else start = 1; + finish = XVECLEN (src, 0); - tmps = alloca (sizeof (rtx) * XVECLEN (src, 0)); + tmps = alloca (sizeof (rtx) * finish); /* Copy the (probable) hard regs into pseudos. */ - for (i = start; i < XVECLEN (src, 0); i++) + for (i = start; i < finish; i++) { rtx reg = XEXP (XVECEXP (src, 0, i), 0); - tmps[i] = gen_reg_rtx (GET_MODE (reg)); - emit_move_insn (tmps[i], reg); + if (!REG_P (reg) || REGNO (reg) < FIRST_PSEUDO_REGISTER) + { + tmps[i] = gen_reg_rtx (GET_MODE (reg)); + emit_move_insn (tmps[i], reg); + } + else + tmps[i] = reg; } /* If we won't be storing directly into memory, protect the real destination @@ -1916,13 +1922,62 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize) } else if (!MEM_P (dst) && GET_CODE (dst) != CONCAT) { - dst = gen_reg_rtx (GET_MODE (orig_dst)); + enum machine_mode outer = GET_MODE (dst); + enum machine_mode inner; + HOST_WIDE_INT bytepos; + bool done = false; + rtx temp; + + if (!REG_P (dst) || REGNO (dst) < FIRST_PSEUDO_REGISTER) + dst = gen_reg_rtx (outer); + /* Make life a bit easier for combine. */ - emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst))); + /* If the first element of the vector is the low part + of the destination mode, use a paradoxical subreg to + initialize the destination. */ + if (start < finish) + { + inner = GET_MODE (tmps[start]); + bytepos = subreg_lowpart_offset (inner, outer); + if (INTVAL (XEXP (XVECEXP (src, 0, start), 1)) == bytepos) + { + temp = simplify_gen_subreg (outer, tmps[start], + inner, 0); + if (temp) + { + emit_move_insn (dst, temp); + done = true; + start++; + } + } + } + + /* If the first element wasn't the low part, try the last. */ + if (!done + && start < finish - 1) + { + inner = GET_MODE (tmps[finish - 1]); + bytepos = subreg_lowpart_offset (inner, outer); + if (INTVAL (XEXP (XVECEXP (src, 0, finish - 1), 1)) == bytepos) + { + temp = simplify_gen_subreg (outer, tmps[finish - 1], + inner, 0); + if (temp) + { + emit_move_insn (dst, temp); + done = true; + finish--; + } + } + } + + /* Otherwise, simply initialize the result to zero. */ + if (!done) + emit_move_insn (dst, CONST0_RTX (outer)); } /* Process the pieces. */ - for (i = start; i < XVECLEN (src, 0); i++) + for (i = start; i < finish; i++) { HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1)); enum machine_mode mode = GET_MODE (tmps[i]); @@ -2483,8 +2538,8 @@ clear_storage (rtx object, rtx size, enum block_op_methods method) else if (set_storage_via_setmem (object, size, const0_rtx, align)) ; else - return clear_storage_via_libcall (object, size, - method == BLOCK_OP_TAILCALL); + return set_storage_via_libcall (object, size, const0_rtx, + method == BLOCK_OP_TAILCALL); return NULL; } @@ -2492,10 +2547,10 @@ clear_storage (rtx object, rtx size, enum block_op_methods method) /* A subroutine of clear_storage. Expand a call to memset. Return the return value of memset, 0 otherwise. */ -static rtx -clear_storage_via_libcall (rtx object, rtx size, bool tailcall) +rtx +set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall) { - tree call_expr, arg_list, fn, object_tree, size_tree; + tree call_expr, arg_list, fn, object_tree, size_tree, val_tree; enum machine_mode size_mode; rtx retval; @@ -2515,11 +2570,14 @@ clear_storage_via_libcall (rtx object, rtx size, bool tailcall) for returning pointers, we could end up generating incorrect code. */ object_tree = make_tree (ptr_type_node, object); + if (GET_CODE (val) != CONST_INT) + val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1); size_tree = make_tree (sizetype, size); + val_tree = make_tree (integer_type_node, val); fn = clear_storage_libcall_fn (true); arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE); - arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list); + arg_list = tree_cons (NULL_TREE, val_tree, arg_list); arg_list = tree_cons (NULL_TREE, object_tree, arg_list); /* Now we have to build up the CALL_EXPR itself. */ @@ -2533,7 +2591,7 @@ clear_storage_via_libcall (rtx object, rtx size, bool tailcall) return retval; } -/* A subroutine of clear_storage_via_libcall. Create the tree node +/* A subroutine of set_storage_via_libcall. Create the tree node for the function we use for block clears. The first time FOR_CALL is true, we call assemble_external. */ @@ -2556,6 +2614,8 @@ init_block_clear_fn (const char *asmspec) TREE_PUBLIC (fn) = 1; DECL_ARTIFICIAL (fn) = 1; TREE_NOTHROW (fn) = 1; + DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT; + DECL_VISIBILITY_SPECIFIED (fn) = 1; block_clear_fn = fn; } @@ -3037,6 +3097,38 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y) return ret; } +/* Return true if word I of OP lies entirely in the + undefined bits of a paradoxical subreg. */ + +static bool +undefined_operand_subword_p (rtx op, int i) +{ + enum machine_mode innermode, innermostmode; + int offset; + if (GET_CODE (op) != SUBREG) + return false; + innermode = GET_MODE (op); + innermostmode = GET_MODE (SUBREG_REG (op)); + offset = i * UNITS_PER_WORD + SUBREG_BYTE (op); + /* The SUBREG_BYTE represents offset, as if the value were stored in + memory, except for a paradoxical subreg where we define + SUBREG_BYTE to be 0; undo this exception as in + simplify_subreg. */ + if (SUBREG_BYTE (op) == 0 + && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode)) + { + int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode)); + if (WORDS_BIG_ENDIAN) + offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += difference % UNITS_PER_WORD; + } + if (offset >= GET_MODE_SIZE (innermostmode) + || offset <= -GET_MODE_SIZE (word_mode)) + return true; + return false; +} + /* A subroutine of emit_move_insn_1. Generate a move from Y into X. MODE is any multi-word or full-word mode that lacks a move_insn pattern. Note that you will get better code if you define such @@ -3074,14 +3166,21 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y) i++) { rtx xpart = operand_subword (x, i, 1, mode); - rtx ypart = operand_subword (y, i, 1, mode); + rtx ypart; + + /* Do not generate code for a move if it would come entirely + from the undefined bits of a paradoxical subreg. */ + if (undefined_operand_subword_p (y, i)) + continue; + + ypart = operand_subword (y, i, 1, mode); /* If we can't get a part of Y, put Y into memory if it is a constant. Otherwise, force it into a register. Then we must be able to get a part of Y. */ if (ypart == 0 && CONSTANT_P (y)) { - y = force_const_mem (mode, y); + y = use_anchored_address (force_const_mem (mode, y)); ypart = operand_subword (y, i, 1, mode); } else if (ypart == 0) @@ -3194,6 +3293,8 @@ emit_move_insn (rtx x, rtx y) of the non-legitimate constant. */ if (!y) y = y_cst; + else + y = use_anchored_address (y); } } @@ -3285,7 +3386,11 @@ compress_float_constant (rtx x, rtx y) } else continue; - + + /* For CSE's benefit, force the compressed constant pool entry + into a new pseudo. This constant may be used in different modes, + and if not, combine will put things back together for us. */ + trunc_y = force_reg (srcmode, trunc_y); emit_unop_insn (ic, x, trunc_y, UNKNOWN); last_insn = get_last_insn (); @@ -3923,13 +4028,16 @@ expand_assignment (tree to, tree from) rtx result; /* Don't crash if the lhs of the assignment was erroneous. */ - if (TREE_CODE (to) == ERROR_MARK) { result = expand_normal (from); return; } + /* Optimize away no-op moves without side-effects. */ + if (operand_equal_p (to, from, 0)) + return; + /* Assignment of a structure component needs special treatment if the structure component's rtx is not simply a MEM. Assignment of an array element at a constant index, and assignment of @@ -4227,14 +4335,14 @@ store_expr (tree exp, rtx target, int call_param_p) { if (TYPE_UNSIGNED (TREE_TYPE (exp)) != SUBREG_PROMOTED_UNSIGNED_P (target)) - exp = convert + exp = fold_convert (lang_hooks.types.signed_or_unsigned_type (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)), exp); - exp = convert (lang_hooks.types.type_for_mode - (GET_MODE (SUBREG_REG (target)), - SUBREG_PROMOTED_UNSIGNED_P (target)), - exp); + exp = fold_convert (lang_hooks.types.type_for_mode + (GET_MODE (SUBREG_REG (target)), + SUBREG_PROMOTED_UNSIGNED_P (target)), + exp); inner_target = SUBREG_REG (target); } @@ -4424,28 +4532,24 @@ store_expr (tree exp, rtx target, int call_param_p) return NULL_RTX; } -/* Examine CTOR to discover: - * how many scalar fields are set to nonzero values, - and place it in *P_NZ_ELTS; - * how many scalar fields are set to non-constant values, - and place it in *P_NC_ELTS; and - * how many scalar fields in total are in CTOR, - and place it in *P_ELT_COUNT. - * if a type is a union, and the initializer from the constructor - is not the largest element in the union, then set *p_must_clear. */ +/* Helper for categorize_ctor_elements. Identical interface. */ -static void +static bool categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, - HOST_WIDE_INT *p_nc_elts, HOST_WIDE_INT *p_elt_count, bool *p_must_clear) { unsigned HOST_WIDE_INT idx; - HOST_WIDE_INT nz_elts, nc_elts, elt_count; + HOST_WIDE_INT nz_elts, elt_count; tree value, purpose; + /* Whether CTOR is a valid constant initializer, in accordance with what + initializer_constant_valid_p does. If inferred from the constructor + elements, true until proven otherwise. */ + bool const_from_elts_p = constructor_static_from_elts_p (ctor); + bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor); + nz_elts = 0; - nc_elts = 0; elt_count = 0; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value) @@ -4467,11 +4571,16 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, { case CONSTRUCTOR: { - HOST_WIDE_INT nz = 0, nc = 0, ic = 0; - categorize_ctor_elements_1 (value, &nz, &nc, &ic, p_must_clear); + HOST_WIDE_INT nz = 0, ic = 0; + + bool const_elt_p + = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear); + nz_elts += mult * nz; - nc_elts += mult * nc; - elt_count += mult * ic; + elt_count += mult * ic; + + if (const_from_elts_p && const_p) + const_p = const_elt_p; } break; @@ -4510,8 +4619,10 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, default: nz_elts += mult; elt_count += mult; - if (!initializer_constant_valid_p (value, TREE_TYPE (value))) - nc_elts += mult; + + if (const_from_elts_p && const_p) + const_p = initializer_constant_valid_p (value, TREE_TYPE (value)) + != NULL_TREE; break; } } @@ -4553,22 +4664,33 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, } *p_nz_elts += nz_elts; - *p_nc_elts += nc_elts; *p_elt_count += elt_count; + + return const_p; } -void +/* Examine CTOR to discover: + * how many scalar fields are set to nonzero values, + and place it in *P_NZ_ELTS; + * how many scalar fields in total are in CTOR, + and place it in *P_ELT_COUNT. + * if a type is a union, and the initializer from the constructor + is not the largest element in the union, then set *p_must_clear. + + Return whether or not CTOR is a valid static constant initializer, the same + as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0". */ + +bool categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts, - HOST_WIDE_INT *p_nc_elts, HOST_WIDE_INT *p_elt_count, bool *p_must_clear) { *p_nz_elts = 0; - *p_nc_elts = 0; *p_elt_count = 0; *p_must_clear = false; - categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count, - p_must_clear); + + return + categorize_ctor_elements_1 (ctor, p_nz_elts, p_elt_count, p_must_clear); } /* Count the number of scalars in TYPE. Return -1 on overflow or @@ -4670,10 +4792,10 @@ mostly_zeros_p (tree exp) if (TREE_CODE (exp) == CONSTRUCTOR) { - HOST_WIDE_INT nz_elts, nc_elts, count, elts; + HOST_WIDE_INT nz_elts, count, elts; bool must_clear; - categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear); + categorize_ctor_elements (exp, &nz_elts, &count, &must_clear); if (must_clear) return 1; @@ -4693,10 +4815,10 @@ all_zeros_p (tree exp) if (TREE_CODE (exp) == CONSTRUCTOR) { - HOST_WIDE_INT nz_elts, nc_elts, count; + HOST_WIDE_INT nz_elts, count; bool must_clear; - categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear); + categorize_ctor_elements (exp, &nz_elts, &count, &must_clear); return nz_elts == 0; } @@ -4902,13 +5024,13 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) { type = lang_hooks.types.type_for_size (BITS_PER_WORD, TYPE_UNSIGNED (type)); - value = convert (type, value); + value = fold_convert (type, value); } if (BYTES_BIG_ENDIAN) value = fold_build2 (LSHIFT_EXPR, type, value, - build_int_cst (NULL_TREE, + build_int_cst (type, BITS_PER_WORD - bitsize)); bitsize = BITS_PER_WORD; mode = word_mode; @@ -5106,13 +5228,17 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) emit_label (loop_start); /* Assign value to element index. */ - position - = convert (ssizetype, - fold_build2 (MINUS_EXPR, TREE_TYPE (index), - index, TYPE_MIN_VALUE (domain))); - position = size_binop (MULT_EXPR, position, - convert (ssizetype, - TYPE_SIZE_UNIT (elttype))); + position = + fold_convert (ssizetype, + fold_build2 (MINUS_EXPR, + TREE_TYPE (index), + index, + TYPE_MIN_VALUE (domain))); + + position = + size_binop (MULT_EXPR, position, + fold_convert (ssizetype, + TYPE_SIZE_UNIT (elttype))); pos_rtx = expand_normal (position); xtarget = offset_address (target, pos_rtx, @@ -5156,9 +5282,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) index, TYPE_MIN_VALUE (domain))); - position = size_binop (MULT_EXPR, index, - convert (ssizetype, - TYPE_SIZE_UNIT (elttype))); + position = + size_binop (MULT_EXPR, index, + fold_convert (ssizetype, + TYPE_SIZE_UNIT (elttype))); xtarget = offset_address (target, expand_normal (position), highest_pow2_factor (position)); @@ -5259,7 +5386,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) } /* Inform later passes that the old value is dead. */ - if (!cleared && REG_P (target)) + if (!cleared && !vector && REG_P (target)) emit_move_insn (target, CONST0_RTX (GET_MODE (target))); /* Store each element of the constructor into the corresponding @@ -5544,6 +5671,13 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, { size_tree = TREE_OPERAND (exp, 1); *punsignedp = BIT_FIELD_REF_UNSIGNED (exp); + + /* For vector types, with the correct size of access, use the mode of + inner type. */ + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE + && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))) + && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp)))) + mode = TYPE_MODE (TREE_TYPE (exp)); } else { @@ -5611,7 +5745,7 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, offset = size_binop (PLUS_EXPR, offset, size_binop (MULT_EXPR, - convert (sizetype, index), + fold_convert (sizetype, index), unit_size)); } break; @@ -5650,7 +5784,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, /* If OFFSET is constant, see if we can return the whole thing as a constant bit position. Otherwise, split it up. */ if (host_integerp (offset, 0) - && 0 != (tem = size_binop (MULT_EXPR, convert (bitsizetype, offset), + && 0 != (tem = size_binop (MULT_EXPR, + fold_convert (bitsizetype, offset), bitsize_unit_node)) && 0 != (tem = size_binop (PLUS_EXPR, tem, bit_offset)) && host_integerp (tem, 0)) @@ -5897,6 +6032,8 @@ force_operand (rtx value, rtx target) case ZERO_EXTEND: case SIGN_EXTEND: case TRUNCATE: + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: convert_move (target, op1, code == ZERO_EXTEND); return target; @@ -6001,6 +6138,19 @@ safe_from_p (rtx x, tree exp, int top_p) return safe_from_p (x, exp, 0); } } + else if (TREE_CODE (exp) == CONSTRUCTOR) + { + constructor_elt *ce; + unsigned HOST_WIDE_INT idx; + + for (idx = 0; + VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce); + idx++) + if ((ce->index != NULL_TREE && !safe_from_p (x, ce->index, 0)) + || !safe_from_p (x, ce->value, 0)) + return 0; + return 1; + } else if (TREE_CODE (exp) == ERROR_MARK) return 1; /* An already-visited SAVE_EXPR? */ else @@ -6104,6 +6254,9 @@ safe_from_p (rtx x, tree exp, int top_p) case tcc_type: /* Should never get a type here. */ gcc_unreachable (); + + case tcc_gimple_stmt: + gcc_unreachable (); } /* If we have an rtl, find any enclosed object. Then see if we conflict @@ -6280,6 +6433,20 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1, } +/* Return a MEM that contains constant EXP. DEFER is as for + output_constant_def and MODIFIER is as for expand_expr. */ + +static rtx +expand_expr_constant (tree exp, int defer, enum expand_modifier modifier) +{ + rtx mem; + + mem = output_constant_def (exp, defer); + if (modifier != EXPAND_INITIALIZER) + mem = use_anchored_address (mem); + return mem; +} + /* A subroutine of expand_expr_addr_expr. Evaluate the address of EXP. The TARGET, TMODE and MODIFIER arguments are as for expand_expr. */ @@ -6301,14 +6468,14 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, exception here is STRING_CST. */ if (TREE_CODE (exp) == CONSTRUCTOR || CONSTANT_CLASS_P (exp)) - return XEXP (output_constant_def (exp, 0), 0); + return XEXP (expand_expr_constant (exp, 0, modifier), 0); /* Everything must be something allowed by is_gimple_addressable. */ switch (TREE_CODE (exp)) { case INDIRECT_REF: /* This case will happen via recursion for &a->b. */ - return expand_expr (TREE_OPERAND (exp, 0), target, tmode, EXPAND_NORMAL); + return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier); case CONST_DECL: /* Recurse and make the output_constant_def clause above handle this. */ @@ -6510,7 +6677,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, /* Handle ERROR_MARK before anybody tries to access its type. */ if (TREE_CODE (exp) == ERROR_MARK - || TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK) + || (!GIMPLE_TUPLE_P (exp) && TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)) { ret = CONST0_RTX (tmode); return ret ? ret : const0_rtx; @@ -6579,8 +6746,8 @@ static rtx expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier, rtx *alt_rtl) { - rtx op0, op1, temp; - tree type = TREE_TYPE (exp); + rtx op0, op1, temp, decl_rtl; + tree type; int unsignedp; enum machine_mode mode; enum tree_code code = TREE_CODE (exp); @@ -6595,8 +6762,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, type) \ : (expr)) - mode = TYPE_MODE (type); - unsignedp = TYPE_UNSIGNED (type); + if (GIMPLE_STMT_P (exp)) + { + type = void_type_node; + mode = VOIDmode; + unsignedp = 0; + } + else + { + type = TREE_TYPE (exp); + mode = TYPE_MODE (type); + unsignedp = TYPE_UNSIGNED (type); + } if (lang_hooks.reduce_bit_field_operations && TREE_CODE (type) == INTEGER_TYPE && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type)) @@ -6701,7 +6878,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case FUNCTION_DECL: case RESULT_DECL: - gcc_assert (DECL_RTL (exp)); + decl_rtl = DECL_RTL (exp); + gcc_assert (decl_rtl); /* Ensure variable marked as used even if it doesn't go through a parser. If it hasn't be used yet, write out an external @@ -6728,27 +6906,24 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, from its initializer, while the initializer is still being parsed. See expand_decl. */ - if (MEM_P (DECL_RTL (exp)) - && REG_P (XEXP (DECL_RTL (exp), 0))) - temp = validize_mem (DECL_RTL (exp)); + if (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0))) + temp = validize_mem (decl_rtl); /* If DECL_RTL is memory, we are in the normal case and either the address is not valid or it is not a register and -fforce-addr is specified, get the address into a register. */ - else if (MEM_P (DECL_RTL (exp)) - && modifier != EXPAND_CONST_ADDRESS - && modifier != EXPAND_SUM - && modifier != EXPAND_INITIALIZER - && (! memory_address_p (DECL_MODE (exp), - XEXP (DECL_RTL (exp), 0)) - || (flag_force_addr - && !REG_P (XEXP (DECL_RTL (exp), 0))))) + else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER) { if (alt_rtl) - *alt_rtl = DECL_RTL (exp); - temp = replace_equiv_address (DECL_RTL (exp), - copy_rtx (XEXP (DECL_RTL (exp), 0))); + *alt_rtl = decl_rtl; + decl_rtl = use_anchored_address (decl_rtl); + if (modifier != EXPAND_CONST_ADDRESS + && modifier != EXPAND_SUM + && (!memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0)) + || (flag_force_addr && !REG_P (XEXP (decl_rtl, 0))))) + temp = replace_equiv_address (decl_rtl, + copy_rtx (XEXP (decl_rtl, 0))); } /* If we got something, return it. But first, set the alignment @@ -6765,8 +6940,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, must be a promoted value. We return a SUBREG of the wanted mode, but mark it so that we know that it was already extended. */ - if (REG_P (DECL_RTL (exp)) - && GET_MODE (DECL_RTL (exp)) != DECL_MODE (exp)) + if (REG_P (decl_rtl) + && GET_MODE (decl_rtl) != DECL_MODE (exp)) { enum machine_mode pmode; @@ -6775,15 +6950,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, pmode = promote_mode (type, DECL_MODE (exp), &unsignedp, (TREE_CODE (exp) == RESULT_DECL || TREE_CODE (exp) == PARM_DECL) ? 1 : 0); - gcc_assert (GET_MODE (DECL_RTL (exp)) == pmode); + gcc_assert (GET_MODE (decl_rtl) == pmode); - temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp)); + temp = gen_lowpart_SUBREG (mode, decl_rtl); SUBREG_PROMOTED_VAR_P (temp) = 1; SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp); return temp; } - return DECL_RTL (exp); + return decl_rtl; case INTEGER_CST: temp = immed_double_const (TREE_INT_CST_LOW (exp), @@ -6801,14 +6976,23 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return temp; case VECTOR_CST: - if (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_INT - || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT) - return const_vector_from_tree (exp); - else - return expand_expr (build_constructor_from_list - (TREE_TYPE (exp), - TREE_VECTOR_CST_ELTS (exp)), - ignore ? const0_rtx : target, tmode, modifier); + { + tree tmp = NULL_TREE; + if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT + || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT) + return const_vector_from_tree (exp); + if (GET_MODE_CLASS (mode) == MODE_INT) + { + tree type_for_mode = lang_hooks.types.type_for_mode (mode, 1); + if (type_for_mode) + tmp = fold_unary (VIEW_CONVERT_EXPR, type_for_mode, exp); + } + if (!tmp) + tmp = build_constructor_from_list (type, + TREE_VECTOR_CST_ELTS (exp)); + return expand_expr (tmp, ignore ? const0_rtx : target, + tmode, modifier); + } case CONST_DECL: return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier); @@ -6852,7 +7036,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, /* ... fall through ... */ case STRING_CST: - temp = output_constant_def (exp, 1); + temp = expand_expr_constant (exp, 1, modifier); /* temp contains a constant address. On RISC machines where a constant address isn't valid, @@ -6953,7 +7137,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, || modifier == EXPAND_CONST_ADDRESS) && TREE_CONSTANT (exp))) { - rtx constructor = output_constant_def (exp, 1); + rtx constructor = expand_expr_constant (exp, 1, modifier); if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER @@ -7576,7 +7760,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return REDUCE_BIT_FIELD (op0); } - op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier); + op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, + modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier); if (GET_MODE (op0) == mode) ; @@ -7638,7 +7823,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, else if (!MEM_P (op0)) { /* If the operand is not a MEM, force it into memory. Since we - are going to be be changing the mode of the MEM, don't call + are going to be changing the mode of the MEM, don't call force_const_mem for constants because we don't allow pool constants to change mode. */ tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); @@ -8024,11 +8209,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, subtarget, &op0, &op1, 0); return expand_divmod (1, code, mode, op0, op1, target, unsignedp); - case FIX_ROUND_EXPR: - case FIX_FLOOR_EXPR: - case FIX_CEIL_EXPR: - gcc_unreachable (); /* Not used for C. */ - case FIX_TRUNC_EXPR: op0 = expand_normal (TREE_OPERAND (exp, 0)); if (target == 0 || modifier == EXPAND_STACK_PARM) @@ -8184,24 +8364,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, emit_move_insn (target, op0); temp = gen_label_rtx (); - - /* If this mode is an integer too wide to compare properly, - compare word by word. Rely on cse to optimize constant cases. */ - if (GET_MODE_CLASS (mode) == MODE_INT - && ! can_compare_p (GE, mode, ccp_jump)) - { - if (code == MAX_EXPR) - do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1, - NULL_RTX, temp); - else - do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target, - NULL_RTX, temp); - } - else - { - do_compare_rtx_and_jump (target, cmpop1, comparison_code, - unsignedp, mode, NULL_RTX, NULL_RTX, temp); - } + do_compare_rtx_and_jump (target, cmpop1, comparison_code, + unsignedp, mode, NULL_RTX, NULL_RTX, temp); } emit_move_insn (target, op1); emit_label (temp); @@ -8419,10 +8583,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, target = expand_vec_cond_expr (exp, target); return target; - case MODIFY_EXPR: + case GIMPLE_MODIFY_STMT: { - tree lhs = TREE_OPERAND (exp, 0); - tree rhs = TREE_OPERAND (exp, 1); + tree lhs = GIMPLE_STMT_OPERAND (exp, 0); + tree rhs = GIMPLE_STMT_OPERAND (exp, 1); gcc_assert (ignore); @@ -8443,14 +8607,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, && integer_onep (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1)))) { rtx label = gen_label_rtx (); - + int value = TREE_CODE (rhs) == BIT_IOR_EXPR; do_jump (TREE_OPERAND (rhs, 1), - TREE_CODE (rhs) == BIT_IOR_EXPR ? label : 0, - TREE_CODE (rhs) == BIT_AND_EXPR ? label : 0); - expand_assignment (lhs, convert (TREE_TYPE (rhs), - (TREE_CODE (rhs) == BIT_IOR_EXPR - ? integer_one_node - : integer_zero_node))); + value ? label : 0, + value ? 0 : label); + expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value)); do_pending_stack_adjust (); emit_label (label); return const0_rtx; @@ -8605,6 +8766,30 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return temp; } + case VEC_EXTRACT_EVEN_EXPR: + case VEC_EXTRACT_ODD_EXPR: + { + expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), + NULL_RTX, &op0, &op1, 0); + this_optab = optab_for_tree_code (code, type); + temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp, + OPTAB_WIDEN); + gcc_assert (temp); + return temp; + } + + case VEC_INTERLEAVE_HIGH_EXPR: + case VEC_INTERLEAVE_LOW_EXPR: + { + expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), + NULL_RTX, &op0, &op1, 0); + this_optab = optab_for_tree_code (code, type); + temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp, + OPTAB_WIDEN); + gcc_assert (temp); + return temp; + } + case VEC_LSHIFT_EXPR: case VEC_RSHIFT_EXPR: { @@ -8612,6 +8797,37 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return target; } + case VEC_UNPACK_HI_EXPR: + case VEC_UNPACK_LO_EXPR: + { + op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); + this_optab = optab_for_tree_code (code, type); + temp = expand_widen_pattern_expr (exp, op0, NULL_RTX, NULL_RTX, + target, unsignedp); + gcc_assert (temp); + return temp; + } + + case VEC_WIDEN_MULT_HI_EXPR: + case VEC_WIDEN_MULT_LO_EXPR: + { + tree oprnd0 = TREE_OPERAND (exp, 0); + tree oprnd1 = TREE_OPERAND (exp, 1); + + expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0); + target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX, + target, unsignedp); + gcc_assert (target); + return target; + } + + case VEC_PACK_MOD_EXPR: + case VEC_PACK_SAT_EXPR: + { + mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); + goto binop; + } + default: return lang_hooks.expand_expr (exp, original_target, tmode, modifier, alt_rtl); @@ -8714,7 +8930,7 @@ is_aligning_offset (tree offset, tree exp) tree string_constant (tree arg, tree *ptr_offset) { - tree array, offset; + tree array, offset, lower_bound; STRIP_NOPS (arg); if (TREE_CODE (arg) == ADDR_EXPR) @@ -8736,6 +8952,20 @@ string_constant (tree arg, tree *ptr_offset) if (TREE_CODE (array) != STRING_CST && TREE_CODE (array) != VAR_DECL) return 0; + + /* Check if the array has a non-zero lower bound. */ + lower_bound = array_ref_low_bound (TREE_OPERAND (arg, 0)); + if (!integer_zerop (lower_bound)) + { + /* If the offset and base aren't both constants, return 0. */ + if (TREE_CODE (lower_bound) != INTEGER_CST) + return 0; + if (TREE_CODE (offset) != INTEGER_CST) + return 0; + /* Adjust offset by the lower bound. */ + offset = size_diffop (fold_convert (sizetype, offset), + fold_convert (sizetype, lower_bound)); + } } else return 0; @@ -8770,7 +9000,7 @@ string_constant (tree arg, tree *ptr_offset) if (TREE_CODE (array) == STRING_CST) { - *ptr_offset = convert (sizetype, offset); + *ptr_offset = fold_convert (sizetype, offset); return array; } else if (TREE_CODE (array) == VAR_DECL) @@ -8797,7 +9027,7 @@ string_constant (tree arg, tree *ptr_offset) /* If variable is bigger than the string literal, OFFSET must be constant and inside of the bounds of the string literal. */ - offset = convert (sizetype, offset); + offset = fold_convert (sizetype, offset); if (compare_tree_int (DECL_SIZE_UNIT (array), length) > 0 && (! host_integerp (offset, 1) || compare_tree_int (offset, length) >= 0)) @@ -8984,6 +9214,17 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap) return 0; icode = setcc_gen_code[(int) code]; + + if (icode == CODE_FOR_nothing) + { + enum machine_mode wmode; + + for (wmode = operand_mode; + icode == CODE_FOR_nothing && wmode != VOIDmode; + wmode = GET_MODE_WIDER_MODE (wmode)) + icode = cstore_optab->handlers[(int) wmode].insn_code; + } + if (icode == CODE_FOR_nothing || (only_cheap && insn_data[(int) icode].operand[0].mode != mode)) { @@ -9029,25 +9270,10 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap) target = gen_reg_rtx (GET_MODE (target)); emit_move_insn (target, invert ? const0_rtx : const1_rtx); - result = compare_from_rtx (op0, op1, code, unsignedp, - operand_mode, NULL_RTX); - if (GET_CODE (result) == CONST_INT) - return (((result == const0_rtx && ! invert) - || (result != const0_rtx && invert)) - ? const0_rtx : const1_rtx); - - /* The code of RESULT may not match CODE if compare_from_rtx - decided to swap its operands and reverse the original code. - - We know that compare_from_rtx returns either a CONST_INT or - a new comparison code, so it is safe to just extract the - code from RESULT. */ - code = GET_CODE (result); - label = gen_label_rtx (); - gcc_assert (bcc_gen_fctn[(int) code]); - - emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label)); + do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX, + NULL_RTX, label); + emit_move_insn (target, invert ? const1_rtx : const0_rtx); emit_label (label); @@ -9109,9 +9335,8 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range, { if (TYPE_MODE (index_type) != index_mode) { - index_expr = convert (lang_hooks.types.type_for_size - (index_bits, 0), index_expr); - index_type = TREE_TYPE (index_expr); + index_type = lang_hooks.types.type_for_size (index_bits, 0); + index_expr = fold_convert (index_type, index_expr); } index = expand_normal (index_expr); @@ -9237,8 +9462,8 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range, return 0; index_expr = fold_build2 (MINUS_EXPR, index_type, - convert (index_type, index_expr), - convert (index_type, minval)); + fold_convert (index_type, index_expr), + fold_convert (index_type, minval)); index = expand_normal (index_expr); do_pending_stack_adjust ();