From b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180 Mon Sep 17 00:00:00 2001 From: kan Date: Fri, 11 Jul 2003 03:40:53 +0000 Subject: Gcc 3.3.1-pre as of 2003-07-11. --- contrib/gcc/expmed.c | 190 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 114 insertions(+), 76 deletions(-) (limited to 'contrib/gcc/expmed.c') diff --git a/contrib/gcc/expmed.c b/contrib/gcc/expmed.c index ce89335..2274bda 100644 --- a/contrib/gcc/expmed.c +++ b/contrib/gcc/expmed.c @@ -33,6 +33,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "optabs.h" #include "real.h" #include "recog.h" +#include "langhooks.h" static void store_fixed_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, @@ -53,7 +54,7 @@ static rtx extract_split_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT, static void do_cmp_and_jump PARAMS ((rtx, rtx, enum rtx_code, enum machine_mode, rtx)); -/* Non-zero means divides or modulus operations are relatively cheap for +/* Nonzero means divides or modulus operations are relatively cheap for powers of two, so don't use branches; emit the operation instead. Usually, this will mean that the MD file will emit non-branch sequences. */ @@ -103,16 +104,15 @@ static int mul_highpart_cost[NUM_MACHINE_MODES]; void init_expmed () { - /* This is "some random pseudo register" for purposes of calling recog - to see what insns exist. */ - rtx reg = gen_rtx_REG (word_mode, 10000); - rtx shift_insn, shiftadd_insn, shiftsub_insn; + rtx reg, shift_insn, shiftadd_insn, shiftsub_insn; int dummy; int m; enum machine_mode mode, wider_mode; start_sequence (); + /* This is "some random pseudo register" for purposes of calling recog + to see what insns exist. */ reg = gen_rtx_REG (word_mode, 10000); zero_cost = rtx_cost (const0_rtx, 0); @@ -143,19 +143,18 @@ init_expmed () for (m = 1; m < MAX_BITS_PER_WORD; m++) { + rtx c_int = GEN_INT ((HOST_WIDE_INT) 1 << m); shift_cost[m] = shiftadd_cost[m] = shiftsub_cost[m] = 32000; XEXP (SET_SRC (PATTERN (shift_insn)), 1) = GEN_INT (m); if (recog (PATTERN (shift_insn), shift_insn, &dummy) >= 0) shift_cost[m] = rtx_cost (SET_SRC (PATTERN (shift_insn)), SET); - XEXP (XEXP (SET_SRC (PATTERN (shiftadd_insn)), 0), 1) - = GEN_INT ((HOST_WIDE_INT) 1 << m); + XEXP (XEXP (SET_SRC (PATTERN (shiftadd_insn)), 0), 1) = c_int; if (recog (PATTERN (shiftadd_insn), shiftadd_insn, &dummy) >= 0) shiftadd_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftadd_insn)), SET); - XEXP (XEXP (SET_SRC (PATTERN (shiftsub_insn)), 0), 1) - = GEN_INT ((HOST_WIDE_INT) 1 << m); + XEXP (XEXP (SET_SRC (PATTERN (shiftsub_insn)), 0), 1) = c_int; if (recog (PATTERN (shiftsub_insn), shiftsub_insn, &dummy) >= 0) shiftsub_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftsub_insn)), SET); } @@ -347,7 +346,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size) && (GET_CODE (op0) != MEM ? ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD || GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode)) - && byte_offset % GET_MODE_SIZE (fieldmode) == 0) + && byte_offset % GET_MODE_SIZE (fieldmode) == 0) : (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0)) || (offset * BITS_PER_UNIT % bitsize == 0 && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0)))) @@ -535,7 +534,9 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size) structure fields. */ if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT && GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT) - value = gen_lowpart (word_mode, value); + value = gen_lowpart ((GET_MODE (value) == VOIDmode + ? word_mode : int_mode_for_mode (GET_MODE (value))), + value); /* Now OFFSET is nonzero only if OP0 is memory and is therefore always measured in bytes. */ @@ -656,7 +657,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size) value1 = gen_lowpart (maxmode, value1); } else if (GET_CODE (value) == CONST_INT) - value1 = GEN_INT (trunc_int_for_mode (INTVAL (value), maxmode)); + value1 = gen_int_mode (INTVAL (value), maxmode); else if (!CONSTANT_P (value)) /* Parse phase is supposed to make VALUE's data type match that of the component reference, which is a type @@ -675,7 +676,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size) if (pat) emit_insn (pat); else - { + { delete_insns_since (last); store_fixed_bit_field (op0, offset, bitsize, bitpos, value); } @@ -737,8 +738,8 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value) mode = GET_MODE (op0); if (GET_MODE_BITSIZE (mode) == 0 - || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode)) - mode = word_mode; + || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode)) + mode = word_mode; mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0)); @@ -1032,25 +1033,15 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, if (tmode == VOIDmode) tmode = mode; + while (GET_CODE (op0) == SUBREG) { - int outer_size = GET_MODE_BITSIZE (GET_MODE (op0)); - int inner_size = GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))); - - offset += SUBREG_BYTE (op0) / UNITS_PER_WORD; - - inner_size = MIN (inner_size, BITS_PER_WORD); - - if (BYTES_BIG_ENDIAN && (outer_size < inner_size)) + bitpos += SUBREG_BYTE (op0) * BITS_PER_UNIT; + if (bitpos > unit) { - bitpos += inner_size - outer_size; - if (bitpos > unit) - { - offset += (bitpos / unit); - bitpos %= unit; - } + offset += (bitpos / unit); + bitpos %= unit; } - op0 = SUBREG_REG (op0); } @@ -1087,9 +1078,13 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, set_mem_expr (op0, 0); } - /* ??? We currently assume TARGET is at least as big as BITSIZE. - If that's wrong, the solution is to test for it and set TARGET to 0 - if needed. */ + /* Extraction of a full-word or multi-word value from a structure + in a register or aligned memory can be done with just a SUBREG. + A subword value in the least significant part of a register + can also be extracted with a SUBREG. For this, we need the + byte offset of the value in op0. */ + + byte_offset = bitpos / BITS_PER_UNIT + offset * UNITS_PER_WORD; /* If OP0 is a register, BITPOS must count within a word. But as we have it, it counts within whatever size OP0 now has. @@ -1099,18 +1094,13 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, && unit > GET_MODE_BITSIZE (GET_MODE (op0))) bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0)); - /* Extracting a full-word or multi-word value - from a structure in a register or aligned memory. - This can be done with just SUBREG. - So too extracting a subword value in - the least significant part of the register. */ - - byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT - + (offset * UNITS_PER_WORD); + /* ??? We currently assume TARGET is at least as big as BITSIZE. + If that's wrong, the solution is to test for it and set TARGET to 0 + if needed. */ mode1 = (VECTOR_MODE_P (tmode) - ? mode - : mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0)); + ? mode + : mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0)); if (((GET_CODE (op0) != MEM && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), @@ -1928,12 +1918,12 @@ expand_shift (code, mode, shifted, amount, target, unsignedp) if (SHIFT_COUNT_TRUNCATED) { if (GET_CODE (op1) == CONST_INT - && ((unsigned HOST_WIDE_INT) INTVAL (op1) >= + && ((unsigned HOST_WIDE_INT) INTVAL (op1) >= (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode))) - op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1) + op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1) % GET_MODE_BITSIZE (mode)); else if (GET_CODE (op1) == SUBREG - && SUBREG_BYTE (op1) == 0) + && subreg_lowpart_p (op1)) op1 = SUBREG_REG (op1); } #endif @@ -2566,8 +2556,8 @@ expand_mult (mode, op0, op1, target, unsignedp) there is no difference between signed and unsigned. */ op0 = expand_binop (mode, ! unsignedp - && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT) - ? smulv_optab : smul_optab, + && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT) + ? smulv_optab : smul_optab, op0, op1, target, unsignedp, OPTAB_LIB_WIDEN); if (op0 == 0) abort (); @@ -2790,7 +2780,7 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost) if (size > HOST_BITS_PER_WIDE_INT) abort (); - op1 = GEN_INT (trunc_int_for_mode (cnst1, mode)); + op1 = gen_int_mode (cnst1, mode); wide_op1 = immed_double_const (cnst1, @@ -2932,7 +2922,7 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost) the result is exact for inputs up to 0x1fffffff. The input range can be reduced by using cross-sum rules. For odd divisors >= 3, the following table gives right shift counts - so that if an number is shifted by an integer multiple of the given + so that if a number is shifted by an integer multiple of the given amount, the remainder stays the same: 2, 4, 3, 6, 10, 12, 4, 8, 18, 6, 11, 20, 18, 0, 5, 10, 12, 0, 12, 20, 14, 12, 23, 21, 8, 0, 20, 18, 0, 0, 6, 12, 0, 22, 0, 18, 20, 30, 0, 0, @@ -3012,9 +3002,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) if (! unsignedp && op1 == constm1_rtx) { if (rem_flag) - return const0_rtx; + return const0_rtx; return expand_unop (mode, flag_trapv && GET_MODE_CLASS(mode) == MODE_INT - ? negv_optab : neg_optab, op0, target, 0); + ? negv_optab : neg_optab, op0, target, 0); } if (target @@ -3277,7 +3267,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) if (rem_flag && d < 0) { d = abs_d; - op1 = GEN_INT (trunc_int_for_mode (abs_d, compute_mode)); + op1 = gen_int_mode (abs_d, compute_mode); } if (d == 1) @@ -3316,8 +3306,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) t1 = copy_to_mode_reg (compute_mode, op0); do_cmp_and_jump (t1, const0_rtx, GE, compute_mode, label); - expand_inc (t1, GEN_INT (trunc_int_for_mode - (abs_d - 1, compute_mode))); + expand_inc (t1, gen_int_mode (abs_d - 1, + compute_mode)); emit_label (label); quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1, build_int_2 (lgup, 0), @@ -3857,8 +3847,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0, build_int_2 (pre_shift, 0), NULL_RTX, unsignedp); quotient = expand_mult (compute_mode, t1, - GEN_INT (trunc_int_for_mode - (ml, compute_mode)), + gen_int_mode (ml, compute_mode), NULL_RTX, 0); insn = get_last_insn (); @@ -4112,21 +4101,22 @@ make_tree (type, x) make_tree (type, XEXP (x, 1)))); case LSHIFTRT: + t = (*lang_hooks.types.unsigned_type) (type); return fold (convert (type, - build (RSHIFT_EXPR, unsigned_type (type), - make_tree (unsigned_type (type), - XEXP (x, 0)), + build (RSHIFT_EXPR, t, + make_tree (t, XEXP (x, 0)), make_tree (type, XEXP (x, 1))))); case ASHIFTRT: + t = (*lang_hooks.types.signed_type) (type); return fold (convert (type, - build (RSHIFT_EXPR, signed_type (type), - make_tree (signed_type (type), XEXP (x, 0)), + build (RSHIFT_EXPR, t, + make_tree (t, XEXP (x, 0)), make_tree (type, XEXP (x, 1))))); case DIV: if (TREE_CODE (type) != REAL_TYPE) - t = signed_type (type); + t = (*lang_hooks.types.signed_type) (type); else t = type; @@ -4135,7 +4125,7 @@ make_tree (type, x) make_tree (t, XEXP (x, 0)), make_tree (t, XEXP (x, 1))))); case UDIV: - t = unsigned_type (type); + t = (*lang_hooks.types.unsigned_type) (type); return fold (convert (type, build (TRUNC_DIV_EXPR, t, make_tree (t, XEXP (x, 0)), @@ -4143,7 +4133,8 @@ make_tree (type, x) case SIGN_EXTEND: case ZERO_EXTEND: - t = type_for_mode (GET_MODE (XEXP (x, 0)), GET_CODE (x) == ZERO_EXTEND); + t = (*lang_hooks.types.type_for_mode) (GET_MODE (XEXP (x, 0)), + GET_CODE (x) == ZERO_EXTEND); return fold (convert (type, make_tree (t, XEXP (x, 0)))); default: @@ -4165,12 +4156,50 @@ make_tree (type, x) } } +/* Check whether the multiplication X * MULT + ADD overflows. + X, MULT and ADD must be CONST_*. + MODE is the machine mode for the computation. + X and MULT must have mode MODE. ADD may have a different mode. + So can X (defaults to same as MODE). + UNSIGNEDP is nonzero to do unsigned multiplication. */ + +bool +const_mult_add_overflow_p (x, mult, add, mode, unsignedp) + rtx x, mult, add; + enum machine_mode mode; + int unsignedp; +{ + tree type, mult_type, add_type, result; + + type = (*lang_hooks.types.type_for_mode) (mode, unsignedp); + + /* In order to get a proper overflow indication from an unsigned + type, we have to pretend that it's a sizetype. */ + mult_type = type; + if (unsignedp) + { + mult_type = copy_node (type); + TYPE_IS_SIZETYPE (mult_type) = 1; + } + + add_type = (GET_MODE (add) == VOIDmode ? mult_type + : (*lang_hooks.types.type_for_mode) (GET_MODE (add), unsignedp)); + + result = fold (build (PLUS_EXPR, mult_type, + fold (build (MULT_EXPR, mult_type, + make_tree (mult_type, x), + make_tree (mult_type, mult))), + make_tree (add_type, add))); + + return TREE_CONSTANT_OVERFLOW (result); +} + /* Return an rtx representing the value of X * MULT + ADD. TARGET is a suggestion for where to store the result (an rtx). MODE is the machine mode for the computation. X and MULT must have mode MODE. ADD may have a different mode. So can X (defaults to same as MODE). - UNSIGNEDP is non-zero to do unsigned multiplication. + UNSIGNEDP is nonzero to do unsigned multiplication. This may emit insns. */ rtx @@ -4179,9 +4208,10 @@ expand_mult_add (x, target, mult, add, mode, unsignedp) enum machine_mode mode; int unsignedp; { - tree type = type_for_mode (mode, unsignedp); + tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp); tree add_type = (GET_MODE (add) == VOIDmode - ? type : type_for_mode (GET_MODE (add), unsignedp)); + ? type: (*lang_hooks.types.type_for_mode) (GET_MODE (add), + unsignedp)); tree result = fold (build (PLUS_EXPR, type, fold (build (MULT_EXPR, type, make_tree (type, x), @@ -4311,19 +4341,27 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) { if (code == EQ || code == NE) { + rtx op00, op01, op0both; + /* Do a logical OR of the two words and compare the result. */ - rtx op0h = gen_highpart (word_mode, op0); - rtx op0l = gen_lowpart (word_mode, op0); - rtx op0both = expand_binop (word_mode, ior_optab, op0h, op0l, - NULL_RTX, unsignedp, OPTAB_DIRECT); + 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, ior_optab, op00, op01, + NULL_RTX, unsignedp, OPTAB_DIRECT); if (op0both != 0) return emit_store_flag (target, code, op0both, op1, word_mode, unsignedp, normalizep); } else if (code == LT || code == GE) - /* If testing the sign bit, can just test on high word. */ - return emit_store_flag (target, code, gen_highpart (word_mode, op0), - op1, word_mode, unsignedp, normalizep); + { + rtx op0h; + + /* 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)); + return emit_store_flag (target, code, op0h, op1, word_mode, + unsignedp, normalizep); + } } /* From now on, we won't change CODE, so set ICODE now. */ @@ -4583,7 +4621,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) if (code == EQ || code == NE) { /* For EQ or NE, one way to do the comparison is to apply an operation - that converts the operand into a positive number if it is non-zero + that converts the operand into a positive number if it is nonzero or zero if it was originally zero. Then, for EQ, we subtract 1 and for NE we negate. This puts the result in the sign bit. Then we normalize with a shift, if needed. -- cgit v1.1