X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fexpmed.c;h=8e8a63917a1966784b157c96a0fcf27bae0bd546;hb=5865514819db1b7b720f3b1da912b1758c39e2a0;hp=6f4e331154658c4376292f8332a092cb78151792;hpb=b7ba5735b5557bbfdcc5c328d80e2274f63b185a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/expmed.c b/gcc/expmed.c index 6f4e3311546..8e8a63917a1 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -1,7 +1,7 @@ /* Medium-level subroutines: convert bit-field store and extract and shifts, multiplies and divides to rtl instructions. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GCC. @@ -37,6 +37,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "real.h" #include "recog.h" #include "langhooks.h" +#include "target.h" static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, @@ -1126,6 +1127,28 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, return op0; } + /* See if we can get a better vector mode before extracting. */ + if (VECTOR_MODE_P (GET_MODE (op0)) + && !MEM_P (op0) + && GET_MODE_INNER (GET_MODE (op0)) != tmode) + { + enum machine_mode new_mode; + int nunits = GET_MODE_NUNITS (GET_MODE (op0)); + + if (GET_MODE_CLASS (tmode) == MODE_FLOAT) + new_mode = MIN_MODE_VECTOR_FLOAT; + else + new_mode = MIN_MODE_VECTOR_INT; + + for (; new_mode != VOIDmode ; new_mode = GET_MODE_WIDER_MODE (new_mode)) + if (GET_MODE_NUNITS (new_mode) == nunits + && GET_MODE_INNER (new_mode) == tmode + && targetm.vector_mode_supported_p (new_mode)) + break; + if (new_mode != VOIDmode) + op0 = gen_lowpart (new_mode, op0); + } + /* Use vec_extract patterns for extracting parts of vectors whenever available. */ if (VECTOR_MODE_P (GET_MODE (op0)) @@ -1176,6 +1199,8 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, { emit_insn (seq); emit_insn (pat); + if (mode0 != mode) + return gen_lowpart (tmode, dest); return dest; } } @@ -2217,7 +2242,9 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted, && GET_CODE (op1) == CONST_INT && INTVAL (op1) > 0 && INTVAL (op1) < GET_MODE_BITSIZE (mode) - && shift_cost[mode][INTVAL (op1)] > INTVAL (op1) * add_cost[mode]) + && INTVAL (op1) < MAX_BITS_PER_WORD + && shift_cost[mode][INTVAL (op1)] > INTVAL (op1) * add_cost[mode] + && shift_cost[mode][INTVAL (op1)] != MAX_COST) { int i; for (i = 0; i < INTVAL (op1); i++) @@ -2954,10 +2981,9 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val, int opno; enum machine_mode nmode; - /* Avoid referencing memory over and over. - For speed, but also for correctness when mem is volatile. */ - if (MEM_P (op0)) - op0 = force_reg (mode, op0); + /* Avoid referencing memory over and over and invalid sharing + on SUBREGs. */ + op0 = force_reg (mode, op0); /* ACCUM starts out either as OP0 or as a zero, depending on the first operation. */ @@ -3068,7 +3094,8 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val, insn = get_last_insn (); set_unique_reg_note (insn, REG_EQUAL, - gen_rtx_MULT (nmode, tem, GEN_INT (val_so_far))); + gen_rtx_MULT (nmode, tem, + GEN_INT (val_so_far))); } if (variant == negate_variant) @@ -4147,7 +4174,14 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode, int lgup, post_shift; rtx mlr; HOST_WIDE_INT d = INTVAL (op1); - unsigned HOST_WIDE_INT abs_d = d >= 0 ? d : -d; + unsigned HOST_WIDE_INT abs_d; + + /* Since d might be INT_MIN, we have to cast to + unsigned HOST_WIDE_INT before negating to avoid + undefined signed overflow. */ + abs_d = (d >= 0 + ? (unsigned HOST_WIDE_INT) d + : - (unsigned HOST_WIDE_INT) d); /* n rem d = n rem -d */ if (rem_flag && d < 0) @@ -4974,17 +5008,17 @@ make_tree (tree type, rtx x) case CONST_VECTOR: { - int i, units; - rtx elt; + int units = CONST_VECTOR_NUNITS (x); + tree itype = TREE_TYPE (type); tree t = NULL_TREE; + int i; - units = CONST_VECTOR_NUNITS (x); /* Build a tree with vector elements. */ for (i = units - 1; i >= 0; --i) { - elt = CONST_VECTOR_ELT (x, i); - t = tree_cons (NULL_TREE, make_tree (type, elt), t); + rtx elt = CONST_VECTOR_ELT (x, i); + t = tree_cons (NULL_TREE, make_tree (itype, elt), t); } return build_vector (type, t); @@ -5042,6 +5076,15 @@ make_tree (tree type, rtx x) GET_CODE (x) == ZERO_EXTEND); return fold_convert (type, make_tree (t, XEXP (x, 0))); + case CONST: + return make_tree (type, XEXP (x, 0)); + + case SYMBOL_REF: + t = SYMBOL_REF_DECL (x); + if (t) + return fold_convert (type, build_fold_addr_expr (t)); + /* else fall through. */ + default: t = build_decl (VAR_DECL, NULL_TREE, type); @@ -5080,6 +5123,77 @@ expand_and (enum machine_mode mode, rtx op0, rtx op1, rtx target) return target; } +/* Helper function for emit_store_flag. */ +static rtx +emit_store_flag_1 (rtx target, rtx subtarget, enum machine_mode mode, + int normalizep) +{ + rtx op0; + enum machine_mode target_mode = GET_MODE (target); + + /* If we are converting to a wider mode, first convert to + TARGET_MODE, then normalize. This produces better combining + opportunities on machines that have a SIGN_EXTRACT when we are + testing a single bit. This mostly benefits the 68k. + + If STORE_FLAG_VALUE does not have the sign bit set when + interpreted in MODE, we can do this conversion as unsigned, which + is usually more efficient. */ + if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (mode)) + { + convert_move (target, subtarget, + (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + && 0 == (STORE_FLAG_VALUE + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (mode) -1)))); + op0 = target; + mode = target_mode; + } + else + op0 = subtarget; + + /* If we want to keep subexpressions around, don't reuse our last + target. */ + if (optimize) + subtarget = 0; + + /* Now normalize to the proper value in MODE. Sometimes we don't + have to do anything. */ + if (normalizep == 0 || normalizep == STORE_FLAG_VALUE) + ; + /* STORE_FLAG_VALUE might be the most negative number, so write + the comparison this way to avoid a compiler-time warning. */ + else if (- normalizep == STORE_FLAG_VALUE) + op0 = expand_unop (mode, neg_optab, op0, subtarget, 0); + + /* We don't want to use STORE_FLAG_VALUE < 0 below since this makes + it hard to use a value of just the sign bit due to ANSI integer + constant typing rules. */ + else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && (STORE_FLAG_VALUE + & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))) + op0 = expand_shift (RSHIFT_EXPR, mode, op0, + size_int (GET_MODE_BITSIZE (mode) - 1), subtarget, + normalizep == 1); + else + { + gcc_assert (STORE_FLAG_VALUE & 1); + + op0 = expand_and (mode, op0, const1_rtx, subtarget); + if (normalizep == -1) + op0 = expand_unop (mode, neg_optab, op0, op0, 0); + } + + /* If we were converting to a smaller mode, do the conversion now. */ + if (target_mode != mode) + { + convert_move (target, op0, 0); + return target; + } + else + return op0; +} + /* Emit a store-flags instruction for comparison CODE on OP0 and OP1 and storing in TARGET. Normally return TARGET. Return 0 if that cannot be done. @@ -5169,12 +5283,14 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, { rtx op00, op01, op0both; - /* Do a logical OR or AND of the two words and compare the result. */ + /* Do a logical OR or AND of the two words and compare the + result. */ op00 = simplify_gen_subreg (word_mode, op0, mode, 0); op01 = simplify_gen_subreg (word_mode, op0, mode, UNITS_PER_WORD); op0both = expand_binop (word_mode, op1 == const0_rtx ? ior_optab : and_optab, - op00, op01, NULL_RTX, unsignedp, OPTAB_DIRECT); + op00, op01, NULL_RTX, unsignedp, + OPTAB_DIRECT); if (op0both != 0) return emit_store_flag (target, code, op0both, op1, word_mode, @@ -5186,15 +5302,13 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, /* If testing the sign bit, can just test on high word. */ op0h = simplify_gen_subreg (word_mode, op0, mode, - subreg_highpart_offset (word_mode, mode)); + subreg_highpart_offset (word_mode, + mode)); return emit_store_flag (target, code, op0h, op1, word_mode, unsignedp, normalizep); } } - /* From now on, we won't change CODE, so set ICODE now. */ - icode = setcc_gen_code[(int) code]; - /* If this is A < 0 or A >= 0, we can do this by taking the ones complement of A (for GE) and shifting the sign bit to the low bit. */ if (op1 == const0_rtx && (code == LT || code == GE) @@ -5202,7 +5316,8 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, && (normalizep || STORE_FLAG_VALUE == 1 || (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode)) - == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))))) + == ((unsigned HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (mode) - 1)))))) { subtarget = target; @@ -5237,6 +5352,8 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, return op0; } + icode = setcc_gen_code[(int) code]; + if (icode != CODE_FOR_nothing) { insn_operand_predicate_fn pred; @@ -5294,72 +5411,65 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, if (pattern) { emit_insn (pattern); + return emit_store_flag_1 (target, subtarget, compare_mode, + normalizep); + } + } + else + { + /* We don't have an scc insn, so try a cstore insn. */ - /* If we are converting to a wider mode, first convert to - TARGET_MODE, then normalize. This produces better combining - opportunities on machines that have a SIGN_EXTRACT when we are - testing a single bit. This mostly benefits the 68k. + for (compare_mode = mode; compare_mode != VOIDmode; + compare_mode = GET_MODE_WIDER_MODE (compare_mode)) + { + icode = cstore_optab->handlers[(int) compare_mode].insn_code; + if (icode != CODE_FOR_nothing) + break; + } + + if (icode != CODE_FOR_nothing) + { + enum machine_mode result_mode + = insn_data[(int) icode].operand[0].mode; + rtx cstore_op0 = op0; + rtx cstore_op1 = op1; + + do_pending_stack_adjust (); + last = get_last_insn (); - If STORE_FLAG_VALUE does not have the sign bit set when - interpreted in COMPARE_MODE, we can do this conversion as - unsigned, which is usually more efficient. */ - if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (compare_mode)) + if (compare_mode != mode) { - convert_move (target, subtarget, - (GET_MODE_BITSIZE (compare_mode) - <= HOST_BITS_PER_WIDE_INT) - && 0 == (STORE_FLAG_VALUE - & ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (compare_mode) -1)))); - op0 = target; - compare_mode = target_mode; + cstore_op0 = convert_modes (compare_mode, mode, cstore_op0, + unsignedp); + cstore_op1 = convert_modes (compare_mode, mode, cstore_op1, + unsignedp); } - else - op0 = subtarget; + + if (!insn_data[(int) icode].operand[2].predicate (cstore_op0, + compare_mode)) + cstore_op0 = copy_to_mode_reg (compare_mode, cstore_op0); - /* If we want to keep subexpressions around, don't reuse our - last target. */ + if (!insn_data[(int) icode].operand[3].predicate (cstore_op1, + compare_mode)) + cstore_op1 = copy_to_mode_reg (compare_mode, cstore_op1); - if (optimize) - subtarget = 0; + comparison = gen_rtx_fmt_ee (code, result_mode, cstore_op0, + cstore_op1); + subtarget = target; - /* Now normalize to the proper value in COMPARE_MODE. Sometimes - we don't have to do anything. */ - if (normalizep == 0 || normalizep == STORE_FLAG_VALUE) - ; - /* STORE_FLAG_VALUE might be the most negative number, so write - the comparison this way to avoid a compiler-time warning. */ - else if (- normalizep == STORE_FLAG_VALUE) - op0 = expand_unop (compare_mode, neg_optab, op0, subtarget, 0); - - /* We don't want to use STORE_FLAG_VALUE < 0 below since this - makes it hard to use a value of just the sign bit due to - ANSI integer constant typing rules. */ - else if (GET_MODE_BITSIZE (compare_mode) <= HOST_BITS_PER_WIDE_INT - && (STORE_FLAG_VALUE - & ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (compare_mode) - 1)))) - op0 = expand_shift (RSHIFT_EXPR, compare_mode, op0, - size_int (GET_MODE_BITSIZE (compare_mode) - 1), - subtarget, normalizep == 1); - else - { - gcc_assert (STORE_FLAG_VALUE & 1); - - op0 = expand_and (compare_mode, op0, const1_rtx, subtarget); - if (normalizep == -1) - op0 = expand_unop (compare_mode, neg_optab, op0, op0, 0); - } + if (optimize || !(insn_data[(int) icode].operand[0].predicate + (subtarget, result_mode))) + subtarget = gen_reg_rtx (result_mode); + + pattern = GEN_FCN (icode) (subtarget, comparison, cstore_op0, + cstore_op1); - /* If we were converting to a smaller mode, do the - conversion now. */ - if (target_mode != compare_mode) + if (pattern) { - convert_move (target, op0, 0); - return target; + emit_insn (pattern); + return emit_store_flag_1 (target, subtarget, result_mode, + normalizep); } - else - return op0; } }