Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#include "config.h"
#include "tree.h"
#include "tm_p.h"
#include "flags.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
#include "insn-config.h"
#include "expr.h"
+#include "optabs.h"
#include "real.h"
#include "recog.h"
static void store_fixed_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT, rtx,
- unsigned int));
+ unsigned HOST_WIDE_INT, rtx));
static void store_split_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT, rtx,
- unsigned int));
+ unsigned HOST_WIDE_INT, rtx));
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));
+ rtx, 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));
+ unsigned HOST_WIDE_INT, int));
static void do_cmp_and_jump PARAMS ((rtx, rtx, enum rtx_code,
enum machine_mode, rtx));
#define MAX_BITS_PER_WORD BITS_PER_WORD
#endif
+/* Reduce conditional compilation elsewhere. */
+#ifndef HAVE_insv
+#define HAVE_insv 0
+#define CODE_FOR_insv CODE_FOR_nothing
+#define gen_insv(a,b,c,d) NULL_RTX
+#endif
+#ifndef HAVE_extv
+#define HAVE_extv 0
+#define CODE_FOR_extv CODE_FOR_nothing
+#define gen_extv(a,b,c,d) NULL_RTX
+#endif
+#ifndef HAVE_extzv
+#define HAVE_extzv 0
+#define CODE_FOR_extzv CODE_FOR_nothing
+#define gen_extzv(a,b,c,d) NULL_RTX
+#endif
+
/* 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;
return result;
}
+
+/* Report on the availability of insv/extv/extzv and the desired mode
+ of each of their operands. Returns MAX_MACHINE_MODE if HAVE_foo
+ is false; else the mode of the specified operand. If OPNO is -1,
+ all the caller cares about is whether the insn is available. */
+enum machine_mode
+mode_for_extraction (pattern, opno)
+ enum extraction_pattern pattern;
+ int opno;
+{
+ const struct insn_data *data;
+
+ switch (pattern)
+ {
+ case EP_insv:
+ if (HAVE_insv)
+ {
+ data = &insn_data[CODE_FOR_insv];
+ break;
+ }
+ return MAX_MACHINE_MODE;
+
+ case EP_extv:
+ if (HAVE_extv)
+ {
+ data = &insn_data[CODE_FOR_extv];
+ break;
+ }
+ return MAX_MACHINE_MODE;
+
+ case EP_extzv:
+ if (HAVE_extzv)
+ {
+ data = &insn_data[CODE_FOR_extzv];
+ break;
+ }
+ return MAX_MACHINE_MODE;
+
+ default:
+ abort ();
+ }
+
+ if (opno == -1)
+ return VOIDmode;
+
+ /* Everyone who uses this function used to follow it with
+ if (result == VOIDmode) result = word_mode; */
+ if (data->operand[opno].mode == VOIDmode)
+ return word_mode;
+ return data->operand[opno].mode;
+}
+
\f
/* Generate code to store value from rtx VALUE
into a bit-field within structure STR_RTX
else, we use the mode of operand 3. */
rtx
-store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
+store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, total_size)
rtx str_rtx;
unsigned HOST_WIDE_INT bitsize;
unsigned HOST_WIDE_INT bitnum;
enum machine_mode fieldmode;
rtx value;
- unsigned int align;
HOST_WIDE_INT total_size;
{
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
- unsigned HOST_WIDE_INT insv_bitsize;
- enum machine_mode op_mode;
-
- 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
+ rtx op0 = str_rtx;
- /* It is wrong to have align==0, since every object is aligned at
- least at a bit boundary. This usually means a bug elsewhere. */
- if (align == 0)
- abort ();
+ enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
/* Discount the part of the structure before the desired byte.
We need to know how many bytes are safe to reference after it. */
meaningful at a much higher level; when structures are copied
between memory and regs, the higher-numbered regs
always get higher addresses. */
- offset += SUBREG_WORD (op0);
+ offset += (SUBREG_BYTE (op0) / UNITS_PER_WORD);
/* We used to adjust BITPOS here, but now we do the whole adjustment
right after the loop. */
op0 = SUBREG_REG (op0);
}
- /* 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
- && unit > GET_MODE_BITSIZE (GET_MODE (op0)))
- bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
-
value = protect_from_queue (value, 0);
if (flag_force_mem)
done with a simple store. For targets that support fast unaligned
memory, any naturally sized, unit aligned field can be done directly. */
- if (bitsize == GET_MODE_BITSIZE (fieldmode)
+ if (bitpos == 0
+ && bitsize == GET_MODE_BITSIZE (fieldmode)
&& (GET_CODE (op0) != MEM
? (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
|| GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode))
- : (! SLOW_UNALIGNED_ACCESS (fieldmode, align)
+ : (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0))
|| (offset * BITS_PER_UNIT % bitsize == 0
- && align % GET_MODE_BITSIZE (fieldmode) == 0)))
- && (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0))
+ && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
{
if (GET_MODE (op0) != fieldmode)
{
abort ();
}
if (GET_CODE (op0) == REG)
- op0 = gen_rtx_SUBREG (fieldmode, op0, offset);
+ op0 = gen_rtx_SUBREG (fieldmode, op0,
+ (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ + (offset * UNITS_PER_WORD));
else
- op0 = change_address (op0, fieldmode,
- plus_constant (XEXP (op0, 0), offset));
+ op0 = adjust_address (op0, fieldmode, offset);
}
emit_move_insn (op0, value);
return value;
if (imode != GET_MODE (op0))
{
if (GET_CODE (op0) == MEM)
- op0 = change_address (op0, imode, NULL_RTX);
+ op0 = adjust_address (op0, imode, 0);
else if (imode != BLKmode)
op0 = gen_lowpart (imode, op0);
else
}
}
+ /* 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
+ && unit > GET_MODE_BITSIZE (GET_MODE (op0)))
+ bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
+
/* Storing an lsb-aligned field in a register
can be done with a movestrict instruction. */
}
emit_insn (GEN_FCN (icode)
- (gen_rtx_SUBREG (fieldmode, op0, offset), value));
+ (gen_rtx_SUBREG (fieldmode, op0,
+ (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ + (offset * UNITS_PER_WORD)),
+ value));
return value;
}
if I is 1, use the next to lowest word; and so on. */
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);
+ ? 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),
(GET_MODE (value) == VOIDmode
? fieldmode
: GET_MODE (value))),
- align, total_size);
+ total_size);
}
return value;
}
abort ();
}
op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
- op0, offset);
+ op0, (offset * UNITS_PER_WORD));
}
offset = 0;
}
else
- {
- op0 = protect_from_queue (op0, 1);
- }
+ op0 = protect_from_queue (op0, 1);
/* If VALUE is a floating-point mode, access it as an integer of the
corresponding size. This can occur on a machine with 64 bit registers
/* Now OFFSET is nonzero only if OP0 is memory
and is therefore always measured in bytes. */
-#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. */
- && (insv_bitsize >= bitsize)
+ && (GET_MODE_BITSIZE (op_mode) >= bitsize)
&& ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
- && (bitsize + bitpos > insv_bitsize)))
+ && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode))))
{
int xbitpos = bitpos;
rtx value1;
rtx xop0 = op0;
rtx last = get_last_insn ();
rtx pat;
- enum machine_mode maxmode;
+ enum machine_mode maxmode = mode_for_extraction (EP_insv, 3);
int save_volatile_ok = volatile_ok;
- maxmode = insn_data[(int) CODE_FOR_insv].operand[3].mode;
- if (maxmode == VOIDmode)
- maxmode = word_mode;
-
volatile_ok = 1;
/* If this machine's insv can only insert into a register, copy OP0
if (GET_MODE (op0) == BLKmode
|| GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (maxmode))
bestmode
- = get_best_mode (bitsize, bitnum, align, maxmode,
+ = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0), maxmode,
MEM_VOLATILE_P (op0));
else
bestmode = GET_MODE (op0);
if (bestmode == VOIDmode
- || (SLOW_UNALIGNED_ACCESS (bestmode, align)
- && GET_MODE_BITSIZE (bestmode) > align))
+ || (SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0))
+ && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0)))
goto insv_loses;
- /* Adjust address to point to the containing unit of that mode. */
+ /* Adjust address to point to the containing unit of that mode.
+ Compute offset as multiple of this unit, counting in bytes. */
unit = GET_MODE_BITSIZE (bestmode);
- /* Compute offset as multiple of this unit, counting in bytes. */
offset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
bitpos = bitnum % unit;
- op0 = change_address (op0, bestmode,
- plus_constant (XEXP (op0, 0), offset));
+ op0 = adjust_address (op0, bestmode, offset);
/* 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);
+ total_size);
emit_move_insn (op0, tempreg);
return value;
}
/* Add OFFSET into OP0's address. */
if (GET_CODE (xop0) == MEM)
- xop0 = change_address (xop0, byte_mode,
- plus_constant (XEXP (xop0, 0), offset));
+ xop0 = adjust_address (xop0, byte_mode, offset);
/* If xop0 is a register, we need it in MAXMODE
to make it acceptable to the format of insv. */
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_BYTE (xop0));
if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
if we must narrow it, be sure we do it correctly. */
if (GET_MODE_SIZE (GET_MODE (value)) < GET_MODE_SIZE (maxmode))
- {
- /* 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 = simplify_gen_subreg (maxmode, value1,
+ GET_MODE (value1), 0);
else
value1 = gen_lowpart (maxmode, value1);
}
+ else if (GET_CODE (value) == CONST_INT)
+ value1 = GEN_INT (trunc_int_for_mode (INTVAL (value), maxmode));
else if (!CONSTANT_P (value))
/* Parse phase is supposed to make VALUE's data type
match that of the component reference, which is a type
else
{
delete_insns_since (last);
- store_fixed_bit_field (op0, offset, bitsize, bitpos, value, align);
+ store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
}
}
else
insv_loses:
-#endif
/* Insv is not available; store using shifts and boolean ops. */
- store_fixed_bit_field (op0, offset, bitsize, bitpos, value, align);
+ store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
return value;
}
\f
(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.
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;
+store_fixed_bit_field (op0, offset, bitsize, bitpos, value)
+ rtx op0;
unsigned HOST_WIDE_INT offset, bitsize, bitpos;
- register rtx value;
- unsigned int struct_align;
+ rtx value;
{
- register enum machine_mode mode;
+ enum machine_mode mode;
unsigned int total_bits = BITS_PER_WORD;
rtx subtarget, temp;
int all_zero = 0;
int all_one = 0;
- 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
and a field split across two aligned halfwords within the structure.
/* Special treatment for a bit field split across two registers. */
if (bitsize + bitpos > BITS_PER_WORD)
{
- store_split_bit_field (op0, bitsize, bitpos,
- value, BITS_PER_WORD);
+ store_split_bit_field (op0, bitsize, bitpos, value);
return;
}
}
{
/* Get the proper mode to use for this field. We want a mode that
includes the entire field. If such a mode would be larger than
- a word, we won't be doing the extraction the normal way. */
+ a word, we won't be doing the extraction the normal way.
+ We don't want a mode bigger than the destination. */
+ mode = GET_MODE (op0);
+ if (GET_MODE_BITSIZE (mode) == 0
+ || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode))
+ mode = word_mode;
mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
- struct_align, word_mode,
- GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0));
+ MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
if (mode == VOIDmode)
{
/* The only way this should occur is if the field spans word
boundaries. */
- store_split_bit_field (op0,
- bitsize, bitpos + offset * BITS_PER_UNIT,
- value, struct_align);
+ store_split_bit_field (op0, bitsize, bitpos + offset * BITS_PER_UNIT,
+ value);
return;
}
Then alter OP0 to refer to that word. */
bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
offset -= (offset % (total_bits / BITS_PER_UNIT));
- op0 = change_address (op0, mode,
- plus_constant (XEXP (op0, 0), offset));
+ op0 = adjust_address (op0, mode, offset);
}
mode = GET_MODE (op0);
if (GET_CODE (value) == CONST_INT)
{
- register HOST_WIDE_INT v = INTVAL (value);
+ HOST_WIDE_INT v = INTVAL (value);
if (bitsize < HOST_BITS_PER_WIDE_INT)
v &= ((HOST_WIDE_INT) 1 << bitsize) - 1;
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.
- 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)
+store_split_bit_field (op0, bitsize, bitpos, value)
rtx op0;
unsigned HOST_WIDE_INT bitsize, bitpos;
rtx value;
- unsigned int align;
{
unsigned int unit;
unsigned int bitsdone = 0;
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
unit = BITS_PER_WORD;
else
- unit = MIN (align, BITS_PER_WORD);
+ unit = MIN (MEM_ALIGN (op0), 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
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.
-
- ??? 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))));
+ 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);
}
else
{
>> bitsdone)
& (((HOST_WIDE_INT) 1 << thissize) - 1));
else
- 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))));
+ part = extract_fixed_bit_field (word_mode, value, 0, thissize,
+ bitsdone, NULL_RTX, 1);
}
/* If OP0 is a register, then handle OFFSET here.
the current word starting from the base register. */
if (GET_CODE (op0) == SUBREG)
{
- word = operand_subword_force (SUBREG_REG (op0),
- SUBREG_WORD (op0) + offset,
+ int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
+ word = operand_subword_force (SUBREG_REG (op0), word_offset,
GET_MODE (SUBREG_REG (op0)));
offset = 0;
}
/* OFFSET is in UNITs, and UNIT is in bits.
store_fixed_bit_field wants offset in bytes. */
- store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT,
- thissize, thispos, part, align);
+ store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize,
+ thispos, part);
bitsdone += thissize;
}
}
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.
TOTAL_SIZE is the size in bytes of the containing structure,
or -1 if varying.
rtx
extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
- target, mode, tmode, align, total_size)
+ target, mode, tmode, total_size)
rtx str_rtx;
unsigned HOST_WIDE_INT bitsize;
unsigned HOST_WIDE_INT bitnum;
int unsignedp;
rtx target;
enum machine_mode mode, tmode;
- unsigned int align;
HOST_WIDE_INT total_size;
{
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 op0 = str_rtx;
rtx spec_target = target;
rtx spec_target_subreg = 0;
enum machine_mode int_mode;
-#ifdef HAVE_extv
- unsigned HOST_WIDE_INT extv_bitsize;
- enum machine_mode extv_mode;
-#endif
-#ifdef HAVE_extzv
- unsigned HOST_WIDE_INT extzv_bitsize;
- enum machine_mode extzv_mode;
-#endif
-
-#ifdef HAVE_extv
- 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
- 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
+ enum machine_mode extv_mode = mode_for_extraction (EP_extv, 0);
+ enum machine_mode extzv_mode = mode_for_extraction (EP_extzv, 0);
/* Discount the part of the structure before the desired byte.
We need to know how many bytes are safe to reference after it. */
int outer_size = GET_MODE_BITSIZE (GET_MODE (op0));
int inner_size = GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)));
- offset += SUBREG_WORD (op0);
+ offset += SUBREG_BYTE (op0) / UNITS_PER_WORD;
inner_size = MIN (inner_size, BITS_PER_WORD);
op0 = SUBREG_REG (op0);
}
+ if (GET_CODE (op0) == REG
+ && mode == GET_MODE (op0)
+ && bitnum == 0
+ && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
+ {
+ /* We're trying to extract a full register from itself. */
+ return op0;
+ }
+
/* Make sure we are playing with integral modes. Pun with subregs
if we aren't. */
{
if (imode != GET_MODE (op0))
{
if (GET_CODE (op0) == MEM)
- op0 = change_address (op0, imode, NULL_RTX);
+ op0 = adjust_address (op0, imode, 0);
else if (imode != BLKmode)
op0 = gen_lowpart (imode, op0);
else
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
GET_MODE_BITSIZE (GET_MODE (op0))))
|| (GET_CODE (op0) == MEM
- && (! SLOW_UNALIGNED_ACCESS (mode, align)
+ && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (op0))
|| (offset * BITS_PER_UNIT % bitsize == 0
- && align % bitsize == 0))))
+ && MEM_ALIGN (op0) % 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
abort ();
}
if (GET_CODE (op0) == REG)
- op0 = gen_rtx_SUBREG (mode1, op0, offset);
+ op0 = gen_rtx_SUBREG (mode1, op0,
+ (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ + (offset * UNITS_PER_WORD));
else
- op0 = change_address (op0, mode1,
- plus_constant (XEXP (op0, 0), offset));
+ op0 = adjust_address (op0, mode1, offset);
}
if (mode1 != mode)
return convert_to_mode (tmode, op0, unsignedp);
= 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);
+ word_mode, total_size);
if (target_part == 0)
abort ();
total_words = GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD;
for (i = nwords; i < total_words; i++)
- {
- int wordnum = WORDS_BIG_ENDIAN ? total_words - i - 1 : i;
- rtx target_part = operand_subword (target, wordnum, 1, VOIDmode);
- emit_move_insn (target_part, const0_rtx);
- }
+ emit_move_insn
+ (operand_subword (target,
+ WORDS_BIG_ENDIAN ? total_words - i - 1 : i,
+ 1, VOIDmode),
+ const0_rtx);
}
return target;
}
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);
+ op0, (offset * UNITS_PER_WORD));
}
offset = 0;
}
else
- {
- op0 = protect_from_queue (str_rtx, 1);
- }
+ op0 = protect_from_queue (str_rtx, 1);
/* Now OFFSET is nonzero only for memory operands. */
if (unsignedp)
{
-#ifdef HAVE_extzv
if (HAVE_extzv
- && (extzv_bitsize >= bitsize)
+ && (GET_MODE_BITSIZE (extzv_mode) >= bitsize)
&& ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
- && (bitsize + bitpos > extzv_bitsize)))
+ && (bitsize + bitpos > GET_MODE_BITSIZE (extzv_mode))))
{
unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
rtx xspec_target = spec_target;
rtx xspec_target_subreg = spec_target_subreg;
rtx pat;
- enum machine_mode maxmode;
-
- maxmode = insn_data[(int) CODE_FOR_extzv].operand[0].mode;
- if (maxmode == VOIDmode)
- maxmode = word_mode;
+ enum machine_mode maxmode = mode_for_extraction (EP_extzv, 0);
if (GET_CODE (xop0) == MEM)
{
if (GET_MODE (xop0) == BLKmode
|| (GET_MODE_SIZE (GET_MODE (op0))
> GET_MODE_SIZE (maxmode)))
- bestmode = get_best_mode (bitsize, bitnum, align, maxmode,
+ bestmode = get_best_mode (bitsize, bitnum,
+ MEM_ALIGN (xop0), maxmode,
MEM_VOLATILE_P (xop0));
else
bestmode = GET_MODE (xop0);
if (bestmode == VOIDmode
- || (SLOW_UNALIGNED_ACCESS (bestmode, align)
- && GET_MODE_BITSIZE (bestmode) > align))
+ || (SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (xop0))
+ && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (xop0)))
goto extzv_loses;
/* Compute offset as multiple of this unit,
unit = GET_MODE_BITSIZE (bestmode);
xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
xbitpos = bitnum % unit;
- xop0 = change_address (xop0, bestmode,
- plus_constant (XEXP (xop0, 0),
- xoffset));
+ xop0 = adjust_address (xop0, bestmode, xoffset);
+
/* Fetch it to a register in that size. */
xop0 = force_reg (bestmode, xop0);
}
else
/* Get ref to first byte containing part of the field. */
- xop0 = change_address (xop0, byte_mode,
- plus_constant (XEXP (xop0, 0), xoffset));
+ xop0 = adjust_address (xop0, byte_mode, xoffset);
volatile_ok = save_volatile_ok;
}
{
delete_insns_since (last);
target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
- bitpos, target, 1, align);
+ bitpos, target, 1);
}
}
else
- extzv_loses:
-#endif
- target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
- bitpos, target, 1, align);
+ extzv_loses:
+ target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
+ bitpos, target, 1);
}
else
{
-#ifdef HAVE_extv
if (HAVE_extv
- && (extv_bitsize >= bitsize)
+ && (GET_MODE_BITSIZE (extv_mode) >= bitsize)
&& ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
- && (bitsize + bitpos > extv_bitsize)))
+ && (bitsize + bitpos > GET_MODE_BITSIZE (extv_mode))))
{
int xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
rtx xspec_target = spec_target;
rtx xspec_target_subreg = spec_target_subreg;
rtx pat;
- enum machine_mode maxmode;
-
- maxmode = insn_data[(int) CODE_FOR_extv].operand[0].mode;
- if (maxmode == VOIDmode)
- maxmode = word_mode;
+ enum machine_mode maxmode = mode_for_extraction (EP_extv, 0);
if (GET_CODE (xop0) == MEM)
{
if (GET_MODE (xop0) == BLKmode
|| (GET_MODE_SIZE (GET_MODE (op0))
> GET_MODE_SIZE (maxmode)))
- bestmode = get_best_mode (bitsize, bitnum, align, maxmode,
+ bestmode = get_best_mode (bitsize, bitnum,
+ MEM_ALIGN (xop0), maxmode,
MEM_VOLATILE_P (xop0));
else
bestmode = GET_MODE (xop0);
if (bestmode == VOIDmode
- || (SLOW_UNALIGNED_ACCESS (bestmode, align)
- && GET_MODE_BITSIZE (bestmode) > align))
+ || (SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (xop0))
+ && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (xop0)))
goto extv_loses;
/* Compute offset as multiple of this unit,
unit = GET_MODE_BITSIZE (bestmode);
xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
xbitpos = bitnum % unit;
- xop0 = change_address (xop0, bestmode,
- plus_constant (XEXP (xop0, 0),
- xoffset));
+ xop0 = adjust_address (xop0, bestmode, xoffset);
+
/* Fetch it to a register in that size. */
xop0 = force_reg (bestmode, xop0);
}
else
/* Get ref to first byte containing part of the field. */
- xop0 = change_address (xop0, byte_mode,
- plus_constant (XEXP (xop0, 0), xoffset));
+ xop0 = adjust_address (xop0, byte_mode, xoffset);
}
/* If op0 is a register, we need it in MAXMODE (which is usually
{
delete_insns_since (last);
target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
- bitpos, target, 0, align);
+ bitpos, target, 0);
}
}
else
- extv_loses:
-#endif
- target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
- bitpos, target, 0, align);
+ extv_loses:
+ target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
+ bitpos, target, 0);
}
if (target == spec_target)
return target;
UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value).
If TARGET is nonzero, attempts to store the value there
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. */
+ If TARGET is not used, create a pseudo-reg of mode TMODE for the value. */
static rtx
extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
- target, unsignedp, align)
+ target, unsignedp)
enum machine_mode tmode;
- register rtx op0, target;
+ rtx op0, target;
unsigned HOST_WIDE_INT offset, bitsize, bitpos;
int unsignedp;
- unsigned int align;
{
unsigned int total_bits = BITS_PER_WORD;
enum machine_mode mode;
{
/* Special treatment for a bit field split across two registers. */
if (bitsize + bitpos > BITS_PER_WORD)
- return extract_split_bit_field (op0, bitsize, bitpos,
- unsignedp, align);
+ return extract_split_bit_field (op0, bitsize, bitpos, unsignedp);
}
else
{
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,
- word_mode,
- GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0));
+ mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
+ MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0));
if (mode == VOIDmode)
/* The only way this should occur is if the field spans word
boundaries. */
return extract_split_bit_field (op0, bitsize,
bitpos + offset * BITS_PER_UNIT,
- unsignedp, align);
+ unsignedp);
total_bits = GET_MODE_BITSIZE (mode);
Then alter OP0 to refer to that word. */
bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
offset -= (offset % (total_bits / BITS_PER_UNIT));
- op0 = change_address (op0, mode,
- plus_constant (XEXP (op0, 0), offset));
+ op0 = adjust_address (op0, mode, offset);
}
mode = GET_MODE (op0);
if (BYTES_BIG_ENDIAN)
- {
- /* BITPOS is the distance between our msb and that of OP0.
- Convert it to the distance from the lsb. */
-
- bitpos = total_bits - bitsize - bitpos;
- }
+ /* BITPOS is the distance between our msb and that of OP0.
+ Convert it to the distance from the lsb. */
+ bitpos = total_bits - bitsize - bitpos;
/* Now BITPOS is always the distance between the field's lsb and that of OP0.
We have reduced the big-endian case to the little-endian case. */
if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos))
{
- tree amount = build_int_2 (GET_MODE_BITSIZE (mode) - (bitsize + bitpos), 0);
+ tree amount
+ = build_int_2 (GET_MODE_BITSIZE (mode) - (bitsize + bitpos), 0);
/* Maybe propagate the target for the shift. */
/* But not if we will return the result--could confuse integrate.c. */
rtx subtarget = (target != 0 && GET_CODE (target) == REG
OP0 is the REG, SUBREG or MEM rtx for the first of the two words.
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. This is also the size of the
- memory objects to be used. */
+ UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend. */
static rtx
-extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
+extract_split_bit_field (op0, bitsize, bitpos, unsignedp)
rtx op0;
unsigned HOST_WIDE_INT bitsize, bitpos;
int unsignedp;
- unsigned int align;
{
unsigned int unit;
unsigned int bitsdone = 0;
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
unit = BITS_PER_WORD;
else
- unit = MIN (align, BITS_PER_WORD);
+ unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
while (bitsdone < bitsize)
{
the current word starting from the base register. */
if (GET_CODE (op0) == SUBREG)
{
- word = operand_subword_force (SUBREG_REG (op0),
- SUBREG_WORD (op0) + offset,
+ int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
+ word = operand_subword_force (SUBREG_REG (op0), word_offset,
GET_MODE (SUBREG_REG (op0)));
offset = 0;
}
extract_fixed_bit_field wants offset in bytes. */
part = extract_fixed_bit_field (word_mode, word,
offset * unit / BITS_PER_UNIT,
- thissize, thispos, 0, 1, align);
+ thissize, thispos, 0, 1);
bitsdone += thissize;
/* Shift this part into place for the result. */
rtx
expand_shift (code, mode, shifted, amount, target, unsignedp)
enum tree_code code;
- register enum machine_mode mode;
+ enum machine_mode mode;
rtx shifted;
tree amount;
- register rtx target;
+ rtx target;
int unsignedp;
{
- register rtx op1, temp = 0;
- register int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR);
- register int rotate = (code == LROTATE_EXPR || code == RROTATE_EXPR);
+ rtx op1, temp = 0;
+ int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR);
+ int rotate = (code == LROTATE_EXPR || code == RROTATE_EXPR);
int try;
/* Previously detected shift-counts computed by NEGATE_EXPR
op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
% GET_MODE_BITSIZE (mode));
else if (GET_CODE (op1) == SUBREG
- && SUBREG_WORD (op1) == 0)
+ && SUBREG_BYTE (op1) == 0)
op1 = SUBREG_REG (op1);
}
#endif
that is in range, try a rotate in the opposite direction. */
if (temp == 0 && GET_CODE (op1) == CONST_INT
- && INTVAL (op1) > 0 && INTVAL (op1) < GET_MODE_BITSIZE (mode))
+ && INTVAL (op1) > 0
+ && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
temp = expand_binop (mode,
left ? rotr_optab : rotl_optab,
shifted,
rtx
expand_mult (mode, op0, op1, target, unsignedp)
enum machine_mode mode;
- register rtx op0, op1, target;
+ rtx op0, op1, target;
int unsignedp;
{
rtx const_op1 = op1;
int mult_cost;
enum {basic_variant, negate_variant, add_variant} variant = basic_variant;
+ /* op0 must be register to make mult_cost match the precomputed
+ shiftadd_cost array. */
+ op0 = force_reg (mode, op0);
+
/* Try to do the computation three ways: multiply by the negative of OP1
and then negate, do the multiplication directly, or do multiplication
by OP1 - 1. */
rtx
expand_mult_highpart_adjust (mode, adj_operand, op0, op1, target, unsignedp)
enum machine_mode mode;
- register rtx adj_operand, op0, op1, target;
+ rtx adj_operand, op0, op1, target;
int unsignedp;
{
rtx tem;
rtx
expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
enum machine_mode mode;
- register rtx op0, target;
+ rtx op0, target;
unsigned HOST_WIDE_INT cnst1;
int unsignedp;
int max_cost;
if (size > HOST_BITS_PER_WIDE_INT)
abort ();
- op1 = GEN_INT (cnst1);
+ op1 = GEN_INT (trunc_int_for_mode (cnst1, mode));
if (GET_MODE_BITSIZE (wider_mode) <= HOST_BITS_PER_INT)
wide_op1 = op1;
int rem_flag;
enum tree_code code;
enum machine_mode mode;
- register rtx op0, op1, target;
+ rtx op0, op1, target;
int unsignedp;
{
enum machine_mode compute_mode;
- register rtx tquotient;
+ rtx tquotient;
rtx quotient = 0, remainder = 0;
rtx last;
int size;
if (rem_flag && d < 0)
{
d = abs_d;
- op1 = GEN_INT (abs_d);
+ op1 = GEN_INT (trunc_int_for_mode (abs_d, compute_mode));
}
if (d == 1)
t1 = copy_to_mode_reg (compute_mode, op0);
do_cmp_and_jump (t1, const0_rtx, GE,
compute_mode, label);
- expand_inc (t1, GEN_INT (abs_d - 1));
+ expand_inc (t1, GEN_INT (trunc_int_for_mode
+ (abs_d - 1, compute_mode)));
emit_label (label);
quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
build_int_2 (lgup, 0),
REG_EQUAL,
gen_rtx_DIV (compute_mode,
op0,
- GEN_INT (abs_d)));
+ GEN_INT
+ (trunc_int_for_mode
+ (abs_d,
+ compute_mode))));
quotient = expand_unop (compute_mode, neg_optab,
quotient, quotient, 0);
ml = invert_mod2n (d >> pre_shift, size);
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_2 (pre_shift, 0), NULL_RTX, unsignedp);
- quotient = expand_mult (compute_mode, t1, GEN_INT (ml), NULL_RTX,
- 0);
+ quotient = expand_mult (compute_mode, t1,
+ GEN_INT (trunc_int_for_mode
+ (ml, compute_mode)),
+ NULL_RTX, 0);
insn = get_last_insn ();
set_unique_reg_note (insn,
/* Return a tree node with data type TYPE, describing the value of X.
Usually this is an RTL_EXPR, if there is no obvious better choice.
X may be an expression, however we only support those expressions
- generated by loop.c. */
+ generated by loop.c. */
tree
make_tree (type, x)
/* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */
- if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
- || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+ if (swap_commutative_operands_p (op0, op1))
{
tem = op0;
op0 = op1;
last = get_last_insn ();
comparison
- = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX, 0);
+ = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX);
if (GET_CODE (comparison) == CONST_INT)
return (comparison == const0_rtx ? const0_rtx
: normalizep == 1 ? const1_rtx
/* Note that ABS doesn't yield a positive number for INT_MIN, but
that is compensated by the subsequent overflow when subtracting
- one / negating. */
+ one / negating. */
if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
tem = expand_unop (mode, abs_optab, op0, subtarget, 1);
emit_move_insn (target, const1_rtx);
label = gen_label_rtx ();
- do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX, 0,
+ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX,
NULL_RTX, label);
emit_move_insn (target, const0_rtx);
emit_label (label2);
}
else
- {
- emit_cmp_and_jump_insns (arg1, arg2, op, NULL_RTX, mode, 0, 0, label);
- }
+ emit_cmp_and_jump_insns (arg1, arg2, op, NULL_RTX, mode, 0, label);
}