/* Medium-level subroutines: convert bit-field store and extract
and shifts, multiplies and divides to rtl instructions.
- Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "toplev.h"
#include "rtl.h"
#include "tree.h"
+#include "tm_p.h"
#include "flags.h"
#include "insn-flags.h"
#include "insn-codes.h"
#include "real.h"
#include "recog.h"
-static void store_fixed_bit_field PROTO((rtx, int, int, int, rtx, int));
-static void store_split_bit_field PROTO((rtx, int, int, rtx, int));
-static rtx extract_fixed_bit_field PROTO((enum machine_mode, rtx, int,
- int, int, rtx, int, int));
-static rtx mask_rtx PROTO((enum machine_mode, int,
- int, 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))
+static void store_fixed_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, rtx,
+ unsigned int));
+static void store_split_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, rtx,
+ unsigned int));
+static rtx extract_fixed_bit_field PARAMS ((enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT,
+ rtx, int, unsigned int));
+static rtx mask_rtx PARAMS ((enum machine_mode, int,
+ int, int));
+static rtx lshift_value PARAMS ((enum machine_mode, rtx,
+ int, int));
+static rtx extract_split_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, int,
+ unsigned int));
+static void do_cmp_and_jump PARAMS ((rtx, rtx, enum rtx_code,
+ enum machine_mode, rtx));
/* Non-zero means divides or modulus operations are relatively cheap for
powers of two, so don't use branches; emit the operation instead.
static int sdiv_pow2_cheap, smod_pow2_cheap;
#ifndef SLOW_UNALIGNED_ACCESS
-#define SLOW_UNALIGNED_ACCESS STRICT_ALIGNMENT
+#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
#endif
/* For compilers that support multiple targets with different word sizes,
#define MAX_BITS_PER_WORD BITS_PER_WORD
#endif
-/* Cost of various pieces of RTL. Note that some of these are indexed by shift count,
- and some by mode. */
+/* Cost of various pieces of RTL. Note that some of these are indexed by
+ shift count and some by mode. */
static int add_cost, negate_cost, zero_cost;
static int shift_cost[MAX_BITS_PER_WORD];
static int shiftadd_cost[MAX_BITS_PER_WORD];
void
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);
start_sequence ();
- /* 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);
-
- reg = gen_rtx (REG, word_mode, 10000);
+ reg = gen_rtx_REG (word_mode, 10000);
zero_cost = rtx_cost (const0_rtx, 0);
add_cost = rtx_cost (gen_rtx_PLUS (word_mode, reg, 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)))),
+ 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);
}
}
- /* Free the objects we just allocated. */
end_sequence ();
- obfree (free_point);
}
/* Return an rtx representing minus the value of X.
into a bit-field within structure STR_RTX
containing BITSIZE bits starting at bit BITNUM.
FIELDMODE is the machine-mode of the FIELD_DECL node for this field.
- ALIGN is the alignment that STR_RTX is known to have, measured in bytes.
+ ALIGN is the alignment that STR_RTX is known to have.
TOTAL_SIZE is the size of the structure in bytes, or -1 if varying. */
/* ??? Note that there are two different ideas here for how
rtx
store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
rtx str_rtx;
- register int bitsize;
- int bitnum;
+ unsigned HOST_WIDE_INT bitsize;
+ unsigned HOST_WIDE_INT bitnum;
enum machine_mode fieldmode;
rtx value;
- int align;
- int total_size;
+ unsigned int align;
+ HOST_WIDE_INT total_size;
{
- int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;
- register int offset = bitnum / unit;
- register int bitpos = bitnum % unit;
+ unsigned int unit
+ = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;
+ unsigned HOST_WIDE_INT offset = bitnum / unit;
+ unsigned HOST_WIDE_INT bitpos = bitnum % unit;
register rtx op0 = str_rtx;
#ifdef HAVE_insv
- int insv_bitsize;
+ unsigned HOST_WIDE_INT insv_bitsize;
+ enum machine_mode op_mode;
- if (insn_operand_mode[(int) CODE_FOR_insv][3] == VOIDmode)
- insv_bitsize = GET_MODE_BITSIZE (word_mode);
- else
- insv_bitsize = GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_insv][3]);
+ op_mode = insn_data[(int) CODE_FOR_insv].operand[3].mode;
+ if (op_mode == VOIDmode)
+ op_mode = word_mode;
+ insv_bitsize = GET_MODE_BITSIZE (op_mode);
#endif
if (GET_CODE (str_rtx) == MEM && ! MEM_IN_STRUCT_P (str_rtx))
if (flag_force_mem)
value = force_not_mem (value);
- /* Note that the adjustment of BITPOS above has no effect on whether
- BITPOS is 0 in a REG bigger than a word. */
- if (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
+ if ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
+ || (GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode)
+ && GET_MODE_SIZE (fieldmode) != 0))
&& (GET_CODE (op0) != MEM
- || ! SLOW_UNALIGNED_ACCESS
+ || ! SLOW_UNALIGNED_ACCESS (fieldmode, align)
|| (offset * BITS_PER_UNIT % bitsize == 0
- && align % GET_MODE_SIZE (fieldmode) == 0))
- && bitpos == 0 && bitsize == GET_MODE_BITSIZE (fieldmode))
+ && align % GET_MODE_BITSIZE (fieldmode) == 0))
+ && (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0)
+ && bitsize == GET_MODE_BITSIZE (fieldmode))
{
/* Storing in a full-word or multi-word field in a register
+ can be done with just SUBREG. Also, storing in the entire object
can be done with just SUBREG. */
if (GET_MODE (op0) != fieldmode)
{
if (GET_CODE (op0) != MEM
&& (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0)
&& bitsize == GET_MODE_BITSIZE (fieldmode)
- && (GET_MODE (op0) == fieldmode
- || (movstrict_optab->handlers[(int) fieldmode].insn_code
- != CODE_FOR_nothing)))
+ && (movstrict_optab->handlers[(int) fieldmode].insn_code
+ != CODE_FOR_nothing))
{
+ int icode = movstrict_optab->handlers[(int) fieldmode].insn_code;
+
/* Get appropriate low part of the value being stored. */
if (GET_CODE (value) == CONST_INT || GET_CODE (value) == REG)
value = gen_lowpart (fieldmode, value);
|| GET_CODE (value) == CONST))
value = convert_to_mode (fieldmode, value, 0);
- if (GET_MODE (op0) == fieldmode)
- emit_move_insn (op0, value);
- else
+ if (! (*insn_data[icode].operand[1].predicate) (value, fieldmode))
+ value = copy_to_mode_reg (fieldmode, value);
+
+ if (GET_CODE (op0) == SUBREG)
{
- int icode = movstrict_optab->handlers[(int) fieldmode].insn_code;
- if (! (*insn_operand_predicate[icode][1]) (value, fieldmode))
- value = copy_to_mode_reg (fieldmode, value);
+ 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) == 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));
- emit_insn (GEN_FCN (icode)
- (gen_rtx_SUBREG (fieldmode, op0, offset), value));
- }
return value;
}
be less than full.
However, only do that if the value is not BLKmode. */
- int backwards = WORDS_BIG_ENDIAN && fieldmode != BLKmode;
-
- int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
- int i;
+ unsigned int backwards = WORDS_BIG_ENDIAN && fieldmode != BLKmode;
+ unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
+ unsigned int i;
/* This is the mode we must force value to, so that there will be enough
subwords to extract. Note that fieldmode will often (always?) be
{
/* If I is 0, use the low-order word in both field and target;
if I is 1, use the next to lowest word; and so on. */
- int wordnum = (backwards ? nwords - i - 1 : i);
- int bit_offset = (backwards
- ? MAX (bitsize - (i + 1) * BITS_PER_WORD, 0)
- : i * BITS_PER_WORD);
+ unsigned int wordnum = (backwards ? nwords - i - 1 : i);
+ unsigned int bit_offset = (backwards
+ ? MAX ((int) bitsize - ((int) i + 1)
+ * BITS_PER_WORD,
+ 0)
+ : (int) i * BITS_PER_WORD);
+
store_bit_field (op0, MIN (BITS_PER_WORD,
bitsize - i * BITS_PER_WORD),
bitnum + bit_offset, word_mode,
enum machine_mode maxmode;
int save_volatile_ok = volatile_ok;
- maxmode = insn_operand_mode[(int) CODE_FOR_insv][3];
+ maxmode = insn_data[(int) CODE_FOR_insv].operand[3].mode;
if (maxmode == VOIDmode)
maxmode = word_mode;
/* 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
- && ! ((*insn_operand_predicate[(int) CODE_FOR_insv][0])
+ && ! ((*insn_data[(int) CODE_FOR_insv].operand[0].predicate)
(op0, VOIDmode)))
{
rtx tempreg;
if (GET_MODE (op0) == BLKmode
|| GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (maxmode))
bestmode
- = get_best_mode (bitsize, bitnum, align * BITS_PER_UNIT, maxmode,
+ = get_best_mode (bitsize, bitnum, align, maxmode,
MEM_VOLATILE_P (op0));
else
bestmode = GET_MODE (op0);
if (bestmode == VOIDmode
- || (SLOW_UNALIGNED_ACCESS && GET_MODE_SIZE (bestmode) > align))
+ || (SLOW_UNALIGNED_ACCESS (bestmode, align)
+ && GET_MODE_BITSIZE (bestmode) > align))
goto insv_loses;
/* Adjust address to point to the containing unit of that mode. */
op0 = change_address (op0, bestmode,
plus_constant (XEXP (op0, 0), offset));
- /* Fetch that unit, store the bitfield in it, then store the unit. */
+ /* Fetch that unit, store the bitfield in it, then store
+ the unit. */
tempreg = copy_to_reg (op0);
store_bit_field (tempreg, bitsize, bitpos, fieldmode, value,
align, total_size);
/* If this machine's insv insists on a register,
get VALUE1 into a register. */
- if (! ((*insn_operand_predicate[(int) CODE_FOR_insv][3])
+ if (! ((*insn_data[(int) CODE_FOR_insv].operand[3].predicate)
(value1, maxmode)))
value1 = force_reg (maxmode, value1);
(If OP0 is a register, it may be a full word or a narrower mode,
but BITPOS still counts within a full word,
which is significant on bigendian machines.)
- STRUCT_ALIGN is the alignment the structure is known to have (in bytes).
+ STRUCT_ALIGN is the alignment the structure is known to have.
Note that protect_from_queue has already been done on OP0 and VALUE. */
static void
store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align)
register rtx op0;
- register int offset, bitsize, bitpos;
+ unsigned HOST_WIDE_INT offset, bitsize, bitpos;
register rtx value;
- int struct_align;
+ unsigned int struct_align;
{
register enum machine_mode mode;
- int total_bits = BITS_PER_WORD;
+ unsigned int total_bits = BITS_PER_WORD;
rtx subtarget, temp;
int all_zero = 0;
int all_one = 0;
- if (! SLOW_UNALIGNED_ACCESS)
- struct_align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ if (! SLOW_UNALIGNED_ACCESS (word_mode, struct_align))
+ struct_align = BIGGEST_ALIGNMENT;
/* There is a case not handled here:
a structure with a known alignment of just a halfword
a word, we won't be doing the extraction the normal way. */
mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
- struct_align * BITS_PER_UNIT, word_mode,
+ struct_align, word_mode,
GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0));
if (mode == VOIDmode)
BITSIZE is the field width; BITPOS the position of its first bit
(within the word).
VALUE is the value to store.
- ALIGN is the known alignment of OP0, measured in bytes.
+ ALIGN is the known alignment of OP0.
This is also the size of the memory objects to be used.
This does not yet handle fields wider than BITS_PER_WORD. */
static void
store_split_bit_field (op0, bitsize, bitpos, value, align)
rtx op0;
- int bitsize, bitpos;
+ unsigned HOST_WIDE_INT bitsize, bitpos;
rtx value;
- int align;
+ unsigned int align;
{
- int unit;
- int bitsdone = 0;
+ unsigned int unit;
+ unsigned int bitsdone = 0;
/* Make sure UNIT isn't larger than BITS_PER_WORD, we can only handle that
much at a time. */
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
unit = BITS_PER_WORD;
else
- unit = MIN (align * BITS_PER_UNIT, BITS_PER_WORD);
+ unit = MIN (align, BITS_PER_WORD);
/* If VALUE is a constant other than a CONST_INT, get it into a register in
WORD_MODE. If we can do this using gen_lowpart_common, do so. Note
while (bitsdone < bitsize)
{
- int thissize;
+ unsigned HOST_WIDE_INT thissize;
rtx part, word;
- int thispos;
- int offset;
+ unsigned HOST_WIDE_INT thispos;
+ unsigned HOST_WIDE_INT offset;
offset = (bitpos + bitsdone) / unit;
thispos = (bitpos + bitsdone) % unit;
GET_MODE (value) == VOIDmode
? UNITS_PER_WORD
: (GET_MODE (value) == BLKmode
- ? 1
- : GET_MODE_ALIGNMENT (GET_MODE (value)) / BITS_PER_UNIT));
+ ? 1 : GET_MODE_ALIGNMENT (GET_MODE (value))));
}
else
{
GET_MODE (value) == VOIDmode
? UNITS_PER_WORD
: (GET_MODE (value) == BLKmode
- ? 1
- : GET_MODE_ALIGNMENT (GET_MODE (value)) / BITS_PER_UNIT));
+ ? 1 : GET_MODE_ALIGNMENT (GET_MODE (value))));
}
/* If OP0 is a register, then handle OFFSET here.
TMODE is the mode the caller would like the value to have;
but the value may be returned with type MODE instead.
- ALIGN is the alignment that STR_RTX is known to have, measured in bytes.
+ ALIGN is the alignment that STR_RTX is known to have.
TOTAL_SIZE is the size in bytes of the containing structure,
or -1 if varying.
extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
target, mode, tmode, align, total_size)
rtx str_rtx;
- register int bitsize;
- int bitnum;
+ unsigned HOST_WIDE_INT bitsize;
+ unsigned HOST_WIDE_INT bitnum;
int unsignedp;
rtx target;
enum machine_mode mode, tmode;
- int align;
- int total_size;
+ unsigned int align;
+ HOST_WIDE_INT total_size;
{
- int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;
- register int offset = bitnum / unit;
- register int bitpos = bitnum % unit;
+ unsigned int unit
+ = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;
+ unsigned HOST_WIDE_INT offset = bitnum / unit;
+ unsigned HOST_WIDE_INT bitpos = bitnum % unit;
register rtx op0 = str_rtx;
rtx spec_target = target;
rtx spec_target_subreg = 0;
+ enum machine_mode int_mode;
#ifdef HAVE_extv
- int extv_bitsize;
+ unsigned HOST_WIDE_INT extv_bitsize;
+ enum machine_mode extv_mode;
#endif
#ifdef HAVE_extzv
- int extzv_bitsize;
+ unsigned HOST_WIDE_INT extzv_bitsize;
+ enum machine_mode extzv_mode;
#endif
#ifdef HAVE_extv
- if (insn_operand_mode[(int) CODE_FOR_extv][0] == VOIDmode)
- extv_bitsize = GET_MODE_BITSIZE (word_mode);
- else
- extv_bitsize = GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_extv][0]);
+ extv_mode = insn_data[(int) CODE_FOR_extv].operand[0].mode;
+ if (extv_mode == VOIDmode)
+ extv_mode = word_mode;
+ extv_bitsize = GET_MODE_BITSIZE (extv_mode);
#endif
#ifdef HAVE_extzv
- if (insn_operand_mode[(int) CODE_FOR_extzv][0] == VOIDmode)
- extzv_bitsize = GET_MODE_BITSIZE (word_mode);
- else
- extzv_bitsize
- = GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_extzv][0]);
+ extzv_mode = insn_data[(int) CODE_FOR_extzv].operand[0].mode;
+ if (extzv_mode == VOIDmode)
+ extzv_mode = word_mode;
+ extzv_bitsize = GET_MODE_BITSIZE (extzv_mode);
#endif
/* Discount the part of the structure before the desired byte.
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
GET_MODE_BITSIZE (GET_MODE (op0))))
|| (GET_CODE (op0) == MEM
- && (! SLOW_UNALIGNED_ACCESS
+ && (! SLOW_UNALIGNED_ACCESS (mode, align)
|| (offset * BITS_PER_UNIT % bitsize == 0
- && align * BITS_PER_UNIT % bitsize == 0))))
+ && align % bitsize == 0))))
&& ((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode)
&& bitpos % BITS_PER_WORD == 0)
|| (mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0) != BLKmode
: bitpos == 0))))
{
enum machine_mode mode1
- = mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0);
+ = (VECTOR_MODE_P (tmode) ? mode
+ : mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0));
if (mode1 != GET_MODE (op0))
{
This is because the most significant word is the one which may
be less than full. */
- int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
- int i;
+ unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
+ unsigned int i;
if (target == 0 || GET_CODE (target) != REG)
target = gen_reg_rtx (mode);
/* If I is 0, use the low-order word in both field and target;
if I is 1, use the next to lowest word; and so on. */
/* Word number in TARGET to use. */
- int wordnum = (WORDS_BIG_ENDIAN
- ? GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD - i - 1
- : i);
+ unsigned int wordnum
+ = (WORDS_BIG_ENDIAN
+ ? GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD - i - 1
+ : i);
/* Offset from start of field in OP0. */
- int bit_offset = (WORDS_BIG_ENDIAN
- ? MAX (0, bitsize - (i + 1) * BITS_PER_WORD)
- : i * BITS_PER_WORD);
+ unsigned int bit_offset = (WORDS_BIG_ENDIAN
+ ? MAX (0, ((int) bitsize - ((int) i + 1)
+ * (int) BITS_PER_WORD))
+ : (int) i * BITS_PER_WORD);
rtx target_part = operand_subword (target, wordnum, 1, VOIDmode);
rtx result_part
= extract_bit_field (op0, MIN (BITS_PER_WORD,
bitsize - i * BITS_PER_WORD),
- bitnum + bit_offset,
- 1, target_part, mode, word_mode,
- align, total_size);
+ bitnum + bit_offset, 1, target_part, mode,
+ word_mode, align, total_size);
if (target_part == 0)
abort ();
need to be zero'd out. */
if (GET_MODE_SIZE (GET_MODE (target)) > nwords * UNITS_PER_WORD)
{
- int i,total_words;
+ unsigned int i, total_words;
total_words = GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD;
for (i = nwords; i < total_words; i++)
NULL_RTX, 0);
}
- /* From here on we know the desired field is smaller than a word
- so we can assume it is an integer. So we can safely extract it as one
- size of integer, if necessary, and then truncate or extend
- to the size that is wanted. */
+ /* From here on we know the desired field is smaller than a word. */
+
+ /* Check if there is a correspondingly-sized integer field, so we can
+ safely extract it as one size of integer, if necessary; then
+ truncate or extend to the size that is wanted; then use SUBREGs or
+ convert_to_mode to get one of the modes we really wanted. */
+
+ int_mode = int_mode_for_mode (tmode);
+ if (int_mode == BLKmode)
+ int_mode = int_mode_for_mode (mode);
+ if (int_mode == BLKmode)
+ abort(); /* Should probably push op0 out to memory and then
+ do a load. */
/* 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. */
&& ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > extzv_bitsize)))
{
- int xbitpos = bitpos, xoffset = offset;
+ unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
rtx last = get_last_insn ();
rtx xop0 = op0;
rtx pat;
enum machine_mode maxmode;
- maxmode = insn_operand_mode[(int) CODE_FOR_extzv][0];
+ maxmode = insn_data[(int) CODE_FOR_extzv].operand[0].mode;
if (maxmode == VOIDmode)
maxmode = word_mode;
volatile_ok = 1;
/* Is the memory operand acceptable? */
- if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1])
+ if (! ((*insn_data[(int) CODE_FOR_extzv].operand[1].predicate)
(xop0, GET_MODE (xop0))))
{
/* No, load into a reg and extract from there. */
if (GET_MODE (xop0) == BLKmode
|| (GET_MODE_SIZE (GET_MODE (op0))
> GET_MODE_SIZE (maxmode)))
- bestmode = get_best_mode (bitsize, bitnum,
- align * BITS_PER_UNIT, maxmode,
+ bestmode = get_best_mode (bitsize, bitnum, align, maxmode,
MEM_VOLATILE_P (xop0));
else
bestmode = GET_MODE (xop0);
if (bestmode == VOIDmode
- || (SLOW_UNALIGNED_ACCESS && GET_MODE_SIZE (bestmode) > align))
+ || (SLOW_UNALIGNED_ACCESS (bestmode, align)
+ && GET_MODE_BITSIZE (bestmode) > align))
goto extzv_loses;
/* Compute offset as multiple of this unit,
/* If this machine's extzv insists on a register target,
make sure we have one. */
- if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][0])
+ if (! ((*insn_data[(int) CODE_FOR_extzv].operand[0].predicate)
(xtarget, maxmode)))
xtarget = gen_reg_rtx (maxmode);
else
{
delete_insns_since (last);
- target = extract_fixed_bit_field (tmode, op0, offset, bitsize,
+ target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 1, align);
}
}
else
extzv_loses:
#endif
- target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
- target, 1, align);
+ target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
+ bitpos, target, 1, align);
}
else
{
rtx pat;
enum machine_mode maxmode;
- maxmode = insn_operand_mode[(int) CODE_FOR_extv][0];
+ maxmode = insn_data[(int) CODE_FOR_extv].operand[0].mode;
if (maxmode == VOIDmode)
maxmode = word_mode;
if (GET_CODE (xop0) == MEM)
{
/* Is the memory operand acceptable? */
- if (! ((*insn_operand_predicate[(int) CODE_FOR_extv][1])
+ if (! ((*insn_data[(int) CODE_FOR_extv].operand[1].predicate)
(xop0, GET_MODE (xop0))))
{
/* No, load into a reg and extract from there. */
if (GET_MODE (xop0) == BLKmode
|| (GET_MODE_SIZE (GET_MODE (op0))
> GET_MODE_SIZE (maxmode)))
- bestmode = get_best_mode (bitsize, bitnum,
- align * BITS_PER_UNIT, maxmode,
+ bestmode = get_best_mode (bitsize, bitnum, align, maxmode,
MEM_VOLATILE_P (xop0));
else
bestmode = GET_MODE (xop0);
if (bestmode == VOIDmode
- || (SLOW_UNALIGNED_ACCESS && GET_MODE_SIZE (bestmode) > align))
+ || (SLOW_UNALIGNED_ACCESS (bestmode, align)
+ && GET_MODE_BITSIZE (bestmode) > align))
goto extv_loses;
/* Compute offset as multiple of this unit,
/* If this machine's extv insists on a register target,
make sure we have one. */
- if (! ((*insn_operand_predicate[(int) CODE_FOR_extv][0])
+ if (! ((*insn_data[(int) CODE_FOR_extv].operand[0].predicate)
(xtarget, maxmode)))
xtarget = gen_reg_rtx (maxmode);
else
{
delete_insns_since (last);
- target = extract_fixed_bit_field (tmode, op0, offset, bitsize,
+ target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
bitpos, target, 0, align);
}
}
else
extv_loses:
#endif
- target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
- target, 0, align);
+ target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
+ bitpos, target, 0, align);
}
if (target == spec_target)
return target;
and return TARGET, but this is not guaranteed.
If TARGET is not used, create a pseudo-reg of mode TMODE for the value.
- ALIGN is the alignment that STR_RTX is known to have, measured in bytes. */
+ ALIGN is the alignment that STR_RTX is known to have. */
static rtx
extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
target, unsignedp, align)
enum machine_mode tmode;
register rtx op0, target;
- register int offset, bitsize, bitpos;
+ unsigned HOST_WIDE_INT offset, bitsize, bitpos;
int unsignedp;
- int align;
+ unsigned int align;
{
- int total_bits = BITS_PER_WORD;
+ unsigned int total_bits = BITS_PER_WORD;
enum machine_mode mode;
if (GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
includes the entire field. If such a mode would be larger than
a word, we won't be doing the extraction the normal way. */
- mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
- align * BITS_PER_UNIT, word_mode,
+ mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, align,
+ word_mode,
GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0));
if (mode == VOIDmode)
BITSIZE is the field width; BITPOS, position of its first bit, in the word.
UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend.
- ALIGN is the known alignment of OP0, measured in bytes.
- This is also the size of the memory objects to be used. */
+ ALIGN is the known alignment of OP0. This is also the size of the
+ memory objects to be used. */
static rtx
extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
rtx op0;
- int bitsize, bitpos, unsignedp, align;
+ unsigned HOST_WIDE_INT bitsize, bitpos;
+ int unsignedp;
+ unsigned int align;
{
- int unit;
- int bitsdone = 0;
+ unsigned int unit;
+ unsigned int bitsdone = 0;
rtx result = NULL_RTX;
int first = 1;
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
unit = BITS_PER_WORD;
else
- unit = MIN (align * BITS_PER_UNIT, BITS_PER_WORD);
+ unit = MIN (align, BITS_PER_WORD);
while (bitsdone < bitsize)
{
- int thissize;
+ unsigned HOST_WIDE_INT thissize;
rtx part, word;
- int thispos;
- int offset;
+ unsigned HOST_WIDE_INT thispos;
+ unsigned HOST_WIDE_INT offset;
offset = (bitpos + bitsdone) / unit;
thispos = (bitpos + bitsdone) % unit;
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));
+static void synth_mult PARAMS ((struct algorithm *,
+ unsigned HOST_WIDE_INT,
+ int));
+static unsigned HOST_WIDE_INT choose_multiplier PARAMS ((unsigned HOST_WIDE_INT,
+ int, int,
+ unsigned HOST_WIDE_INT *,
+ int *, int *));
+static unsigned HOST_WIDE_INT invert_mod2n PARAMS ((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
tem = expand_shift (LSHIFT_EXPR, mode, op0,
build_int_2 (log, 0), NULL_RTX, 0);
accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
- add_target ? add_target : accum_target);
+ add_target
+ ? add_target : accum_target);
val_so_far += (HOST_WIDE_INT) 1 << log;
break;
tem = expand_shift (LSHIFT_EXPR, mode, op0,
build_int_2 (log, 0), NULL_RTX, 0);
accum = force_operand (gen_rtx_MINUS (mode, accum, tem),
- add_target ? add_target : accum_target);
+ add_target
+ ? add_target : accum_target);
val_so_far -= (HOST_WIDE_INT) 1 << log;
break;
build_int_2 (log, 0), shift_subtarget,
0);
accum = force_operand (gen_rtx_PLUS (mode, accum, op0),
- add_target ? add_target : accum_target);
+ add_target
+ ? add_target : accum_target);
val_so_far = (val_so_far << log) + 1;
break;
build_int_2 (log, 0), shift_subtarget,
0);
accum = force_operand (gen_rtx_MINUS (mode, accum, op0),
- add_target ? add_target : accum_target);
+ add_target
+ ? add_target : accum_target);
val_so_far = (val_so_far << log) - 1;
break;
tem = expand_shift (LSHIFT_EXPR, mode, accum,
build_int_2 (log, 0), NULL_RTX, 0);
accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
- add_target ? add_target : accum_target);
+ add_target
+ ? add_target : accum_target);
val_so_far += val_so_far << log;
break;
break;
default:
- abort ();;
+ abort ();
}
/* Write a REG_EQUAL note on the last insn so that we can cse
int *post_shift_ptr;
int *lgup_ptr;
{
- unsigned HOST_WIDE_INT mhigh_hi, mhigh_lo;
- unsigned HOST_WIDE_INT mlow_hi, mlow_lo;
+ HOST_WIDE_INT mhigh_hi, mlow_hi;
+ unsigned HOST_WIDE_INT mhigh_lo, mlow_lo;
int lgup, post_shift;
int pow, pow2;
- unsigned HOST_WIDE_INT nh, nl, dummy1, dummy2;
+ unsigned HOST_WIDE_INT nl, dummy1;
+ HOST_WIDE_INT nh, dummy2;
/* lgup = ceil(log2(divisor)); */
lgup = ceil_log2 (d);
/* mlow = 2^(N + lgup)/d */
if (pow >= HOST_BITS_PER_WIDE_INT)
{
- nh = (unsigned HOST_WIDE_INT) 1 << (pow - HOST_BITS_PER_WIDE_INT);
+ nh = (HOST_WIDE_INT) 1 << (pow - HOST_BITS_PER_WIDE_INT);
nl = 0;
}
else
/* mhigh = (2^(N + lgup) + 2^N + lgup - precision)/d */
if (pow2 >= HOST_BITS_PER_WIDE_INT)
- nh |= (unsigned HOST_WIDE_INT) 1 << (pow2 - HOST_BITS_PER_WIDE_INT);
+ nh |= (HOST_WIDE_INT) 1 << (pow2 - HOST_BITS_PER_WIDE_INT);
else
nl |= (unsigned HOST_WIDE_INT) 1 << pow2;
div_and_round_double (TRUNC_DIV_EXPR, 1, nl, nh, d, (HOST_WIDE_INT) 0,
{
mul_highpart_optab = unsignedp ? umul_highpart_optab : smul_highpart_optab;
target = expand_binop (mode, mul_highpart_optab,
- op0, wide_op1, target, unsignedp, OPTAB_DIRECT);
+ op0, op1, target, unsignedp, OPTAB_DIRECT);
if (target)
return target;
}
{
mul_highpart_optab = unsignedp ? smul_highpart_optab : umul_highpart_optab;
target = expand_binop (mode, mul_highpart_optab,
- op0, wide_op1, target, unsignedp, OPTAB_DIRECT);
+ op0, op1, target, unsignedp, OPTAB_DIRECT);
if (target)
/* We used the wrong signedness. Adjust the result. */
return expand_mult_highpart_adjust (mode, target, op0,
insn = get_last_insn ();
if (insn != last
&& (set = single_set (insn)) != 0
- && SET_DEST (set) == quotient)
+ && SET_DEST (set) == quotient
+ && abs_d < ((unsigned HOST_WIDE_INT) 1
+ << (HOST_BITS_PER_WIDE_INT - 1)))
set_unique_reg_note (insn,
REG_EQUAL,
gen_rtx_DIV (compute_mode,
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),
- tquotient);
+ quotient
+ = force_operand (gen_rtx_MINUS (compute_mode,
+ t3, t2),
+ tquotient);
else
- quotient = force_operand (gen_rtx_MINUS (compute_mode, t2, t3),
- tquotient);
+ quotient
+ = force_operand (gen_rtx_MINUS (compute_mode,
+ t2, t3),
+ tquotient);
}
else
{
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);
+ 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);
+ build_int_2 (size - 1, 0),
+ NULL_RTX, 0);
if (d < 0)
- quotient = force_operand (gen_rtx_MINUS (compute_mode, t4, t3),
- tquotient);
+ quotient
+ = force_operand (gen_rtx_MINUS (compute_mode,
+ t4, t3),
+ tquotient);
else
- quotient = force_operand (gen_rtx_MINUS (compute_mode, t3, t4),
- tquotient);
+ quotient
+ = force_operand (gen_rtx_MINUS (compute_mode,
+ t3, t4),
+ tquotient);
}
}
else /* Too wide mode to use tricky code */
rtx last = get_last_insn ();
rtx pattern, comparison;
+ if (unsignedp)
+ code = unsigned_condition (code);
+
/* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */
break;
}
+ /* If we are comparing a double-word integer with zero, we can convert
+ the comparison into one involving a single word. */
+ if (GET_MODE_BITSIZE (mode) == BITS_PER_WORD * 2
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && op1 == const0_rtx)
+ {
+ if (code == EQ || code == NE)
+ {
+ /* Do a logical OR of the two words and compare the result. */
+ rtx op0h = gen_highpart (word_mode, op0);
+ rtx op0l = gen_lowpart (word_mode, op0);
+ rtx op0both = expand_binop (word_mode, ior_optab, op0h, op0l,
+ NULL_RTX, unsignedp, OPTAB_DIRECT);
+ if (op0both != 0)
+ return emit_store_flag (target, code, op0both, op1, word_mode,
+ unsignedp, normalizep);
+ }
+ else if (code == LT || code == GE)
+ /* If testing the sign bit, can just test on high word. */
+ return emit_store_flag (target, code, gen_highpart (word_mode, op0),
+ op1, word_mode, unsignedp, normalizep);
+ }
+
/* From now on, we won't change CODE, so set ICODE now. */
icode = setcc_gen_code[(int) code];
if (icode != CODE_FOR_nothing)
{
+ insn_operand_predicate_fn pred;
+
/* We think we may be able to do this with a scc insn. Emit the
comparison and then the scc insn.
compare_from_rtx may call emit_queue, which would be deleted below
- if the scc insn fails. So call it ourselves before setting LAST. */
+ if the scc insn fails. So call it ourselves before setting LAST.
+ Likewise for do_pending_stack_adjust. */
emit_queue ();
+ do_pending_stack_adjust ();
last = get_last_insn ();
comparison
abort ();
/* Get a reference to the target in the proper mode for this insn. */
- compare_mode = insn_operand_mode[(int) icode][0];
+ compare_mode = insn_data[(int) icode].operand[0].mode;
subtarget = target;
+ pred = insn_data[(int) icode].operand[0].predicate;
if (preserve_subexpressions_p ()
- || ! (*insn_operand_predicate[(int) icode][0]) (subtarget, compare_mode))
+ || ! (*pred) (subtarget, compare_mode))
subtarget = gen_reg_rtx (compare_mode);
pattern = GEN_FCN (icode) (subtarget);
we don't have to do anything. */
if (normalizep == 0 || normalizep == STORE_FLAG_VALUE)
;
- else if (normalizep == - STORE_FLAG_VALUE)
+ /* STORE_FLAG_VALUE might be the most negative number, so write
+ the comparison this way to avoid a compiler-time warning. */
+ else if (- normalizep == STORE_FLAG_VALUE)
op0 = expand_unop (compare_mode, neg_optab, op0, subtarget, 0);
/* We don't want to use STORE_FLAG_VALUE < 0 below since this
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 ();
+ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX, 0,
+ NULL_RTX, label);
- emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
emit_move_insn (target, const0_rtx);
emit_label (label);
static void
do_cmp_and_jump (arg1, arg2, op, mode, label)
rtx arg1, arg2, label;
- enum rtx_code op;
- enum machine_mode mode;
+ 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))
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && ! can_compare_p (op, mode, ccp_jump))
{
rtx label2 = gen_label_rtx ();