summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/expmed.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>1999-08-26 09:30:50 +0000
committerobrien <obrien@FreeBSD.org>1999-08-26 09:30:50 +0000
commit0bedf4fb30066e5e1d4342a1d3914dae7d37cba7 (patch)
tree68d8110b41afd0ebbf39167b1a4918eea667a7c5 /contrib/gcc/expmed.c
parentd4db5fb866b7ad5216abd5047774a3973b9901a9 (diff)
downloadFreeBSD-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.c780
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));
+ }
+}
OpenPOWER on IntegriCloud