X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fexpmed.c;h=92167f148ab3fbc2e2a80a9adb8fb06a16549f14;hp=748274741f5388631ab099599c24e4279d52cbda;hb=4bb60ec7c74253ba77870bceced0e3fb31cf39d2;hpb=6eecb88e2059d0860ca7897271eb9adf5756d2cd diff --git a/gcc/expmed.c b/gcc/expmed.c index 748274741f5..92167f148ab 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -47,9 +47,15 @@ struct target_expmed *this_target_expmed = &default_target_expmed; static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, - unsigned HOST_WIDE_INT, rtx); + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, + rtx); static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT, - unsigned HOST_WIDE_INT, rtx); + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, + rtx); static rtx extract_fixed_bit_field (enum machine_mode, rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, @@ -333,7 +339,10 @@ mode_for_extraction (enum extraction_pattern pattern, int opno) static bool store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, - unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode, + unsigned HOST_WIDE_INT bitnum, + unsigned HOST_WIDE_INT bitregion_start, + unsigned HOST_WIDE_INT bitregion_end, + enum machine_mode fieldmode, rtx value, bool fallback_p) { unsigned int unit @@ -455,6 +464,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, /* We may be accessing data outside the field, which means we can alias adjacent data. */ + /* ?? not always for C++0x memory model ?? */ if (MEM_P (op0)) { op0 = shallow_copy_rtx (op0); @@ -547,7 +557,9 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, if (!store_bit_field_1 (op0, MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD), - bitnum + bit_offset, word_mode, + bitnum + bit_offset, + bitregion_start, bitregion_end, + word_mode, value_word, fallback_p)) { delete_insns_since (last); @@ -635,9 +647,8 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, X) 0)) is (reg:N X). */ if (GET_CODE (xop0) == SUBREG && REG_P (SUBREG_REG (xop0)) - && (!TRULY_NOOP_TRUNCATION - (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (xop0))), - GET_MODE_BITSIZE (op_mode)))) + && (!TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (SUBREG_REG (xop0)), + op_mode))) { rtx tem = gen_reg_rtx (op_mode); emit_move_insn (tem, xop0); @@ -711,6 +722,10 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, if (HAVE_insv && MEM_P (op0)) { enum machine_mode bestmode; + unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE; + + if (bitregion_end) + maxbits = bitregion_end - bitregion_start + 1; /* Get the mode to use for inserting into this field. If OP0 is BLKmode, get the smallest mode consistent with the alignment. If @@ -718,9 +733,12 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, mode. Otherwise, use the smallest mode containing the field. */ if (GET_MODE (op0) == BLKmode + || GET_MODE_BITSIZE (GET_MODE (op0)) > maxbits || (op_mode != MAX_MACHINE_MODE && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode))) - bestmode = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0), + bestmode = get_best_mode (bitsize, bitnum, + bitregion_start, bitregion_end, + MEM_ALIGN (op0), (op_mode == MAX_MACHINE_MODE ? VOIDmode : op_mode), MEM_VOLATILE_P (op0)); @@ -749,6 +767,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, the unit. */ tempreg = copy_to_reg (xop0); if (store_bit_field_1 (tempreg, bitsize, xbitpos, + bitregion_start, bitregion_end, fieldmode, orig_value, false)) { emit_move_insn (xop0, tempreg); @@ -761,21 +780,59 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, if (!fallback_p) return false; - store_fixed_bit_field (op0, offset, bitsize, bitpos, value); + store_fixed_bit_field (op0, offset, bitsize, bitpos, + bitregion_start, bitregion_end, value); return true; } /* Generate code to store value from rtx VALUE into a bit-field within structure STR_RTX containing BITSIZE bits starting at bit BITNUM. + + BITREGION_START is bitpos of the first bitfield in this region. + BITREGION_END is the bitpos of the ending bitfield in this region. + These two fields are 0, if the C++ memory model does not apply, + or we are not interested in keeping track of bitfield regions. + FIELDMODE is the machine-mode of the FIELD_DECL node for this field. */ void store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, - unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode, + unsigned HOST_WIDE_INT bitnum, + unsigned HOST_WIDE_INT bitregion_start, + unsigned HOST_WIDE_INT bitregion_end, + enum machine_mode fieldmode, rtx value) { - if (!store_bit_field_1 (str_rtx, bitsize, bitnum, fieldmode, value, true)) + /* Under the C++0x memory model, we must not touch bits outside the + bit region. Adjust the address to start at the beginning of the + bit region. */ + if (MEM_P (str_rtx) + && bitregion_start > 0) + { + enum machine_mode bestmode; + enum machine_mode op_mode; + unsigned HOST_WIDE_INT offset; + + op_mode = mode_for_extraction (EP_insv, 3); + if (op_mode == MAX_MACHINE_MODE) + op_mode = VOIDmode; + + offset = bitregion_start / BITS_PER_UNIT; + bitnum -= bitregion_start; + bitregion_end -= bitregion_start; + bitregion_start = 0; + bestmode = get_best_mode (bitsize, bitnum, + bitregion_start, bitregion_end, + MEM_ALIGN (str_rtx), + op_mode, + MEM_VOLATILE_P (str_rtx)); + str_rtx = adjust_address (str_rtx, bestmode, offset); + } + + if (!store_bit_field_1 (str_rtx, bitsize, bitnum, + bitregion_start, bitregion_end, + fieldmode, value, true)) gcc_unreachable (); } @@ -791,7 +848,10 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, static void store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT bitsize, - unsigned HOST_WIDE_INT bitpos, rtx value) + unsigned HOST_WIDE_INT bitpos, + unsigned HOST_WIDE_INT bitregion_start, + unsigned HOST_WIDE_INT bitregion_end, + rtx value) { enum machine_mode mode; unsigned int total_bits = BITS_PER_WORD; @@ -812,12 +872,19 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, /* Special treatment for a bit field split across two registers. */ if (bitsize + bitpos > BITS_PER_WORD) { - store_split_bit_field (op0, bitsize, bitpos, value); + store_split_bit_field (op0, bitsize, bitpos, + bitregion_start, bitregion_end, + value); return; } } else { + unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE; + + if (bitregion_end) + maxbits = bitregion_end - bitregion_start + 1; + /* Get the proper mode to use for this field. We want a mode that includes the entire field. If such a mode would be larger than a word, we won't be doing the extraction the normal way. @@ -830,10 +897,12 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, if (MEM_VOLATILE_P (op0) && GET_MODE_BITSIZE (GET_MODE (op0)) > 0 + && GET_MODE_BITSIZE (GET_MODE (op0)) <= maxbits && flag_strict_volatile_bitfields > 0) mode = GET_MODE (op0); else mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, + bitregion_start, bitregion_end, MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0)); if (mode == VOIDmode) @@ -841,7 +910,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, /* The only way this should occur is if the field spans word boundaries. */ store_split_bit_field (op0, bitsize, bitpos + offset * BITS_PER_UNIT, - value); + bitregion_start, bitregion_end, value); return; } @@ -961,7 +1030,10 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, static void store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize, - unsigned HOST_WIDE_INT bitpos, rtx value) + unsigned HOST_WIDE_INT bitpos, + unsigned HOST_WIDE_INT bitregion_start, + unsigned HOST_WIDE_INT bitregion_end, + rtx value) { unsigned int unit; unsigned int bitsdone = 0; @@ -1076,7 +1148,7 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize, it is just an out-of-bounds access. Ignore it. */ if (word != const0_rtx) store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize, - thispos, part); + thispos, bitregion_start, bitregion_end, part); bitsdone += thissize; } } @@ -1304,8 +1376,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ? bitpos + bitsize == BITS_PER_WORD : bitpos == 0))) && ((!MEM_P (op0) - && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode1), - GET_MODE_BITSIZE (GET_MODE (op0))) + && TRULY_NOOP_TRUNCATION_MODES_P (mode1, GET_MODE (op0)) && GET_MODE_SIZE (mode1) != 0 && byte_offset % GET_MODE_SIZE (mode1) == 0) || (MEM_P (op0) @@ -1341,7 +1412,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD; unsigned int i; - if (target == 0 || !REG_P (target)) + if (target == 0 || !REG_P (target) || !valid_multiword_target_p (target)) target = gen_reg_rtx (mode); /* Indicate for flow that the entire target reg is being set. */ @@ -1475,12 +1546,11 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, mode. Instead, create a temporary and use convert_move to set the target. */ if (REG_P (xtarget) - && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (xtarget)), - GET_MODE_BITSIZE (ext_mode))) + && TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (xtarget), ext_mode)) { xtarget = gen_lowpart (ext_mode, xtarget); - if (GET_MODE_SIZE (ext_mode) - > GET_MODE_SIZE (GET_MODE (xspec_target))) + if (GET_MODE_PRECISION (ext_mode) + > GET_MODE_PRECISION (GET_MODE (xspec_target))) xspec_target_subreg = xtarget; } else @@ -1518,7 +1588,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, if (GET_MODE (op0) == BLKmode || (ext_mode != MAX_MACHINE_MODE && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (ext_mode))) - bestmode = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0), + bestmode = get_best_mode (bitsize, bitnum, 0, 0, MEM_ALIGN (op0), (ext_mode == MAX_MACHINE_MODE ? VOIDmode : ext_mode), MEM_VOLATILE_P (op0)); @@ -1644,7 +1714,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0, mode = tmode; } else - mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, + mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, 0, 0, MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0)); if (mode == VOIDmode) @@ -1769,8 +1839,6 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0, /* To extract a signed bit-field, first shift its msb to the msb of the word, then arithmetic-shift its lsb to the lsb of the word. */ op0 = force_reg (mode, op0); - if (mode != tmode) - target = 0; /* Find the narrowest integer mode that contains the field. */ @@ -1782,6 +1850,9 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0, break; } + if (mode != tmode) + target = 0; + if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos)) { int amount = GET_MODE_BITSIZE (mode) - (bitsize + bitpos); @@ -2032,14 +2103,14 @@ expand_dec (rtx target, rtx dec) /* Output a shift instruction for expression code CODE, with SHIFTED being the rtx for the value to shift, - and AMOUNT the tree for the amount to shift by. + and AMOUNT the rtx for the amount to shift by. Store the result in the rtx TARGET, if that is convenient. If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic. Return the rtx for where the value is. */ -rtx -expand_variable_shift (enum tree_code code, enum machine_mode mode, rtx shifted, - tree amount, rtx target, int unsignedp) +static rtx +expand_shift_1 (enum tree_code code, enum machine_mode mode, rtx shifted, + rtx amount, rtx target, int unsignedp) { rtx op1, temp = 0; int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR); @@ -2053,7 +2124,7 @@ expand_variable_shift (enum tree_code code, enum machine_mode mode, rtx shifted, int attempt; bool speed = optimize_insn_for_speed_p (); - op1 = expand_normal (amount); + op1 = amount; op1_mode = GET_MODE (op1); /* Determine whether the shift/rotate amount is a vector, or scalar. If the @@ -2092,7 +2163,7 @@ expand_variable_shift (enum tree_code code, enum machine_mode mode, rtx shifted, if (code == LSHIFT_EXPR && CONST_INT_P (op1) && INTVAL (op1) > 0 - && INTVAL (op1) < GET_MODE_BITSIZE (mode) + && INTVAL (op1) < GET_MODE_PRECISION (mode) && INTVAL (op1) < MAX_BITS_PER_WORD && shift_cost[speed][mode][INTVAL (op1)] > INTVAL (op1) * add_cost[speed][mode] && shift_cost[speed][mode][INTVAL (op1)] != MAX_COST) @@ -2138,25 +2209,26 @@ expand_variable_shift (enum tree_code code, enum machine_mode mode, rtx shifted, code below. */ rtx subtarget = target == shifted ? 0 : target; - tree new_amount, other_amount; + rtx new_amount, other_amount; rtx temp1; - tree type = TREE_TYPE (amount); - if (GET_MODE (op1) != TYPE_MODE (type) - && GET_MODE (op1) != VOIDmode) - op1 = convert_to_mode (TYPE_MODE (type), op1, 1); - new_amount = make_tree (type, op1); - other_amount - = fold_build2 (MINUS_EXPR, type, - build_int_cst (type, GET_MODE_BITSIZE (mode)), - new_amount); + + new_amount = op1; + if (CONST_INT_P (op1)) + other_amount = GEN_INT (GET_MODE_BITSIZE (mode) + - INTVAL (op1)); + else + other_amount + = simplify_gen_binary (MINUS, GET_MODE (op1), + GEN_INT (GET_MODE_PRECISION (mode)), + op1); shifted = force_reg (mode, shifted); - temp = expand_variable_shift (left ? LSHIFT_EXPR : RSHIFT_EXPR, - mode, shifted, new_amount, 0, 1); - temp1 = expand_variable_shift (left ? RSHIFT_EXPR : LSHIFT_EXPR, - mode, shifted, other_amount, - subtarget, 1); + temp = expand_shift_1 (left ? LSHIFT_EXPR : RSHIFT_EXPR, + mode, shifted, new_amount, 0, 1); + temp1 = expand_shift_1 (left ? RSHIFT_EXPR : LSHIFT_EXPR, + mode, shifted, other_amount, + subtarget, 1); return expand_binop (mode, ior_optab, temp, temp1, target, unsignedp, methods); } @@ -2211,12 +2283,25 @@ rtx expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted, int amount, rtx target, int unsignedp) { - /* ??? With re-writing expand_shift we could avoid going through a - tree for the shift amount and directly do GEN_INT (amount). */ - return expand_variable_shift (code, mode, shifted, - build_int_cst (integer_type_node, amount), - target, unsignedp); + return expand_shift_1 (code, mode, + shifted, GEN_INT (amount), target, unsignedp); } + +/* Output a shift instruction for expression code CODE, + with SHIFTED being the rtx for the value to shift, + and AMOUNT the tree for the amount to shift by. + Store the result in the rtx TARGET, if that is convenient. + If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic. + Return the rtx for where the value is. */ + +rtx +expand_variable_shift (enum tree_code code, enum machine_mode mode, rtx shifted, + tree amount, rtx target, int unsignedp) +{ + return expand_shift_1 (code, mode, + shifted, expand_normal (amount), target, unsignedp); +} + /* Indicates the type of fixup needed after a constant multiplication. BASIC_VARIANT means no fixup is needed, NEGATE_VARIANT means that @@ -3100,7 +3185,7 @@ expand_widening_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, this_optab == umul_widen_optab)) && CONST_INT_P (cop1) && (INTVAL (cop1) >= 0 - || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)) + || HWI_COMPUTABLE_MODE_P (mode))) { HOST_WIDE_INT coeff = INTVAL (cop1); int max_cost; @@ -3447,7 +3532,7 @@ expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1, gcc_assert (!SCALAR_FLOAT_MODE_P (mode)); /* We can't support modes wider than HOST_BITS_PER_INT. */ - gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT); + gcc_assert (HWI_COMPUTABLE_MODE_P (mode)); cnst1 = INTVAL (op1) & GET_MODE_MASK (mode); @@ -5024,10 +5109,8 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code, if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (result_mode)) { convert_move (target, subtarget, - (GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT) - && 0 == (STORE_FLAG_VALUE - & ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (result_mode) -1)))); + val_signbit_known_clear_p (result_mode, + STORE_FLAG_VALUE)); op0 = target; result_mode = target_mode; } @@ -5051,9 +5134,7 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code, /* 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 (result_mode) <= HOST_BITS_PER_WIDE_INT - && (STORE_FLAG_VALUE - & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (result_mode) - 1)))) + else if (val_signbit_known_set_p (result_mode, STORE_FLAG_VALUE)) op0 = expand_shift (RSHIFT_EXPR, result_mode, op0, GET_MODE_BITSIZE (result_mode) - 1, subtarget, normalizep == 1); @@ -5191,9 +5272,9 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1, target = gen_reg_rtx (target_mode); convert_move (target, tem, - 0 == ((normalizep ? normalizep : STORE_FLAG_VALUE) - & ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (word_mode) -1)))); + !val_signbit_known_set_p (word_mode, + (normalizep ? normalizep + : STORE_FLAG_VALUE))); return target; } } @@ -5203,10 +5284,7 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1, if (op1 == const0_rtx && (code == LT || code == GE) && GET_MODE_CLASS (mode) == MODE_INT && (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)))))) + || val_signbit_p (mode, STORE_FLAG_VALUE))) { subtarget = target; @@ -5315,9 +5393,7 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, if (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1) normalizep = STORE_FLAG_VALUE; - else if (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))) + else if (val_signbit_p (mode, STORE_FLAG_VALUE)) ; else return 0;