diff options
author | obrien <obrien@FreeBSD.org> | 1999-08-26 09:30:50 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1999-08-26 09:30:50 +0000 |
commit | 0bedf4fb30066e5e1d4342a1d3914dae7d37cba7 (patch) | |
tree | 68d8110b41afd0ebbf39167b1a4918eea667a7c5 /contrib/gcc/expmed.c | |
parent | d4db5fb866b7ad5216abd5047774a3973b9901a9 (diff) | |
download | FreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.zip FreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.tar.gz |
Virgin import of gcc from EGCS 1.1.2
Diffstat (limited to 'contrib/gcc/expmed.c')
-rw-r--r-- | contrib/gcc/expmed.c | 780 |
1 files changed, 490 insertions, 290 deletions
diff --git a/contrib/gcc/expmed.c b/contrib/gcc/expmed.c index 8006e8b..2f656c2 100644 --- a/contrib/gcc/expmed.c +++ b/contrib/gcc/expmed.c @@ -1,6 +1,6 @@ /* Medium-level subroutines: convert bit-field store and extract and shifts, multiplies and divides to rtl instructions. - Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc. This file is part of GNU CC. @@ -21,6 +21,7 @@ Boston, MA 02111-1307, USA. */ #include "config.h" +#include "system.h" #include "rtl.h" #include "tree.h" #include "flags.h" @@ -40,6 +41,8 @@ static rtx mask_rtx PROTO((enum machine_mode, int, static rtx lshift_value PROTO((enum machine_mode, rtx, int, int)); static rtx extract_split_bit_field PROTO((rtx, int, int, int, int)); +static void do_cmp_and_jump PROTO((rtx, rtx, enum rtx_code, + enum machine_mode, rtx)); #define CEIL(x,y) (((x) + (y) - 1) / (y)) @@ -79,7 +82,7 @@ init_expmed () char *free_point; /* 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 reg = gen_rtx_REG (word_mode, 10000); rtx shift_insn, shiftadd_insn, shiftsub_insn; int dummy; int m; @@ -90,34 +93,37 @@ init_expmed () /* Since we are on the permanent obstack, we must be sure we save this spot AFTER we call start_sequence, since it will reuse the rtl it makes. */ - free_point = (char *) oballoc (0); - zero_cost = rtx_cost (const0_rtx, 0); - add_cost = rtx_cost (gen_rtx (PLUS, word_mode, reg, reg), SET); - - shift_insn = emit_insn (gen_rtx (SET, VOIDmode, reg, - gen_rtx (ASHIFT, word_mode, reg, - const0_rtx))); + reg = gen_rtx (REG, word_mode, 10000); - shiftadd_insn = emit_insn (gen_rtx (SET, VOIDmode, reg, - gen_rtx (PLUS, word_mode, - gen_rtx (MULT, word_mode, - reg, const0_rtx), - reg))); - - shiftsub_insn = emit_insn (gen_rtx (SET, VOIDmode, reg, - gen_rtx (MINUS, word_mode, - gen_rtx (MULT, word_mode, - reg, const0_rtx), - reg))); + zero_cost = rtx_cost (const0_rtx, 0); + add_cost = rtx_cost (gen_rtx_PLUS (word_mode, reg, reg), SET); + + shift_insn = emit_insn (gen_rtx_SET (VOIDmode, reg, + gen_rtx_ASHIFT (word_mode, reg, + const0_rtx))); + + shiftadd_insn + = emit_insn (gen_rtx_SET (VOIDmode, reg, + gen_rtx_PLUS (word_mode, + gen_rtx_MULT (word_mode, + reg, const0_rtx), + reg))); + + shiftsub_insn + = emit_insn (gen_rtx_SET (VOIDmode, reg, + gen_rtx_MINUS (word_mode, + gen_rtx_MULT (word_mode, + reg, const0_rtx), + reg))); init_recog (); shift_cost[0] = 0; shiftadd_cost[0] = shiftsub_cost[0] = add_cost; - for (m = 1; m < BITS_PER_WORD; m++) + for (m = 1; m < MAX_BITS_PER_WORD; m++) { shift_cost[m] = shiftadd_cost[m] = shiftsub_cost[m] = 32000; @@ -136,37 +142,39 @@ init_expmed () shiftsub_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftsub_insn)), SET); } - negate_cost = rtx_cost (gen_rtx (NEG, word_mode, reg), SET); + negate_cost = rtx_cost (gen_rtx_NEG (word_mode, reg), SET); sdiv_pow2_cheap - = (rtx_cost (gen_rtx (DIV, word_mode, reg, GEN_INT (32)), SET) + = (rtx_cost (gen_rtx_DIV (word_mode, reg, GEN_INT (32)), SET) <= 2 * add_cost); smod_pow2_cheap - = (rtx_cost (gen_rtx (MOD, word_mode, reg, GEN_INT (32)), SET) + = (rtx_cost (gen_rtx_MOD (word_mode, reg, GEN_INT (32)), SET) <= 2 * add_cost); for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) { - reg = gen_rtx (REG, mode, 10000); - div_cost[(int) mode] = rtx_cost (gen_rtx (UDIV, mode, reg, reg), SET); - mul_cost[(int) mode] = rtx_cost (gen_rtx (MULT, mode, reg, reg), SET); + reg = gen_rtx_REG (mode, 10000); + div_cost[(int) mode] = rtx_cost (gen_rtx_UDIV (mode, reg, reg), SET); + mul_cost[(int) mode] = rtx_cost (gen_rtx_MULT (mode, reg, reg), SET); wider_mode = GET_MODE_WIDER_MODE (mode); if (wider_mode != VOIDmode) { mul_widen_cost[(int) wider_mode] - = rtx_cost (gen_rtx (MULT, wider_mode, - gen_rtx (ZERO_EXTEND, wider_mode, reg), - gen_rtx (ZERO_EXTEND, wider_mode, reg)), + = rtx_cost (gen_rtx_MULT (wider_mode, + gen_rtx_ZERO_EXTEND (wider_mode, reg), + gen_rtx_ZERO_EXTEND (wider_mode, reg)), SET); mul_highpart_cost[(int) mode] - = rtx_cost (gen_rtx (TRUNCATE, mode, - gen_rtx (LSHIFTRT, wider_mode, - gen_rtx (MULT, wider_mode, - gen_rtx (ZERO_EXTEND, wider_mode, reg), - gen_rtx (ZERO_EXTEND, wider_mode, reg)), - GEN_INT (GET_MODE_BITSIZE (mode)))), + = rtx_cost (gen_rtx_TRUNCATE + (mode, + gen_rtx_LSHIFTRT + (wider_mode, + gen_rtx_MULT (wider_mode, + gen_rtx_ZERO_EXTEND (wider_mode, reg), + gen_rtx_ZERO_EXTEND (wider_mode, reg)), + GEN_INT (GET_MODE_BITSIZE (mode)))), SET); } } @@ -185,21 +193,12 @@ negate_rtx (mode, x) enum machine_mode mode; rtx x; { - if (GET_CODE (x) == CONST_INT) - { - HOST_WIDE_INT val = - INTVAL (x); - if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT) - { - /* Sign extend the value from the bits that are significant. */ - if (val & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))) - val |= (HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (mode); - else - val &= ((HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (mode)) - 1; - } - return GEN_INT (val); - } - else - return expand_unop (GET_MODE (x), neg_optab, x, NULL_RTX, 0); + rtx result = simplify_unary_operation (NEG, mode, x, mode); + + if (result == 0) + result = expand_unop (mode, neg_optab, x, NULL_RTX, 0); + + return result; } /* Generate code to store value from rtx VALUE @@ -281,7 +280,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) if (GET_MODE (op0) != fieldmode) { if (GET_CODE (op0) == REG) - op0 = gen_rtx (SUBREG, fieldmode, op0, offset); + op0 = gen_rtx_SUBREG (fieldmode, op0, offset); else op0 = change_address (op0, fieldmode, plus_constant (XEXP (op0, 0), offset)); @@ -316,7 +315,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) if(! (*insn_operand_predicate[icode][1]) (value, fieldmode)) value = copy_to_mode_reg (fieldmode, value); emit_insn (GEN_FCN (icode) - (gen_rtx (SUBREG, fieldmode, op0, offset), value)); + (gen_rtx_SUBREG (fieldmode, op0, offset), value)); } return value; } @@ -373,7 +372,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) { if (offset != 0 || GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD) - op0 = gen_rtx (SUBREG, TYPE_MODE (type_for_size (BITS_PER_WORD, 0)), + op0 = gen_rtx_SUBREG (TYPE_MODE (type_for_size (BITS_PER_WORD, 0)), op0, offset); offset = 0; } @@ -390,7 +389,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) { if (GET_CODE (value) != REG) value = copy_to_reg (value); - value = gen_rtx (SUBREG, word_mode, value, 0); + value = gen_rtx_SUBREG (word_mode, value, 0); } /* Now OFFSET is nonzero only if OP0 is memory @@ -398,6 +397,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) #ifdef HAVE_insv if (HAVE_insv + && GET_MODE (value) != BLKmode && !(bitsize == 1 && GET_CODE (value) == CONST_INT) /* Ensure insv's size is wide enough for this field. */ && (GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_insv][3]) @@ -417,13 +417,13 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) int save_volatile_ok = volatile_ok; volatile_ok = 1; - /* If this machine's insv can only insert into a register, or if we - are to force MEMs into a register, copy OP0 into a register and - save it back later. */ + /* If this machine's insv can only insert into a register, copy OP0 + into a register and save it back later. */ + /* This used to check flag_force_mem, but that was a serious + de-optimization now that flag_force_mem is enabled by -O2. */ if (GET_CODE (op0) == MEM - && (flag_force_mem - || ! ((*insn_operand_predicate[(int) CODE_FOR_insv][0]) - (op0, VOIDmode)))) + && ! ((*insn_operand_predicate[(int) CODE_FOR_insv][0]) + (op0, VOIDmode))) { rtx tempreg; enum machine_mode bestmode; @@ -472,9 +472,9 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) if (GET_CODE (xop0) == SUBREG) /* We can't just change the mode, because this might clobber op0, and we will need the original value of op0 if insv fails. */ - xop0 = gen_rtx (SUBREG, maxmode, SUBREG_REG (xop0), SUBREG_WORD (xop0)); + xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_WORD (xop0)); if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode) - xop0 = gen_rtx (SUBREG, maxmode, xop0, 0); + xop0 = gen_rtx_SUBREG (maxmode, xop0, 0); /* On big-endian machines, we count bits from the most significant. If the bit field insn does not, we must invert. */ @@ -504,7 +504,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) /* Avoid making subreg of a subreg, or of a mem. */ if (GET_CODE (value1) != REG) value1 = copy_to_reg (value1); - value1 = gen_rtx (SUBREG, maxmode, value1, 0); + value1 = gen_rtx_SUBREG (maxmode, value1, 0); } else value1 = gen_lowpart (maxmode, value1); @@ -565,6 +565,9 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align) int all_zero = 0; int all_one = 0; + if (! SLOW_UNALIGNED_ACCESS) + struct_align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; + /* There is a case not handled here: a structure with a known alignment of just a halfword and a field split across two aligned halfwords within the structure. @@ -607,7 +610,7 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align) total_bits = GET_MODE_BITSIZE (mode); /* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to - be be in the range 0 to total_bits-1, and put any excess bytes in + be in the range 0 to total_bits-1, and put any excess bytes in OFFSET. */ if (bitpos >= total_bits) { @@ -752,6 +755,8 @@ store_split_bit_field (op0, bitsize, bitpos, value, align) ? GET_MODE (value) : word_mode, value)); } + else if (GET_CODE (value) == ADDRESSOF) + value = copy_to_reg (value); while (bitsdone < bitsize) { @@ -776,7 +781,7 @@ store_split_bit_field (op0, bitsize, bitpos, value, align) /* We must do an endian conversion exactly the same way as it is done in extract_bit_field, so that the two calls to extract_fixed_bit_field will have comparable arguments. */ - if (GET_CODE (value) != MEM) + if (GET_CODE (value) != MEM || GET_MODE (value) == BLKmode) total_bits = BITS_PER_WORD; else total_bits = GET_MODE_BITSIZE (GET_MODE (value)); @@ -789,10 +794,19 @@ store_split_bit_field (op0, bitsize, bitpos, value, align) else /* The args are chosen so that the last part includes the lsb. Give extract_bit_field the value it needs (with - endianness compensation) to fetch the piece we want. */ - part = extract_fixed_bit_field (word_mode, value, 0, thissize, - total_bits - bitsize + bitsdone, - NULL_RTX, 1, align); + endianness compensation) to fetch the piece we want. + + ??? We have no idea what the alignment of VALUE is, so + we have to use a guess. */ + part + = extract_fixed_bit_field + (word_mode, value, 0, thissize, + total_bits - bitsize + bitsdone, NULL_RTX, 1, + GET_MODE (value) == VOIDmode + ? UNITS_PER_WORD + : (GET_MODE (value) == BLKmode + ? 1 + : GET_MODE_ALIGNMENT (GET_MODE (value)) / BITS_PER_UNIT)); } else { @@ -802,8 +816,14 @@ store_split_bit_field (op0, bitsize, bitpos, value, align) >> bitsdone) & (((HOST_WIDE_INT) 1 << thissize) - 1)); else - part = extract_fixed_bit_field (word_mode, value, 0, thissize, - bitsdone, NULL_RTX, 1, align); + part + = extract_fixed_bit_field + (word_mode, value, 0, thissize, bitsdone, NULL_RTX, 1, + GET_MODE (value) == VOIDmode + ? UNITS_PER_WORD + : (GET_MODE (value) == BLKmode + ? 1 + : GET_MODE_ALIGNMENT (GET_MODE (value)) / BITS_PER_UNIT)); } /* If OP0 is a register, then handle OFFSET here. @@ -875,9 +895,6 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, rtx spec_target = target; rtx spec_target_subreg = 0; - if (GET_CODE (str_rtx) == MEM && ! MEM_IN_STRUCT_P (str_rtx)) - abort (); - /* Discount the part of the structure before the desired byte. We need to know how many bytes are safe to reference after it. */ if (total_size >= 0) @@ -893,6 +910,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, offset += SUBREG_WORD (op0); + inner_size = MIN (inner_size, BITS_PER_WORD); + if (BYTES_BIG_ENDIAN && (outer_size < inner_size)) { bitpos += inner_size - outer_size; @@ -913,8 +932,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, /* If OP0 is a register, BITPOS must count within a word. But as we have it, it counts within whatever size OP0 now has. On a bigendian machine, these are not the same, so convert. */ - if (BYTES_BIG_ENDIAN && - GET_CODE (op0) != MEM + if (BYTES_BIG_ENDIAN + && GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0))) bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0)); @@ -924,7 +943,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, So too extracting a subword value in the least significant part of the register. */ - if ((GET_CODE (op0) == REG + if (((GET_CODE (op0) == REG + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), + GET_MODE_BITSIZE (GET_MODE (op0)))) || (GET_CODE (op0) == MEM && (! SLOW_UNALIGNED_ACCESS || (offset * BITS_PER_UNIT % bitsize == 0 @@ -942,7 +963,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, if (mode1 != GET_MODE (op0)) { if (GET_CODE (op0) == REG) - op0 = gen_rtx (SUBREG, mode1, op0, offset); + op0 = gen_rtx_SUBREG (mode1, op0, offset); else op0 = change_address (op0, mode1, plus_constant (XEXP (op0, 0), offset)); @@ -967,6 +988,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, if (target == 0 || GET_CODE (target) != REG) target = gen_reg_rtx (mode); + /* Indicate for flow that the entire target reg is being set. */ + emit_insn (gen_rtx_CLOBBER (VOIDmode, target)); + for (i = 0; i < nwords; i++) { /* If I is 0, use the low-order word in both field and target; @@ -1034,7 +1058,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, { if (offset != 0 || GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD) - op0 = gen_rtx (SUBREG, TYPE_MODE (type_for_size (BITS_PER_WORD, 0)), + op0 = gen_rtx_SUBREG (TYPE_MODE (type_for_size (BITS_PER_WORD, 0)), op0, offset); offset = 0; } @@ -1057,7 +1081,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, { int xbitpos = bitpos, xoffset = offset; rtx bitsize_rtx, bitpos_rtx; - rtx last = get_last_insn(); + rtx last = get_last_insn (); rtx xop0 = op0; rtx xtarget = target; rtx xspec_target = spec_target; @@ -1072,9 +1096,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, volatile_ok = 1; /* Is the memory operand acceptable? */ - if (flag_force_mem - || ! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1]) - (xop0, GET_MODE (xop0)))) + if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1]) + (xop0, GET_MODE (xop0)))) { /* No, load into a reg and extract from there. */ enum machine_mode bestmode; @@ -1122,9 +1145,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, /* If op0 is a register, we need it in MAXMODE (which is usually SImode). to make it acceptable to the format of extzv. */ if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode) - abort (); + goto extzv_loses; if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode) - xop0 = gen_rtx (SUBREG, maxmode, xop0, 0); + xop0 = gen_rtx_SUBREG (maxmode, xop0, 0); /* On big-endian machines, we count bits from the most significant. If the bit field insn does not, we must invert. */ @@ -1198,7 +1221,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, { int xbitpos = bitpos, xoffset = offset; rtx bitsize_rtx, bitpos_rtx; - rtx last = get_last_insn(); + rtx last = get_last_insn (); rtx xop0 = op0, xtarget = target; rtx xspec_target = spec_target; rtx xspec_target_subreg = spec_target_subreg; @@ -1256,9 +1279,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, /* If op0 is a register, we need it in MAXMODE (which is usually SImode) to make it acceptable to the format of extv. */ if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode) - abort (); + goto extv_loses; if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode) - xop0 = gen_rtx (SUBREG, maxmode, xop0, 0); + xop0 = gen_rtx_SUBREG (maxmode, xop0, 0); /* On big-endian machines, we count bits from the most significant. If the bit field insn does not, we must invert. */ @@ -1337,7 +1360,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, target, unsignedp); if (GET_CODE (target) != REG) target = copy_to_reg (target); - return gen_rtx (SUBREG, tmode, target, 0); + return gen_rtx_SUBREG (tmode, target, 0); } else return convert_to_mode (tmode, target, unsignedp); @@ -1402,7 +1425,7 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, total_bits = GET_MODE_BITSIZE (mode); /* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to - be be in the range 0 to total_bits-1, and put any excess bytes in + be in the range 0 to total_bits-1, and put any excess bytes in OFFSET. */ if (bitpos >= total_bits) { @@ -1461,7 +1484,7 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, #ifdef SLOW_ZERO_EXTEND /* Always generate an `and' if we just zero-extended op0 and SLOW_ZERO_EXTEND, since it - will combine fruitfully with the zero-extend. */ + will combine fruitfully with the zero-extend. */ || tmode != mode #endif #endif @@ -1592,7 +1615,7 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align) { int unit; int bitsdone = 0; - rtx result; + rtx result = NULL_RTX; int first = 1; /* Make sure UNIT isn't larger than BITS_PER_WORD, we can only handle that @@ -1738,11 +1761,16 @@ expand_shift (code, mode, shifted, amount, target, unsignedp) op1 = expand_expr (amount, NULL_RTX, VOIDmode, 0); #ifdef SHIFT_COUNT_TRUNCATED - if (SHIFT_COUNT_TRUNCATED - && GET_CODE (op1) == CONST_INT - && (unsigned HOST_WIDE_INT) INTVAL (op1) >= GET_MODE_BITSIZE (mode)) - op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1) - % GET_MODE_BITSIZE (mode)); + if (SHIFT_COUNT_TRUNCATED) + { + if (GET_CODE (op1) == CONST_INT + && (unsigned HOST_WIDE_INT) INTVAL (op1) >= GET_MODE_BITSIZE (mode)) + op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1) + % GET_MODE_BITSIZE (mode)); + else if (GET_CODE (op1) == SUBREG + && SUBREG_WORD (op1) == 0) + op1 = SUBREG_REG (op1); + } #endif if (op1 == const0_rtx) @@ -1889,6 +1917,15 @@ struct algorithm char log[MAX_BITS_PER_WORD]; }; +static void synth_mult PROTO((struct algorithm *, + unsigned HOST_WIDE_INT, + int)); +static unsigned HOST_WIDE_INT choose_multiplier PROTO((unsigned HOST_WIDE_INT, + int, int, + unsigned HOST_WIDE_INT *, + int *, int *)); +static unsigned HOST_WIDE_INT invert_mod2n PROTO((unsigned HOST_WIDE_INT, + int)); /* Compute and return the best algorithm for multiplying by T. The algorithm must cost less than cost_limit If retval.cost >= COST_LIMIT, no algorithm was found and all @@ -1969,10 +2006,16 @@ synth_mult (alg_out, t, cost_limit) for (w = 1; (w & t) != 0; w <<= 1) ; - if (w > 2 - /* Reject the case where t is 3. - Thus we prefer addition in that case. */ - && t != 3) + /* If T was -1, then W will be zero after the loop. This is another + case where T ends with ...111. Handling this with (T + 1) and + subtract 1 produces slightly better code and results in algorithm + selection much faster than treating it like the ...0111 case + below. */ + if (w == 0 + || (w > 2 + /* Reject the case where t is 3. + Thus we prefer addition in that case. */ + && t != 3)) { /* T ends with ...111. Multiply by (T + 1) and subtract 1. */ @@ -2178,7 +2221,7 @@ expand_mult (mode, op0, op1, target, unsignedp) and then negate, do the multiplication directly, or do multiplication by OP1 - 1. */ - mult_cost = rtx_cost (gen_rtx (MULT, mode, op0, op1), SET); + mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET); mult_cost = MIN (12 * add_cost, mult_cost); synth_mult (&alg, val, mult_cost); @@ -2235,7 +2278,8 @@ expand_mult (mode, op0, op1, target, unsignedp) rtx shift_subtarget = preserve ? 0 : accum; rtx add_target = (opno == alg.ops - 1 && target != 0 && variant != add_variant - ? target : 0); + && ! preserve) + ? target : 0; rtx accum_target = preserve ? 0 : accum; switch (alg.op[opno]) @@ -2249,7 +2293,7 @@ expand_mult (mode, op0, op1, target, unsignedp) case alg_add_t_m2: tem = expand_shift (LSHIFT_EXPR, mode, op0, build_int_2 (log, 0), NULL_RTX, 0); - accum = force_operand (gen_rtx (PLUS, mode, accum, tem), + accum = force_operand (gen_rtx_PLUS (mode, accum, tem), add_target ? add_target : accum_target); val_so_far += (HOST_WIDE_INT) 1 << log; break; @@ -2257,7 +2301,7 @@ expand_mult (mode, op0, op1, target, unsignedp) case alg_sub_t_m2: tem = expand_shift (LSHIFT_EXPR, mode, op0, build_int_2 (log, 0), NULL_RTX, 0); - accum = force_operand (gen_rtx (MINUS, mode, accum, tem), + accum = force_operand (gen_rtx_MINUS (mode, accum, tem), add_target ? add_target : accum_target); val_so_far -= (HOST_WIDE_INT) 1 << log; break; @@ -2266,7 +2310,7 @@ expand_mult (mode, op0, op1, target, unsignedp) accum = expand_shift (LSHIFT_EXPR, mode, accum, build_int_2 (log, 0), shift_subtarget, 0); - accum = force_operand (gen_rtx (PLUS, mode, accum, op0), + accum = force_operand (gen_rtx_PLUS (mode, accum, op0), add_target ? add_target : accum_target); val_so_far = (val_so_far << log) + 1; break; @@ -2275,7 +2319,7 @@ expand_mult (mode, op0, op1, target, unsignedp) accum = expand_shift (LSHIFT_EXPR, mode, accum, build_int_2 (log, 0), shift_subtarget, 0); - accum = force_operand (gen_rtx (MINUS, mode, accum, op0), + accum = force_operand (gen_rtx_MINUS (mode, accum, op0), add_target ? add_target : accum_target); val_so_far = (val_so_far << log) - 1; break; @@ -2283,7 +2327,7 @@ expand_mult (mode, op0, op1, target, unsignedp) case alg_add_factor: tem = expand_shift (LSHIFT_EXPR, mode, accum, build_int_2 (log, 0), NULL_RTX, 0); - accum = force_operand (gen_rtx (PLUS, mode, accum, tem), + accum = force_operand (gen_rtx_PLUS (mode, accum, tem), add_target ? add_target : accum_target); val_so_far += val_so_far << log; break; @@ -2291,7 +2335,7 @@ expand_mult (mode, op0, op1, target, unsignedp) case alg_sub_factor: tem = expand_shift (LSHIFT_EXPR, mode, accum, build_int_2 (log, 0), NULL_RTX, 0); - accum = force_operand (gen_rtx (MINUS, mode, tem, accum), + accum = force_operand (gen_rtx_MINUS (mode, tem, accum), (add_target ? add_target : preserve ? 0 : tem)); val_so_far = (val_so_far << log) - val_so_far; @@ -2306,9 +2350,9 @@ expand_mult (mode, op0, op1, target, unsignedp) insn = get_last_insn (); REG_NOTES (insn) - = gen_rtx (EXPR_LIST, REG_EQUAL, - gen_rtx (MULT, mode, op0, GEN_INT (val_so_far)), - REG_NOTES (insn)); + = gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_MULT (mode, op0, GEN_INT (val_so_far)), + REG_NOTES (insn)); } if (variant == negate_variant) @@ -2319,7 +2363,7 @@ expand_mult (mode, op0, op1, target, unsignedp) else if (variant == add_variant) { val_so_far = val_so_far + 1; - accum = force_operand (gen_rtx (PLUS, mode, accum, op0), target); + accum = force_operand (gen_rtx_PLUS (mode, accum, op0), target); } if (val != val_so_far) @@ -2465,7 +2509,7 @@ invert_mod2n (x, n) unsigned HOST_WIDE_INT x; int n; { - /* Solve x*y == 1 (mod 2^n), where x is odd. Return y. */ + /* Solve x*y == 1 (mod 2^n), where x is odd. Return y. */ /* The algorithm notes that the choice y = x satisfies x*y == 1 mod 2^3, since x is assumed odd. @@ -2510,14 +2554,16 @@ expand_mult_highpart_adjust (mode, adj_operand, op0, op1, target, unsignedp) build_int_2 (GET_MODE_BITSIZE (mode) - 1, 0), NULL_RTX, 0); tem = expand_and (tem, op1, NULL_RTX); - adj_operand = force_operand (gen_rtx (adj_code, mode, adj_operand, tem), - adj_operand); + adj_operand + = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem), + adj_operand); tem = expand_shift (RSHIFT_EXPR, mode, op1, build_int_2 (GET_MODE_BITSIZE (mode) - 1, 0), NULL_RTX, 0); tem = expand_and (tem, op0, NULL_RTX); - target = force_operand (gen_rtx (adj_code, mode, adj_operand, tem), target); + target = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem), + target); return target; } @@ -2609,13 +2655,19 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost) moptab = unsignedp ? umul_widen_optab : smul_widen_optab; if (moptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing && mul_widen_cost[(int) wider_mode] < max_cost) - goto try; + { + op1 = force_reg (mode, op1); + goto try; + } /* Try widening the mode and perform a non-widening multiplication. */ moptab = smul_optab; if (smul_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing && mul_cost[(int) wider_mode] + shift_cost[size-1] < max_cost) - goto try; + { + op1 = wide_op1; + goto try; + } /* Try widening multiplication of opposite signedness, and adjust. */ moptab = unsignedp ? smul_widen_optab : umul_widen_optab; @@ -2623,7 +2675,8 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost) && (mul_widen_cost[(int) wider_mode] + 2 * shift_cost[size-1] + 4 * add_cost < max_cost)) { - tem = expand_binop (wider_mode, moptab, op0, wide_op1, + rtx regop1 = force_reg (mode, op1); + tem = expand_binop (wider_mode, moptab, op0, regop1, NULL_RTX, ! unsignedp, OPTAB_WIDEN); if (tem != 0) { @@ -2641,15 +2694,22 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost) try: /* Pass NULL_RTX as target since TARGET has wrong mode. */ - tem = expand_binop (wider_mode, moptab, op0, wide_op1, + tem = expand_binop (wider_mode, moptab, op0, op1, NULL_RTX, unsignedp, OPTAB_WIDEN); if (tem == 0) return 0; /* Extract the high half of the just generated product. */ - tem = expand_shift (RSHIFT_EXPR, wider_mode, tem, - build_int_2 (size, 0), NULL_RTX, 1); - return convert_modes (mode, wider_mode, tem, unsignedp); + if (mode == word_mode) + { + return gen_highpart (mode, tem); + } + else + { + tem = expand_shift (RSHIFT_EXPR, wider_mode, tem, + build_int_2 (size, 0), NULL_RTX, 1); + return convert_modes (mode, wider_mode, tem, unsignedp); + } } /* Emit the code to divide OP0 by OP1, putting the result in TARGET @@ -2688,11 +2748,12 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) optab optab1, optab2; int op1_is_constant, op1_is_pow2; int max_cost, extra_cost; + static HOST_WIDE_INT last_div_const = 0; op1_is_constant = GET_CODE (op1) == CONST_INT; op1_is_pow2 = (op1_is_constant && ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1)) - || EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1))))); + || (! unsignedp && EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1)))))); /* This is the structure of expand_divmod: @@ -2797,14 +2858,29 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) size = GET_MODE_BITSIZE (mode); #endif + /* Only deduct something for a REM if the last divide done was + for a different constant. Then set the constant of the last + divide. */ max_cost = div_cost[(int) compute_mode] - - (rem_flag ? mul_cost[(int) compute_mode] + add_cost : 0); + - (rem_flag && ! (last_div_const != 0 && op1_is_constant + && INTVAL (op1) == last_div_const) + ? mul_cost[(int) compute_mode] + add_cost : 0); + + last_div_const = ! rem_flag && op1_is_constant ? INTVAL (op1) : 0; /* Now convert to the best mode to use. */ if (compute_mode != mode) { op0 = convert_modes (compute_mode, mode, op0, unsignedp); op1 = convert_modes (compute_mode, mode, op1, unsignedp); + + /* convert_modes may have placed op1 into a register, so we + must recompute the following. */ + op1_is_constant = GET_CODE (op1) == CONST_INT; + op1_is_pow2 = (op1_is_constant + && ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1)) + || (! unsignedp + && EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1)))))) ; } /* If one of the operands is a volatile MEM, copy it into a register. */ @@ -2828,6 +2904,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) code = TRUNC_DIV_EXPR; if (code == FLOOR_MOD_EXPR) code = TRUNC_MOD_EXPR; + if (code == EXACT_DIV_EXPR && op1_is_pow2) + code = TRUNC_DIV_EXPR; } if (op1 != const0_rtx) @@ -2835,7 +2913,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) { case TRUNC_MOD_EXPR: case TRUNC_DIV_EXPR: - if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size) + if (op1_is_constant) { if (unsignedp) { @@ -2849,10 +2927,11 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) pre_shift = floor_log2 (d); if (rem_flag) { - remainder = expand_binop (compute_mode, and_optab, op0, - GEN_INT (((HOST_WIDE_INT) 1 << pre_shift) - 1), - remainder, 1, - OPTAB_LIB_WIDEN); + remainder + = expand_binop (compute_mode, and_optab, op0, + GEN_INT (((HOST_WIDE_INT) 1 << pre_shift) - 1), + remainder, 1, + OPTAB_LIB_WIDEN); if (remainder) return gen_lowpart (mode, remainder); } @@ -2860,91 +2939,96 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) build_int_2 (pre_shift, 0), tquotient, 1); } - else if (d >= ((unsigned HOST_WIDE_INT) 1 << (size - 1))) + else if (size <= HOST_BITS_PER_WIDE_INT) { - /* Most significant bit of divisor is set, emit a scc insn. - emit_store_flag needs to be passed a place for the - result. */ - quotient = emit_store_flag (tquotient, GEU, op0, op1, - compute_mode, 1, 1); - if (quotient == 0) - goto fail1; - } - else - { - /* Find a suitable multiplier and right shift count instead - of multiplying with D. */ - - mh = choose_multiplier (d, size, size, - &ml, &post_shift, &dummy); - - /* If the suggested multiplier is more than SIZE bits, we - can do better for even divisors, using an initial right - shift. */ - if (mh != 0 && (d & 1) == 0) + if (d >= ((unsigned HOST_WIDE_INT) 1 << (size - 1))) { - pre_shift = floor_log2 (d & -d); - mh = choose_multiplier (d >> pre_shift, size, - size - pre_shift, - &ml, &post_shift, &dummy); - if (mh) - abort (); - } - else - pre_shift = 0; - - if (mh != 0) - { - rtx t1, t2, t3, t4; - - extra_cost = (shift_cost[post_shift - 1] - + shift_cost[1] + 2 * add_cost); - t1 = expand_mult_highpart (compute_mode, op0, ml, - NULL_RTX, 1, - max_cost - extra_cost); - if (t1 == 0) + /* Most significant bit of divisor is set; emit an scc + insn. */ + quotient = emit_store_flag (tquotient, GEU, op0, op1, + compute_mode, 1, 1); + if (quotient == 0) goto fail1; - t2 = force_operand (gen_rtx (MINUS, compute_mode, - op0, t1), - NULL_RTX); - t3 = expand_shift (RSHIFT_EXPR, compute_mode, t2, - build_int_2 (1, 0), NULL_RTX, 1); - t4 = force_operand (gen_rtx (PLUS, compute_mode, - t1, t3), - NULL_RTX); - quotient = expand_shift (RSHIFT_EXPR, compute_mode, t4, - build_int_2 (post_shift - 1, - 0), - tquotient, 1); } else { - rtx t1, t2; + /* Find a suitable multiplier and right shift count + instead of multiplying with D. */ - t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0, - build_int_2 (pre_shift, 0), - NULL_RTX, 1); - extra_cost = (shift_cost[pre_shift] - + shift_cost[post_shift]); - t2 = expand_mult_highpart (compute_mode, t1, ml, - NULL_RTX, 1, - max_cost - extra_cost); - if (t2 == 0) - goto fail1; - quotient = expand_shift (RSHIFT_EXPR, compute_mode, t2, - build_int_2 (post_shift, 0), - tquotient, 1); + mh = choose_multiplier (d, size, size, + &ml, &post_shift, &dummy); + + /* If the suggested multiplier is more than SIZE bits, + we can do better for even divisors, using an + initial right shift. */ + if (mh != 0 && (d & 1) == 0) + { + pre_shift = floor_log2 (d & -d); + mh = choose_multiplier (d >> pre_shift, size, + size - pre_shift, + &ml, &post_shift, &dummy); + if (mh) + abort (); + } + else + pre_shift = 0; + + if (mh != 0) + { + rtx t1, t2, t3, t4; + + extra_cost = (shift_cost[post_shift - 1] + + shift_cost[1] + 2 * add_cost); + t1 = expand_mult_highpart (compute_mode, op0, ml, + NULL_RTX, 1, + max_cost - extra_cost); + if (t1 == 0) + goto fail1; + t2 = force_operand (gen_rtx_MINUS (compute_mode, + op0, t1), + NULL_RTX); + t3 = expand_shift (RSHIFT_EXPR, compute_mode, t2, + build_int_2 (1, 0), NULL_RTX,1); + t4 = force_operand (gen_rtx_PLUS (compute_mode, + t1, t3), + NULL_RTX); + quotient + = expand_shift (RSHIFT_EXPR, compute_mode, t4, + build_int_2 (post_shift - 1, 0), + tquotient, 1); + } + else + { + rtx t1, t2; + + t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0, + build_int_2 (pre_shift, 0), + NULL_RTX, 1); + extra_cost = (shift_cost[pre_shift] + + shift_cost[post_shift]); + t2 = expand_mult_highpart (compute_mode, t1, ml, + NULL_RTX, 1, + max_cost - extra_cost); + if (t2 == 0) + goto fail1; + quotient + = expand_shift (RSHIFT_EXPR, compute_mode, t2, + build_int_2 (post_shift, 0), + tquotient, 1); + } } } + else /* Too wide mode to use tricky code */ + break; insn = get_last_insn (); if (insn != last && (set = single_set (insn)) != 0 && SET_DEST (set) == quotient) REG_NOTES (insn) - = gen_rtx (EXPR_LIST, REG_EQUAL, - gen_rtx (UDIV, compute_mode, op0, op1), - REG_NOTES (insn)); + = gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_UDIV (compute_mode, op0, op1), + REG_NOTES (insn)); } else /* TRUNC_DIV, signed */ { @@ -2985,9 +3069,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) rtx t1; t1 = copy_to_mode_reg (compute_mode, op0); - emit_cmp_insn (t1, const0_rtx, GE, - NULL_RTX, compute_mode, 0, 0); - emit_jump_insn (gen_bge (label)); + do_cmp_and_jump (t1, const0_rtx, GE, + compute_mode, label); expand_inc (t1, GEN_INT (abs_d - 1)); emit_label (label); quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1, @@ -3003,8 +3086,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) t2 = expand_shift (RSHIFT_EXPR, compute_mode, t1, build_int_2 (size - lgup, 0), NULL_RTX, 1); - t3 = force_operand (gen_rtx (PLUS, compute_mode, - op0, t2), + t3 = force_operand (gen_rtx_PLUS (compute_mode, + op0, t2), NULL_RTX); quotient = expand_shift (RSHIFT_EXPR, compute_mode, t3, build_int_2 (lgup, 0), @@ -3020,16 +3103,17 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) && (set = single_set (insn)) != 0 && SET_DEST (set) == quotient) REG_NOTES (insn) - = gen_rtx (EXPR_LIST, REG_EQUAL, - gen_rtx (DIV, compute_mode, op0, - GEN_INT (abs_d)), + = gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_DIV (compute_mode, + op0, + GEN_INT (abs_d)), REG_NOTES (insn)); quotient = expand_unop (compute_mode, neg_optab, quotient, quotient, 0); } } - else + else if (size <= HOST_BITS_PER_WIDE_INT) { choose_multiplier (abs_d, size, size - 1, &ml, &post_shift, &lgup); @@ -3049,10 +3133,10 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) t3 = expand_shift (RSHIFT_EXPR, compute_mode, op0, build_int_2 (size - 1, 0), NULL_RTX, 0); if (d < 0) - quotient = force_operand (gen_rtx (MINUS, compute_mode, t3, t2), + quotient = force_operand (gen_rtx_MINUS (compute_mode, t3, t2), tquotient); else - quotient = force_operand (gen_rtx (MINUS, compute_mode, t2, t3), + quotient = force_operand (gen_rtx_MINUS (compute_mode, t2, t3), tquotient); } else @@ -3067,29 +3151,31 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) max_cost - extra_cost); if (t1 == 0) goto fail1; - t2 = force_operand (gen_rtx (PLUS, compute_mode, t1, op0), + t2 = force_operand (gen_rtx_PLUS (compute_mode, t1, op0), NULL_RTX); t3 = expand_shift (RSHIFT_EXPR, compute_mode, t2, build_int_2 (post_shift, 0), NULL_RTX, 0); t4 = expand_shift (RSHIFT_EXPR, compute_mode, op0, build_int_2 (size - 1, 0), NULL_RTX, 0); if (d < 0) - quotient = force_operand (gen_rtx (MINUS, compute_mode, t4, t3), + quotient = force_operand (gen_rtx_MINUS (compute_mode, t4, t3), tquotient); else - quotient = force_operand (gen_rtx (MINUS, compute_mode, t3, t4), + quotient = force_operand (gen_rtx_MINUS (compute_mode, t3, t4), tquotient); } } + else /* Too wide mode to use tricky code */ + break; insn = get_last_insn (); if (insn != last && (set = single_set (insn)) != 0 && SET_DEST (set) == quotient) REG_NOTES (insn) - = gen_rtx (EXPR_LIST, REG_EQUAL, - gen_rtx (DIV, compute_mode, op0, op1), - REG_NOTES (insn)); + = gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_DIV (compute_mode, op0, op1), + REG_NOTES (insn)); } break; } @@ -3157,13 +3243,13 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) else { rtx nsign, t1, t2, t3, t4; - t1 = force_operand (gen_rtx (PLUS, compute_mode, - op0, constm1_rtx), NULL_RTX); + t1 = force_operand (gen_rtx_PLUS (compute_mode, + op0, constm1_rtx), NULL_RTX); t2 = expand_binop (compute_mode, ior_optab, op0, t1, NULL_RTX, 0, OPTAB_WIDEN); nsign = expand_shift (RSHIFT_EXPR, compute_mode, t2, build_int_2 (size - 1, 0), NULL_RTX, 0); - t3 = force_operand (gen_rtx (MINUS, compute_mode, t1, nsign), + t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign), NULL_RTX); t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1, NULL_RTX, 0); @@ -3172,8 +3258,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) rtx t5; t5 = expand_unop (compute_mode, one_cmpl_optab, nsign, NULL_RTX, 0); - quotient = force_operand (gen_rtx (PLUS, compute_mode, - t4, t5), + quotient = force_operand (gen_rtx_PLUS (compute_mode, + t4, t5), tquotient); } } @@ -3188,7 +3274,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) or remainder to get floor rounding, once we have the remainder. Notice that we compute also the final remainder value here, and return the result right away. */ - if (target == 0) + if (target == 0 || GET_MODE (target) != compute_mode) target = gen_reg_rtx (compute_mode); if (rem_flag) @@ -3211,13 +3297,10 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) Save that for later. */ rtx tem; rtx label = gen_label_rtx (); - emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_beq (label)); + do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, label); tem = expand_binop (compute_mode, xor_optab, op0, op1, NULL_RTX, 0, OPTAB_WIDEN); - emit_cmp_insn (tem, const0_rtx, GE, NULL_RTX, compute_mode, 0, 0); - emit_jump_insn (gen_bge (label)); + do_cmp_and_jump (tem, const0_rtx, GE, compute_mode, label); expand_dec (quotient, const1_rtx); expand_inc (remainder, op1); emit_label (label); @@ -3238,11 +3321,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) label3 = gen_label_rtx (); label4 = gen_label_rtx (); label5 = gen_label_rtx (); - emit_cmp_insn (op1, const0_rtx, LT, NULL_RTX, compute_mode, 0, 0); - emit_jump_insn (gen_blt (label2)); - emit_cmp_insn (adjusted_op0, const0_rtx, LT, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_blt (label1)); + do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2); + do_cmp_and_jump (adjusted_op0, const0_rtx, LT, compute_mode, label1); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) @@ -3254,9 +3334,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) emit_jump_insn (gen_jump (label4)); emit_barrier (); emit_label (label2); - emit_cmp_insn (adjusted_op0, const0_rtx, GT, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_bgt (label3)); + do_cmp_and_jump (adjusted_op0, const0_rtx, GT, compute_mode, label3); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) @@ -3296,16 +3374,14 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) { rtx lab; lab = gen_label_rtx (); - emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_beq (lab)); + do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab); expand_inc (t1, const1_rtx); emit_label (lab); quotient = t1; } else - quotient = force_operand (gen_rtx (PLUS, compute_mode, - t1, t3), + quotient = force_operand (gen_rtx_PLUS (compute_mode, + t1, t3), tquotient); break; } @@ -3315,7 +3391,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) quotient or remainder to get ceiling rounding, once we have the remainder. Notice that we compute also the final remainder value here, and return the result right away. */ - if (target == 0) + if (target == 0 || GET_MODE (target) != compute_mode) target = gen_reg_rtx (compute_mode); if (rem_flag) @@ -3337,9 +3413,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) /* This could be computed with a branch-less sequence. Save that for later. */ rtx label = gen_label_rtx (); - emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_beq (label)); + do_cmp_and_jump (remainder, const0_rtx, EQ, + compute_mode, label); expand_inc (quotient, const1_rtx); expand_dec (remainder, op1); emit_label (label); @@ -3356,9 +3431,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) adjusted_op0 = copy_to_mode_reg (compute_mode, op0); label1 = gen_label_rtx (); label2 = gen_label_rtx (); - emit_cmp_insn (adjusted_op0, const0_rtx, NE, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_bne (label1)); + do_cmp_and_jump (adjusted_op0, const0_rtx, NE, + compute_mode, label1); emit_move_insn (quotient, const0_rtx); emit_jump_insn (gen_jump (label2)); emit_barrier (); @@ -3398,16 +3472,14 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) { rtx lab; lab = gen_label_rtx (); - emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_beq (lab)); + do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab); expand_inc (t1, const1_rtx); emit_label (lab); quotient = t1; } else - quotient = force_operand (gen_rtx (PLUS, compute_mode, - t1, t3), + quotient = force_operand (gen_rtx_PLUS (compute_mode, + t1, t3), tquotient); break; } @@ -3417,7 +3489,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) quotient or remainder to get ceiling rounding, once we have the remainder. Notice that we compute also the final remainder value here, and return the result right away. */ - if (target == 0) + if (target == 0 || GET_MODE (target) != compute_mode) target = gen_reg_rtx (compute_mode); if (rem_flag) { @@ -3439,14 +3511,11 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) Save that for later. */ rtx tem; rtx label = gen_label_rtx (); - emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_beq (label)); + do_cmp_and_jump (remainder, const0_rtx, EQ, + compute_mode, label); tem = expand_binop (compute_mode, xor_optab, op0, op1, NULL_RTX, 0, OPTAB_WIDEN); - emit_cmp_insn (tem, const0_rtx, LT, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_blt (label)); + do_cmp_and_jump (tem, const0_rtx, LT, compute_mode, label); expand_inc (quotient, const1_rtx); expand_dec (remainder, op1); emit_label (label); @@ -3467,12 +3536,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) label3 = gen_label_rtx (); label4 = gen_label_rtx (); label5 = gen_label_rtx (); - emit_cmp_insn (op1, const0_rtx, LT, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_blt (label2)); - emit_cmp_insn (adjusted_op0, const0_rtx, GT, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_bgt (label1)); + do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2); + do_cmp_and_jump (adjusted_op0, const0_rtx, GT, + compute_mode, label1); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) @@ -3484,9 +3550,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) emit_jump_insn (gen_jump (label4)); emit_barrier (); emit_label (label2); - emit_cmp_insn (adjusted_op0, const0_rtx, LT, NULL_RTX, - compute_mode, 0, 0); - emit_jump_insn (gen_blt (label3)); + do_cmp_and_jump (adjusted_op0, const0_rtx, LT, + compute_mode, label3); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) @@ -3524,10 +3589,11 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) insn = get_last_insn (); REG_NOTES (insn) - = gen_rtx (EXPR_LIST, REG_EQUAL, - gen_rtx (unsignedp ? UDIV : DIV, compute_mode, - op0, op1), - REG_NOTES (insn)); + = gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_fmt_ee (unsignedp ? UDIV : DIV, + compute_mode, + op0, op1), + REG_NOTES (insn)); } break; @@ -3552,8 +3618,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) tem = plus_constant (op1, -1); tem = expand_shift (RSHIFT_EXPR, compute_mode, tem, build_int_2 (1, 0), NULL_RTX, 1); - emit_cmp_insn (remainder, tem, LEU, NULL_RTX, compute_mode, 0, 0); - emit_jump_insn (gen_bleu (label)); + do_cmp_and_jump (remainder, tem, LEU, compute_mode, label); expand_inc (quotient, const1_rtx); expand_dec (remainder, op1); emit_label (label); @@ -3578,8 +3643,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0, 0); tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem, build_int_2 (1, 0), NULL_RTX, 1); - emit_cmp_insn (tem, abs_op1, LTU, NULL_RTX, compute_mode, 0, 0); - emit_jump_insn (gen_bltu (label)); + do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label); tem = expand_binop (compute_mode, xor_optab, op0, op1, NULL_RTX, 0, OPTAB_WIDEN); mask = expand_shift (RSHIFT_EXPR, compute_mode, tem, @@ -3597,10 +3661,16 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) emit_label (label); } return gen_lowpart (mode, rem_flag ? remainder : quotient); + + default: + abort (); } if (quotient == 0) { + if (target && GET_MODE (target) != compute_mode) + target = 0; + if (rem_flag) { /* Try to produce the remainder directly without a library call. */ @@ -3624,11 +3694,18 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) return gen_lowpart (mode, remainder); } - /* Produce the quotient. */ - /* Try a quotient insn, but not a library call. */ - quotient = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab, - op0, op1, rem_flag ? NULL_RTX : target, - unsignedp, OPTAB_WIDEN); + /* Produce the quotient. Try a quotient insn, but not a library call. + If we have a divmod in this mode, use it in preference to widening + the div (for this test we assume it will not fail). Note that optab2 + is set to the one of the two optabs that the call below will use. */ + quotient + = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab, + op0, op1, rem_flag ? NULL_RTX : target, + unsignedp, + ((optab2->handlers[(int) compute_mode].insn_code + != CODE_FOR_nothing) + ? OPTAB_DIRECT : OPTAB_WIDEN)); + if (quotient == 0) { /* No luck there. Try a quotient-and-remainder insn, @@ -3652,6 +3729,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) if (rem_flag) { + if (target && GET_MODE (target) != compute_mode) + target = 0; + if (quotient == 0) /* No divide instruction either. Use library for remainder. */ remainder = sign_expand_binop (compute_mode, umod_optab, smod_optab, @@ -3834,7 +3914,7 @@ expand_and (op0, op1, target) to perform the operation. It says to use zero-extension. NORMALIZEP is 1 if we should convert the result to be either zero - or one one. Normalize is -1 if we should convert the result to be + or one. Normalize is -1 if we should convert the result to be either zero or -1. If NORMALIZEP is zero, the result will be left "raw" out of the scc insn. */ @@ -3872,7 +3952,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) /* For some comparisons with 1 and -1, we can convert this to comparisons with zero. This will often produce more opportunities for - store-flag insns. */ + store-flag insns. */ switch (code) { @@ -3900,6 +3980,8 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) if (op1 == const1_rtx) op1 = const0_rtx, code = EQ; break; + default: + break; } /* From now on, we won't change CODE, so set ICODE now. */ @@ -3911,7 +3993,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) && GET_MODE_CLASS (mode) == MODE_INT && (normalizep || STORE_FLAG_VALUE == 1 || (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT - && (STORE_FLAG_VALUE + && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode)) == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))))) { subtarget = target; @@ -3930,9 +4012,11 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) subtarget = 0; if (code == GE) - op0 = expand_unop (mode, one_cmpl_optab, op0, subtarget, 0); + op0 = expand_unop (mode, one_cmpl_optab, op0, + ((STORE_FLAG_VALUE == 1 || normalizep) + ? 0 : subtarget), 0); - if (normalizep || STORE_FLAG_VALUE == 1) + if (STORE_FLAG_VALUE == 1 || normalizep) /* If we are supposed to produce a 0/1 value, we want to do a logical shift from the sign bit to the low-order bit; for a -1/0 value, we do an arithmetic shift. */ @@ -4103,7 +4187,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) normalizep = STORE_FLAG_VALUE; else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT - && (STORE_FLAG_VALUE + && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode)) == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))) ; else @@ -4221,3 +4305,119 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) return tem; } + +/* Like emit_store_flag, but always succeeds. */ + +rtx +emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep) + rtx target; + enum rtx_code code; + rtx op0, op1; + enum machine_mode mode; + int unsignedp; + int normalizep; +{ + rtx tem, label; + + /* First see if emit_store_flag can do the job. */ + tem = emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep); + if (tem != 0) + return tem; + + if (normalizep == 0) + normalizep = 1; + + /* If this failed, we have to do this with set/compare/jump/set code. */ + + if (GET_CODE (target) != REG + || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1)) + target = gen_reg_rtx (GET_MODE (target)); + + emit_move_insn (target, const1_rtx); + tem = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX, 0); + if (GET_CODE (tem) == CONST_INT) + return tem; + + label = gen_label_rtx (); + if (bcc_gen_fctn[(int) code] == 0) + abort (); + + emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label)); + emit_move_insn (target, const0_rtx); + emit_label (label); + + return target; +} + +/* Perform possibly multi-word comparison and conditional jump to LABEL + if ARG1 OP ARG2 true where ARG1 and ARG2 are of mode MODE + + The algorithm is based on the code in expr.c:do_jump. + + Note that this does not perform a general comparison. Only variants + generated within expmed.c are correctly handled, others abort (but could + be handled if needed). */ + +static void +do_cmp_and_jump (arg1, arg2, op, mode, label) + rtx arg1, arg2, label; + enum rtx_code op; + enum machine_mode mode; +{ + /* 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 (mode)) + { + rtx label2 = gen_label_rtx (); + + switch (op) + { + case LTU: + do_jump_by_parts_greater_rtx (mode, 1, arg2, arg1, label2, label); + break; + + case LEU: + do_jump_by_parts_greater_rtx (mode, 1, arg1, arg2, label, label2); + break; + + case LT: + do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label2, label); + break; + + case GT: + do_jump_by_parts_greater_rtx (mode, 0, arg1, arg2, label2, label); + break; + + case GE: + do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label, label2); + break; + + /* do_jump_by_parts_equality_rtx compares with zero. Luckily + that's the only equality operations we do */ + case EQ: + if (arg2 != const0_rtx || mode != GET_MODE(arg1)) + abort(); + do_jump_by_parts_equality_rtx (arg1, label2, label); + break; + + case NE: + if (arg2 != const0_rtx || mode != GET_MODE(arg1)) + abort(); + do_jump_by_parts_equality_rtx (arg1, label, label2); + break; + + default: + abort(); + } + + emit_label (label2); + } + else + { + emit_cmp_insn(arg1, arg2, op, NULL_RTX, mode, 0, 0); + if (bcc_gen_fctn[(int) op] == 0) + abort (); + emit_jump_insn ((*bcc_gen_fctn[(int) op]) (label)); + } +} |