diff options
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r-- | gcc/expmed.c | 186 |
1 files changed, 144 insertions, 42 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c index f9bd9ad20be..37116e30e05 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -261,6 +261,21 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) op0 = SUBREG_REG (op0); } + /* Make sure we are playing with integral modes. Pun with subregs + if we aren't. */ + { + enum machine_mode imode = int_mode_for_mode (GET_MODE (op0)); + if (imode != GET_MODE (op0)) + { + if (GET_CODE (op0) == MEM) + op0 = change_address (op0, imode, NULL_RTX); + else if (imode != BLKmode) + op0 = gen_lowpart (imode, op0); + else + abort (); + } + } + /* 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. */ @@ -287,6 +302,18 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) can be done with just SUBREG. */ if (GET_MODE (op0) != fieldmode) { + if (GET_CODE (op0) == SUBREG) + { + if (GET_MODE (SUBREG_REG (op0)) == fieldmode + || GET_MODE_CLASS (fieldmode) == MODE_INT + || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT) + op0 = SUBREG_REG (op0); + else + /* Else we've got some float mode source being extracted into + a different float mode destination -- this combination of + subregs results in Severe Tire Damage. */ + abort (); + } if (GET_CODE (op0) == REG) op0 = gen_rtx_SUBREG (fieldmode, op0, offset); else @@ -320,8 +347,22 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) else { int icode = movstrict_optab->handlers[(int) fieldmode].insn_code; - if(! (*insn_operand_predicate[icode][1]) (value, fieldmode)) + if (! (*insn_operand_predicate[icode][1]) (value, fieldmode)) value = copy_to_mode_reg (fieldmode, value); + + if (GET_CODE (op0) == SUBREG) + { + if (GET_MODE (SUBREG_REG (op0)) == fieldmode + || GET_MODE_CLASS (fieldmode) == MODE_INT + || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT) + op0 = SUBREG_REG (op0); + else + /* Else we've got some float mode source being extracted into + a different float mode destination -- this combination of + subregs results in Severe Tire Damage. */ + abort (); + } + emit_insn (GEN_FCN (icode) (gen_rtx_SUBREG (fieldmode, op0, offset), value)); } @@ -376,12 +417,27 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) /* OFFSET is the number of words or bytes (UNIT says which) from STR_RTX to the first word or byte containing part of the field. */ - if (GET_CODE (op0) == REG) + if (GET_CODE (op0) != MEM) { 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, offset); + { + if (GET_CODE (op0) != REG) + { + /* Since this is a destination (lvalue), we can't copy it to a + pseudo. We can trivially remove a SUBREG that does not + change the size of the operand. Such a SUBREG may have been + added above. Otherwise, abort. */ + if (GET_CODE (op0) == SUBREG + && (GET_MODE_SIZE (GET_MODE (op0)) + == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))) + op0 = SUBREG_REG (op0); + else + abort (); + } + op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0), + op0, offset); + } offset = 0; } else @@ -512,7 +568,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 = copy_to_reg (value1); value1 = gen_rtx_SUBREG (maxmode, value1, 0); } else @@ -955,6 +1011,21 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, op0 = SUBREG_REG (op0); } + /* Make sure we are playing with integral modes. Pun with subregs + if we aren't. */ + { + enum machine_mode imode = int_mode_for_mode (GET_MODE (op0)); + if (imode != GET_MODE (op0)) + { + if (GET_CODE (op0) == MEM) + op0 = change_address (op0, imode, NULL_RTX); + else if (imode != BLKmode) + op0 = gen_lowpart (imode, op0); + else + abort (); + } + } + /* ??? 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. */ @@ -973,7 +1044,7 @@ 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) != MEM && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), GET_MODE_BITSIZE (GET_MODE (op0)))) || (GET_CODE (op0) == MEM @@ -996,6 +1067,18 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, if (mode1 != GET_MODE (op0)) { + if (GET_CODE (op0) == SUBREG) + { + if (GET_MODE (SUBREG_REG (op0)) == mode1 + || GET_MODE_CLASS (mode1) == MODE_INT + || GET_MODE_CLASS (mode1) == MODE_PARTIAL_INT) + op0 = SUBREG_REG (op0); + else + /* Else we've got some float mode source being extracted into + a different float mode destination -- this combination of + subregs results in Severe Tire Damage. */ + abort (); + } if (GET_CODE (op0) == REG) op0 = gen_rtx_SUBREG (mode1, op0, offset); else @@ -1088,12 +1171,16 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, /* OFFSET is the number of words or bytes (UNIT says which) from STR_RTX to the first word or byte containing part of the field. */ - if (GET_CODE (op0) == REG) + if (GET_CODE (op0) != MEM) { 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, offset); + { + if (GET_CODE (op0) != REG) + op0 = copy_to_reg (op0); + op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0), + op0, offset); + } offset = 0; } else @@ -1800,7 +1887,8 @@ expand_shift (code, mode, shifted, amount, target, unsignedp) if (SHIFT_COUNT_TRUNCATED) { if (GET_CODE (op1) == CONST_INT - && (unsigned HOST_WIDE_INT) INTVAL (op1) >= GET_MODE_BITSIZE (mode)) + && ((unsigned HOST_WIDE_INT) INTVAL (op1) >= + (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode))) op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1) % GET_MODE_BITSIZE (mode)); else if (GET_CODE (op1) == SUBREG @@ -1975,7 +2063,7 @@ synth_mult (alg_out, t, cost_limit) { int m; struct algorithm *alg_in, *best_alg; - unsigned int cost; + int cost; unsigned HOST_WIDE_INT q; /* Indicate that no algorithm is yet found. If no algorithm @@ -2385,10 +2473,10 @@ expand_mult (mode, op0, op1, target, unsignedp) multiplication sequences. */ 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)); + set_unique_reg_note (insn, + REG_EQUAL, + gen_rtx_MULT (mode, op0, + GEN_INT (val_so_far))); } if (variant == negate_variant) @@ -2764,6 +2852,27 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost) This could optimize to a bfexts instruction. But C doesn't use these operations, so their optimizations are left for later. */ +/* ??? For modulo, we don't actually need the highpart of the first product, + the low part will do nicely. And for small divisors, the second multiply + can also be a low-part only multiply or even be completely left out. + E.g. to calculate the remainder of a division by 3 with a 32 bit + multiply, multiply with 0x55555556 and extract the upper two bits; + 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 + 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, + 0, 8, 0, 11, 12, 10, 36, 0, 30, 0, 0, 12, 0, 0, 0, 0, 44, 12, 24, 0, + 20, 0, 7, 14, 0, 18, 36, 0, 0, 46, 60, 0, 42, 0, 15, 24, 20, 0, 0, 33, + 0, 20, 0, 0, 18, 0, 60, 0, 0, 0, 0, 0, 40, 18, 0, 0, 12 + + Cross-sum rules for even numbers can be derived by leaving as many bits + to the right alone as the divisor has zeros to the right. + E.g. if x is an unsigned 32 bit number: + (x mod 12) == (((x & 1023) + ((x >> 8) & ~3)) * 0x15555558 >> 2 * 3) >> 28 + */ #define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0) @@ -3061,10 +3170,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) 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)); + set_unique_reg_note (insn, + REG_EQUAL, + gen_rtx_UDIV (compute_mode, op0, op1)); } else /* TRUNC_DIV, signed */ { @@ -3138,12 +3246,11 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) 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, - GEN_INT (abs_d)), - REG_NOTES (insn)); + set_unique_reg_note (insn, + REG_EQUAL, + gen_rtx_DIV (compute_mode, + op0, + GEN_INT (abs_d))); quotient = expand_unop (compute_mode, neg_optab, quotient, quotient, 0); @@ -3208,10 +3315,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) 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)); + set_unique_reg_note (insn, + REG_EQUAL, + gen_rtx_DIV (compute_mode, op0, op1)); } break; } @@ -3624,12 +3730,11 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) NULL_RTX, unsignedp); insn = get_last_insn (); - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_EQUAL, - gen_rtx_fmt_ee (unsignedp ? UDIV : DIV, - compute_mode, - op0, op1), - REG_NOTES (insn)); + set_unique_reg_note (insn, + REG_EQUAL, + gen_rtx_fmt_ee (unsignedp ? UDIV : DIV, + compute_mode, + op0, op1)); } break; @@ -3675,8 +3780,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) remainder = expand_binop (compute_mode, sub_optab, op0, tem, remainder, 0, OPTAB_LIB_WIDEN); } - abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 0, 0); - abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0, 0); + abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 0); + abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0); tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem, build_int_2 (1, 0), NULL_RTX, 1); do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label); @@ -4238,7 +4343,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode)) - == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))) + == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))) ; else return 0; @@ -4465,9 +4570,6 @@ do_cmp_and_jump (arg1, arg2, op, mode, label) } 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)); + emit_cmp_and_jump_insns (arg1, arg2, op, NULL_RTX, mode, 0, 0, label); } } |