/* Convert tree expression to rtl instructions, for GNU compiler.
- Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
- Free Software Foundation, Inc.
+ Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "reload.h"
#include "output.h"
#include "typeclass.h"
-#include "defaults.h"
#include "toplev.h"
#include "ggc.h"
#include "intl.h"
#define CASE_VECTOR_PC_RELATIVE 0
#endif
+/* Hook called by safe_from_p for language-specific tree codes. It is
+ up to the language front-end to install a hook if it has any such
+ codes that safe_from_p needs to know about. Since same_from_p will
+ recursively explore the TREE_OPERANDs of an expression, this hook
+ should not reexamine those pieces. This routine may recursively
+ call safe_from_p; it should always pass `0' as the TOP_P
+ parameter. */
+int (*lang_safe_from_p) PARAMS ((rtx, tree));
+
/* If this is nonzero, we do not bother generating VOLATILE
around volatile memory references, and we are willing to
output indirect addresses. If cse is to follow, we reject
the same indirect address eventually. */
int cse_not_expected;
-/* Nonzero to generate code for all the subroutines within an
- expression before generating the upper levels of the expression.
- Nowadays this is never zero. */
-int do_preexpand_calls = 1;
-
/* Don't check memory usage, since code is being emitted to check a memory
usage. Used when current_function_check_memory_usage is true, to avoid
infinite recursion. */
int reverse;
};
-/* This structure is used by clear_by_pieces to describe the clear to
+/* This structure is used by store_by_pieces to describe the clear to
be performed. */
-struct clear_by_pieces
+struct store_by_pieces
{
rtx to;
rtx to_addr;
int explicit_inc_to;
unsigned HOST_WIDE_INT len;
HOST_WIDE_INT offset;
+ rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+ PTR constfundata;
int reverse;
};
unsigned int));
static void move_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
struct move_by_pieces *));
+static rtx clear_by_pieces_1 PARAMS ((PTR, HOST_WIDE_INT,
+ enum machine_mode));
static void clear_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
unsigned int));
-static void clear_by_pieces_1 PARAMS ((rtx (*) (rtx, ...),
+static void store_by_pieces_1 PARAMS ((struct store_by_pieces *,
+ unsigned int));
+static void store_by_pieces_2 PARAMS ((rtx (*) (rtx, ...),
enum machine_mode,
- struct clear_by_pieces *));
+ struct store_by_pieces *));
static rtx get_subtarget PARAMS ((rtx));
static int is_zeros_p PARAMS ((tree));
static int mostly_zeros_p PARAMS ((tree));
static void store_constructor_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
HOST_WIDE_INT, enum machine_mode,
- tree, tree, unsigned int, int));
+ tree, tree, unsigned int, int,
+ int));
static void store_constructor PARAMS ((tree, rtx, unsigned int, int,
HOST_WIDE_INT));
static rtx store_field PARAMS ((rtx, HOST_WIDE_INT,
get_memory_usage_from_modifier PARAMS ((enum expand_modifier));
static tree save_noncopied_parts PARAMS ((tree, tree));
static tree init_noncopied_parts PARAMS ((tree, tree));
-static int safe_from_p PARAMS ((rtx, tree, int));
static int fixed_type_p PARAMS ((tree));
static rtx var_rtx PARAMS ((tree));
-static int readonly_fields_p PARAMS ((tree));
static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *));
static rtx expand_increment PARAMS ((tree, int, int));
-static void preexpand_calls PARAMS ((tree));
static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
static void do_jump_by_parts_equality PARAMS ((tree, rtx, rtx));
static void do_compare_and_jump PARAMS ((tree, enum rtx_code, enum rtx_code,
to perform a structure copy. */
#ifndef MOVE_BY_PIECES_P
#define MOVE_BY_PIECES_P(SIZE, ALIGN) \
- (move_by_pieces_ninsns (SIZE, ALIGN) < MOVE_RATIO)
+ (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) MOVE_RATIO)
#endif
/* This array records the insn_code of insns to perform block moves. */
enum machine_mode mode;
int num_clobbers;
rtx mem, mem1;
- char *free_point;
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);
-
/* Try indexing by frame ptr and try by stack ptr.
It is known that on the Convex the stack ptr isn't a valid index.
With luck, one or the other is valid on any machine. */
}
end_sequence ();
- obfree (free_point);
}
/* This is run at the start of compiling a function. */
if (to_real)
{
- rtx value;
+ rtx value, insns;
if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
{
/* This conversion is not implemented yet. */
abort ();
- value = emit_library_call_value (libcall, NULL_RTX, 1, to_mode,
+ start_sequence ();
+ value = emit_library_call_value (libcall, NULL_RTX, LCT_CONST, to_mode,
1, from, from_mode);
- emit_move_insn (to, value);
+ insns = get_insns ();
+ end_sequence ();
+ emit_libcall_block (insns, to, value, gen_rtx_FLOAT_TRUNCATE (to_mode,
+ from));
return;
}
else
{
#ifdef HAVE_extendpsisi2
- if (HAVE_extendpsisi2)
+ if (! unsignedp && HAVE_extendpsisi2)
{
emit_unop_insn (CODE_FOR_extendpsisi2, to, from, UNKNOWN);
return;
}
#endif /* HAVE_extendpsisi2 */
+#ifdef HAVE_zero_extendpsisi2
+ if (unsignedp && HAVE_zero_extendpsisi2)
+ {
+ emit_unop_insn (CODE_FOR_zero_extendpsisi2, to, from, UNKNOWN);
+ return;
+ }
+#endif /* HAVE_zero_extendpsisi2 */
abort ();
}
}
max_size = GET_MODE_SIZE (mode);
}
+ if (l)
+ abort ();
return n_insns;
}
/* This was copied from except.c, I don't know if all this is
necessary in this context or not. */
fn = get_identifier ("memcpy");
- push_obstacks_nochange ();
- end_temporary_allocation ();
fntype = build_pointer_type (void_type_node);
fntype = build_function_type (fntype, NULL_TREE);
fn = build_decl (FUNCTION_DECL, fn, fntype);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
- make_decl_rtl (fn, NULL_PTR, 1);
+ make_decl_rtl (fn, NULL_PTR);
assemble_external (fn);
- pop_obstacks ();
}
/* We need to make an argument list for the function call.
retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
#else
- emit_library_call (bcopy_libfunc, 0,
+ emit_library_call (bcopy_libfunc, LCT_NORMAL,
VOIDmode, 3, y, Pmode, x, Pmode,
convert_to_mode (TYPE_MODE (integer_type_node), size,
TREE_UNSIGNED (integer_type_node)),
#endif
enum machine_mode mode;
+ if (nregs == 0)
+ return;
+
/* If SIZE is that of a mode no bigger than a word, just use that
mode's store operation. */
if (size <= UNITS_PER_WORD
int shift = 0;
/* Handle trailing fragments that run over the size of the struct. */
- if (ssize >= 0 && bytepos + bytelen > ssize)
+ if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
bytelen = ssize - bytepos;
if (bytepos == 0
&& bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
tmps[i] = XEXP (src, 0);
- else if (bytepos == GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
+ else if (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
&& bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1))))
tmps[i] = XEXP (src, 1);
else
unsigned int bytelen = GET_MODE_SIZE (mode);
/* Handle trailing fragments that run over the size of the struct. */
- if (ssize >= 0 && bytepos + bytelen > ssize)
+ if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
if (BYTES_BIG_ENDIAN)
{
if (tgtblk == 0)
{
- tgtblk = assign_stack_temp (BLKmode, bytes, 0);
- MEM_SET_IN_STRUCT_P (tgtblk, AGGREGATE_TYPE_P (type));
+ tgtblk = assign_temp (build_qualified_type (type,
+ (TYPE_QUALS (type)
+ | TYPE_QUAL_CONST)),
+ 0, 1, 1);
preserve_temp_slots (tgtblk);
}
}
}
\f
+
+int
+can_store_by_pieces (len, constfun, constfundata, align)
+ unsigned HOST_WIDE_INT len;
+ rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+ PTR constfundata;
+ unsigned int align;
+{
+ unsigned HOST_WIDE_INT max_size, l;
+ HOST_WIDE_INT offset = 0;
+ enum machine_mode mode, tmode;
+ enum insn_code icode;
+ int reverse;
+ rtx cst;
+
+ if (! MOVE_BY_PIECES_P (len, align))
+ return 0;
+
+ if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
+ || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
+ align = MOVE_MAX * BITS_PER_UNIT;
+
+ /* We would first store what we can in the largest integer mode, then go to
+ successively smaller modes. */
+
+ for (reverse = 0;
+ reverse <= (HAVE_PRE_DECREMENT || HAVE_POST_DECREMENT);
+ reverse++)
+ {
+ l = len;
+ mode = VOIDmode;
+ max_size = MOVE_MAX_PIECES + 1;
+ while (max_size > 1)
+ {
+ for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
+ if (GET_MODE_SIZE (tmode) < max_size)
+ mode = tmode;
+
+ if (mode == VOIDmode)
+ break;
+
+ icode = mov_optab->handlers[(int) mode].insn_code;
+ if (icode != CODE_FOR_nothing
+ && align >= GET_MODE_ALIGNMENT (mode))
+ {
+ unsigned int size = GET_MODE_SIZE (mode);
+
+ while (l >= size)
+ {
+ if (reverse)
+ offset -= size;
+
+ cst = (*constfun) (constfundata, offset, mode);
+ if (!LEGITIMATE_CONSTANT_P (cst))
+ return 0;
+
+ if (!reverse)
+ offset += size;
+
+ l -= size;
+ }
+ }
+
+ max_size = GET_MODE_SIZE (mode);
+ }
+
+ /* The code above should have handled everything. */
+ if (l != 0)
+ abort ();
+ }
+
+ return 1;
+}
+
+/* Generate several move instructions to store LEN bytes generated by
+ CONSTFUN to block TO. (A MEM rtx with BLKmode). CONSTFUNDATA is a
+ pointer which will be passed as argument in every CONSTFUN call.
+ ALIGN is maximum alignment we can assume. */
+
+void
+store_by_pieces (to, len, constfun, constfundata, align)
+ rtx to;
+ unsigned HOST_WIDE_INT len;
+ rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+ PTR constfundata;
+ unsigned int align;
+{
+ struct store_by_pieces data;
+
+ if (! MOVE_BY_PIECES_P (len, align))
+ abort ();
+ to = protect_from_queue (to, 1);
+ data.constfun = constfun;
+ data.constfundata = constfundata;
+ data.len = len;
+ data.to = to;
+ store_by_pieces_1 (&data, align);
+}
+
/* Generate several move instructions to clear LEN bytes of block TO. (A MEM
rtx with BLKmode). The caller must pass TO through protect_from_queue
before calling. ALIGN is maximum alignment we can assume. */
unsigned HOST_WIDE_INT len;
unsigned int align;
{
- struct clear_by_pieces data;
- rtx to_addr = XEXP (to, 0);
+ struct store_by_pieces data;
+
+ data.constfun = clear_by_pieces_1;
+ data.constfundata = NULL_PTR;
+ data.len = len;
+ data.to = to;
+ store_by_pieces_1 (&data, align);
+}
+
+/* Callback routine for clear_by_pieces.
+ Return const0_rtx unconditionally. */
+
+static rtx
+clear_by_pieces_1 (data, offset, mode)
+ PTR data ATTRIBUTE_UNUSED;
+ HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return const0_rtx;
+}
+
+/* Subroutine of clear_by_pieces and store_by_pieces.
+ Generate several move instructions to store LEN bytes of block TO. (A MEM
+ rtx with BLKmode). The caller must pass TO through protect_from_queue
+ before calling. ALIGN is maximum alignment we can assume. */
+
+static void
+store_by_pieces_1 (data, align)
+ struct store_by_pieces *data;
+ unsigned int align;
+{
+ rtx to_addr = XEXP (data->to, 0);
unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode;
- data.offset = 0;
- data.to_addr = to_addr;
- data.to = to;
- data.autinc_to
+ data->offset = 0;
+ data->to_addr = to_addr;
+ data->autinc_to
= (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
|| GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
- data.explicit_inc_to = 0;
- data.reverse
+ data->explicit_inc_to = 0;
+ data->reverse
= (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
- if (data.reverse)
- data.offset = len;
- data.len = len;
+ if (data->reverse)
+ data->offset = data->len;
- /* If copying requires more than two move insns,
+ /* If storing requires more than two move insns,
copy addresses to registers (to make displacements shorter)
and use post-increment if available. */
- if (!data.autinc_to
- && move_by_pieces_ninsns (len, align) > 2)
+ if (!data->autinc_to
+ && move_by_pieces_ninsns (data->len, align) > 2)
{
/* Determine the main mode we'll be using. */
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
- if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to)
+ if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
{
- data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
- data.autinc_to = 1;
- data.explicit_inc_to = -1;
+ data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len));
+ data->autinc_to = 1;
+ data->explicit_inc_to = -1;
}
- if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse
- && ! data.autinc_to)
+ if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse
+ && ! data->autinc_to)
{
- data.to_addr = copy_addr_to_reg (to_addr);
- data.autinc_to = 1;
- data.explicit_inc_to = 1;
+ data->to_addr = copy_addr_to_reg (to_addr);
+ data->autinc_to = 1;
+ data->explicit_inc_to = 1;
}
- if ( !data.autinc_to && CONSTANT_P (to_addr))
- data.to_addr = copy_addr_to_reg (to_addr);
+ if ( !data->autinc_to && CONSTANT_P (to_addr))
+ data->to_addr = copy_addr_to_reg (to_addr);
}
if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
|| align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
align = MOVE_MAX * BITS_PER_UNIT;
- /* First move what we can in the largest integer mode, then go to
+ /* First store what we can in the largest integer mode, then go to
successively smaller modes. */
while (max_size > 1)
icode = mov_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
- clear_by_pieces_1 (GEN_FCN (icode), mode, &data);
+ store_by_pieces_2 (GEN_FCN (icode), mode, data);
max_size = GET_MODE_SIZE (mode);
}
/* The code above should have handled everything. */
- if (data.len != 0)
+ if (data->len != 0)
abort ();
}
-/* Subroutine of clear_by_pieces. Clear as many bytes as appropriate
+/* Subroutine of store_by_pieces_1. Store as many bytes as appropriate
with move instructions for mode MODE. GENFUN is the gen_... function
to make a move insn for that mode. DATA has all the other info. */
static void
-clear_by_pieces_1 (genfun, mode, data)
+store_by_pieces_2 (genfun, mode, data)
rtx (*genfun) PARAMS ((rtx, ...));
enum machine_mode mode;
- struct clear_by_pieces *data;
+ struct store_by_pieces *data;
{
unsigned int size = GET_MODE_SIZE (mode);
- rtx to1;
+ rtx to1, cst;
while (data->len >= size)
{
plus_constant (data->to_addr, data->offset));
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
- emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
+ emit_insn (gen_add2_insn (data->to_addr,
+ GEN_INT (-(HOST_WIDE_INT) size)));
- emit_insn ((*genfun) (to1, const0_rtx));
+ cst = (*data->constfun) (data->constfundata, data->offset, mode);
+ emit_insn ((*genfun) (to1, cst));
if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
#endif
rtx retval = 0;
- if (GET_MODE (object) == BLKmode)
+ /* If OBJECT is not BLKmode and SIZE is the same size as its mode,
+ just move a zero. Otherwise, do this a piece at a time. */
+ if (GET_MODE (object) != BLKmode
+ && GET_CODE (size) == CONST_INT
+ && GET_MODE_SIZE (GET_MODE (object)) == (unsigned int) INTVAL (size))
+ emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
+ else
{
object = protect_from_queue (object, 1);
size = protect_from_queue (size, 0);
/* This was copied from except.c, I don't know if all this is
necessary in this context or not. */
fn = get_identifier ("memset");
- push_obstacks_nochange ();
- end_temporary_allocation ();
fntype = build_pointer_type (void_type_node);
fntype = build_function_type (fntype, NULL_TREE);
fn = build_decl (FUNCTION_DECL, fn, fntype);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
- make_decl_rtl (fn, NULL_PTR, 1);
+ make_decl_rtl (fn, NULL_PTR);
assemble_external (fn);
- pop_obstacks ();
}
/* We need to make an argument list for the function call.
retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
#else
- emit_library_call (bzero_libfunc, 0,
+ emit_library_call (bzero_libfunc, LCT_NORMAL,
VOIDmode, 2, object, Pmode, size,
TYPE_MODE (integer_type_node));
#endif
}
}
- else
- emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
return retval;
}
rtx x, y;
{
enum machine_mode mode = GET_MODE (x);
+ rtx y_cst = NULL_RTX;
+ rtx last_insn;
x = protect_from_queue (x, 1);
y = protect_from_queue (y, 0);
if (GET_CODE (y) == CONSTANT_P_RTX)
;
else if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))
- y = force_const_mem (mode, y);
+ {
+ y_cst = y;
+ y = force_const_mem (mode, y);
+ }
/* If X or Y are memory references, verify that their addresses are valid
for the machine. */
if (mode == BLKmode)
abort ();
- return emit_move_insn_1 (x, y);
+ last_insn = emit_move_insn_1 (x, y);
+
+ if (y_cst && GET_CODE (x) == REG)
+ REG_NOTES (last_insn)
+ = gen_rtx_EXPR_LIST (REG_EQUAL, y_cst, REG_NOTES (last_insn));
+
+ return last_insn;
}
/* Low level part of emit_move_insn.
enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
? MODE_FLOAT : MODE_INT);
- enum machine_mode reg_mode =
- mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
+ enum machine_mode reg_mode
+ = mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
if (reg_mode != BLKmode)
{
rtx mem = assign_stack_temp (reg_mode,
GET_MODE_SIZE (mode), 0);
-
rtx cmem = change_address (mem, mode, NULL_RTX);
- cfun->cannot_inline = N_("function using short complex types cannot be inline");
+ cfun->cannot_inline
+ = N_("function using short complex types cannot be inline");
if (packed_dest_p)
{
in_check_memory_usage = 1;
temp = get_push_address (INTVAL (size) - used);
if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
- emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
- temp, Pmode,
- XEXP (xinner, 0), Pmode,
+ emit_library_call (chkr_copy_bitmap_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3, temp,
+ Pmode, XEXP (xinner, 0), Pmode,
GEN_INT (INTVAL (size) - used),
TYPE_MODE (sizetype));
else
- emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
- temp, Pmode,
- GEN_INT (INTVAL (size) - used),
+ emit_library_call (chkr_set_right_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3, temp,
+ Pmode, GEN_INT (INTVAL (size) - used),
TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
TYPE_MODE (integer_type_node));
in_check_memory_usage = 1;
target = copy_to_reg (temp);
if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
- emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+ emit_library_call (chkr_copy_bitmap_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
target, Pmode,
XEXP (xinner, 0), Pmode,
size, TYPE_MODE (sizetype));
else
- emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ emit_library_call (chkr_set_right_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
target, Pmode,
size, TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
to force it to pop the bcopy-arguments right away. */
NO_DEFER_POP;
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memcpy_libfunc, 0,
+ emit_library_call (memcpy_libfunc, LCT_NORMAL,
VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype),
size, TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
#else
- emit_library_call (bcopy_libfunc, 0,
+ emit_library_call (bcopy_libfunc, LCT_NORMAL,
VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode,
convert_to_mode (TYPE_MODE (integer_type_node),
size,
target = get_push_address (GET_MODE_SIZE (mode));
if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
- emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
- target, Pmode,
- XEXP (x, 0), Pmode,
+ emit_library_call (chkr_copy_bitmap_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3, target,
+ Pmode, XEXP (x, 0), Pmode,
GEN_INT (GET_MODE_SIZE (mode)),
TYPE_MODE (sizetype));
else
- emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
- target, Pmode,
- GEN_INT (GET_MODE_SIZE (mode)),
+ emit_library_call (chkr_set_right_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3, target,
+ Pmode, GEN_INT (GET_MODE_SIZE (mode)),
TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
TYPE_MODE (integer_type_node));
/* Check the access right of the pointer. */
in_check_memory_usage = 1;
if (size)
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
- to_addr, Pmode,
+ emit_library_call (chkr_check_addr_libfunc, LCT_CONST_MAKE_BLOCK,
+ VOIDmode, 3, to_addr, Pmode,
GEN_INT (size), TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_WO),
TYPE_MODE (integer_type_node));
/* Copy the rights of the bitmap. */
if (current_function_check_memory_usage)
- emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
- XEXP (to_rtx, 0), Pmode,
+ emit_library_call (chkr_copy_bitmap_libfunc, LCT_CONST_MAKE_BLOCK,
+ VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
XEXP (from_rtx, 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype),
size, TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memcpy_libfunc, 0,
+ emit_library_call (memcpy_libfunc, LCT_NORMAL,
VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
XEXP (from_rtx, 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype),
size, TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
#else
- emit_library_call (bcopy_libfunc, 0,
+ emit_library_call (bcopy_libfunc, LCT_NORMAL,
VOIDmode, 3, XEXP (from_rtx, 0), Pmode,
XEXP (to_rtx, 0), Pmode,
convert_to_mode (TYPE_MODE (integer_type_node),
{
in_check_memory_usage = 1;
if (GET_CODE (temp) == MEM)
- emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
- XEXP (target, 0), Pmode,
+ emit_library_call (chkr_copy_bitmap_libfunc, LCT_CONST_MAKE_BLOCK,
+ VOIDmode, 3, XEXP (target, 0), Pmode,
XEXP (temp, 0), Pmode,
expr_size (exp), TYPE_MODE (sizetype));
else
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
- XEXP (target, 0), Pmode,
+ emit_library_call (chkr_check_addr_libfunc, LCT_CONST_MAKE_BLOCK,
+ VOIDmode, 3, XEXP (target, 0), Pmode,
expr_size (exp), TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_WO),
TYPE_MODE (integer_type_node));
{
addr = plus_constant (addr, TREE_STRING_LENGTH (exp));
size = plus_constant (size, -TREE_STRING_LENGTH (exp));
- align = MIN (align, (BITS_PER_UNIT
- * (INTVAL (copy_size_rtx)
- & - INTVAL (copy_size_rtx))));
+ align = MIN (align,
+ (unsigned int) (BITS_PER_UNIT
+ * (INTVAL (copy_size_rtx)
+ & - INTVAL (copy_size_rtx))));
}
else
{
/* Be sure we can write on ADDR. */
in_check_memory_usage = 1;
if (current_function_check_memory_usage)
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ emit_library_call (chkr_check_addr_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
addr, Pmode,
size, TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_WO),
TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
TYPE is the type of the CONSTRUCTOR, not the element type.
ALIGN and CLEARED are as for store_constructor.
+ ALIAS_SET is the alias set to use for any stores.
This provides a recursive shortcut back to store_constructor when it isn't
necessary to go through store_field. This is so that we can pass through
static void
store_constructor_field (target, bitsize, bitpos,
- mode, exp, type, align, cleared)
+ mode, exp, type, align, cleared, alias_set)
rtx target;
unsigned HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
tree exp, type;
unsigned int align;
int cleared;
+ int alias_set;
{
if (TREE_CODE (exp) == CONSTRUCTOR
&& bitpos % BITS_PER_UNIT == 0
? BLKmode : VOIDmode,
plus_constant (XEXP (target, 0),
bitpos / BITS_PER_UNIT));
+
+
+ /* Show the alignment may no longer be what it was and update the alias
+ set, if required. */
+ if (bitpos != 0)
+ align = MIN (align, (unsigned int) bitpos & - bitpos);
+ if (GET_CODE (target) == MEM)
+ MEM_ALIAS_SET (target) = alias_set;
+
store_constructor (exp, target, align, cleared, bitsize / BITS_PER_UNIT);
}
else
store_field (target, bitsize, bitpos, mode, exp, VOIDmode, 0, align,
- int_size_in_bytes (type), 0);
+ int_size_in_bytes (type), alias_set);
}
/* Store the value of constructor EXP into the rtx TARGET.
/* If the constructor has fewer fields than the structure
or if we are initializing the structure to mostly zeros,
- clear the whole structure first. */
+ clear the whole structure first. Don't do this is TARGET is
+ register whose mode size isn't equal to SIZE since clear_storage
+ can't handle this case. */
else if (size > 0
&& ((list_length (CONSTRUCTOR_ELTS (exp))
!= fields_length (type))
- || mostly_zeros_p (exp)))
+ || mostly_zeros_p (exp))
+ && (GET_CODE (target) != REG
+ || (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target)) == size))
{
if (! cleared)
clear_storage (target, GEN_INT (size), align);
}
#endif
store_constructor_field (to_rtx, bitsize, bitpos, mode,
- TREE_VALUE (elt), type, align, cleared);
+ TREE_VALUE (elt), type, align, cleared,
+ (DECL_NONADDRESSABLE_P (field)
+ && GET_CODE (to_rtx) == MEM)
+ ? MEM_ALIAS_SET (to_rtx)
+ : get_alias_set (TREE_TYPE (field)));
}
}
else if (TREE_CODE (type) == ARRAY_TYPE)
register int i;
int need_to_clear;
tree domain = TYPE_DOMAIN (type);
- HOST_WIDE_INT minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
- HOST_WIDE_INT maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
tree elttype = TREE_TYPE (type);
+ int const_bounds_p = (host_integerp (TYPE_MIN_VALUE (domain), 0)
+ && host_integerp (TYPE_MAX_VALUE (domain), 0));
+ HOST_WIDE_INT minelt;
+ HOST_WIDE_INT maxelt;
+
+ /* If we have constant bounds for the range of the type, get them. */
+ if (const_bounds_p)
+ {
+ minelt = tree_low_cst (TYPE_MIN_VALUE (domain), 0);
+ maxelt = tree_low_cst (TYPE_MAX_VALUE (domain), 0);
+ }
/* If the constructor has fewer elements than the array,
clear the whole array first. Similarly if this is
else
{
HOST_WIDE_INT count = 0, zero_count = 0;
- need_to_clear = 0;
+ need_to_clear = ! const_bounds_p;
+
/* This loop is a more accurate version of the loop in
mostly_zeros_p (it handles RANGE_EXPR in an index).
It is also needed to check for missing elements. */
for (elt = CONSTRUCTOR_ELTS (exp);
- elt != NULL_TREE;
+ elt != NULL_TREE && ! need_to_clear;
elt = TREE_CHAIN (elt))
{
tree index = TREE_PURPOSE (elt);
}
else
this_node_count = 1;
+
count += this_node_count;
if (mostly_zeros_p (TREE_VALUE (elt)))
zero_count += this_node_count;
}
+
/* Clear the entire array first if there are any missing elements,
or if the incidence of zero elements is >= 75%. */
- if (count < maxelt - minelt + 1
- || 4 * zero_count >= 3 * count)
+ if (! need_to_clear
+ && (count < maxelt - minelt + 1 || 4 * zero_count >= 3 * count))
need_to_clear = 1;
}
+
if (need_to_clear && size > 0)
{
if (! cleared)
tree position;
/* If the range is constant and "small", unroll the loop. */
- if (host_integerp (lo_index, 0)
+ if (const_bounds_p
+ && host_integerp (lo_index, 0)
&& host_integerp (hi_index, 0)
&& (lo = tree_low_cst (lo_index, 0),
hi = tree_low_cst (hi_index, 0),
for (; lo <= hi; lo++)
{
bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
- store_constructor_field (target, bitsize, bitpos, mode,
- value, type, align, cleared);
+ store_constructor_field
+ (target, bitsize, bitpos, mode, value, type, align,
+ cleared,
+ TYPE_NONALIASED_COMPONENT (type)
+ ? MEM_ALIAS_SET (target) : get_alias_set (elttype));
}
}
else
bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
store_constructor_field (target, bitsize, bitpos, mode, value,
- type, align, cleared);
+ type, align, cleared,
+ TYPE_NONALIASED_COMPONENT (type)
+ && GET_CODE (target) == MEM
+ ? MEM_ALIAS_SET (target) :
+ get_alias_set (elttype));
+
}
}
}
if (REG_P (target))
{
- targetx = assign_stack_temp (GET_MODE (target),
- GET_MODE_SIZE (GET_MODE (target)),
- 0);
+ targetx
+ = assign_temp
+ ((build_qualified_type (type_for_mode (GET_MODE (target), 0),
+ TYPE_QUAL_CONST)),
+ 0, 1, 1);
emit_move_insn (targetx, target);
}
&& (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
&& (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
{
- emit_library_call (memset_libfunc, 0,
+ emit_library_call (memset_libfunc, LCT_NORMAL,
VOIDmode, 3,
plus_constant (XEXP (targetx, 0),
startb / BITS_PER_UNIT),
else
#endif
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__setbits"),
- 0, VOIDmode, 4, XEXP (targetx, 0), Pmode,
- bitlength_rtx, TYPE_MODE (sizetype),
+ LCT_NORMAL, VOIDmode, 4, XEXP (targetx, 0),
+ Pmode, bitlength_rtx, TYPE_MODE (sizetype),
startbit_rtx, TYPE_MODE (sizetype),
endbit_rtx, TYPE_MODE (sizetype));
if (mode == BLKmode
&& (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
{
- rtx object = assign_stack_temp (GET_MODE (target),
- GET_MODE_SIZE (GET_MODE (target)), 0);
+ rtx object
+ = assign_temp
+ (build_qualified_type (type_for_mode (GET_MODE (target), 0),
+ TYPE_QUAL_CONST),
+ 0, 1, 1);
rtx blk_object = copy_rtx (object);
- MEM_SET_IN_STRUCT_P (object, 1);
- MEM_SET_IN_STRUCT_P (blk_object, 1);
PUT_MODE (blk_object, BLKmode);
- if (bitsize != GET_MODE_BITSIZE (GET_MODE (target)))
+ if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
emit_move_insn (object, target);
store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
align >>= 1;
emit_block_move (target, temp,
- GEN_INT ((bitsize + BITS_PER_UNIT - 1)
- / BITS_PER_UNIT),
+ bitsize == -1 ? expr_size (exp)
+ : GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+ / BITS_PER_UNIT),
align);
return value_mode == VOIDmode ? const0_rtx : target;
}
}
\f
-/* Given an rtx VALUE that may contain additions and multiplications,
- return an equivalent value that just refers to a register or memory.
- This is done by generating instructions to perform the arithmetic
- and returning a pseudo-register containing the value.
+/* Given an rtx VALUE that may contain additions and multiplications, return
+ an equivalent value that just refers to a register, memory, or constant.
+ This is done by generating instructions to perform the arithmetic and
+ returning a pseudo-register containing the value.
The returned value may be a REG, SUBREG, MEM or constant. */
tmp = force_operand (XEXP (value, 0), subtarget);
return expand_mult (GET_MODE (value), tmp,
force_operand (op2, NULL_RTX),
- target, 0);
+ target, 1);
}
if (binoptab)
tree part = TREE_VALUE (tail);
tree part_type = TREE_TYPE (part);
tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
- rtx target = assign_temp (part_type, 0, 1, 1);
+ rtx target
+ = assign_temp (build_qualified_type (part_type,
+ (TYPE_QUALS (part_type)
+ | TYPE_QUAL_CONST)),
+ 0, 1, 1);
+
if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
parts = tree_cons (to_be_saved,
It is always safe for this routine to return zero since it merely
searches for optimization opportunities. */
-static int
+int
safe_from_p (x, exp, top_p)
rtx x;
tree exp;
{
rtx exp_rtl = 0;
int i, nops;
- static int save_expr_count;
- static int save_expr_size = 0;
- static tree *save_expr_rewritten;
- static tree save_expr_trees[256];
+ static tree save_expr_list;
if (x == 0
/* If EXP has varying size, we MUST use a target since we currently
|| TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)) == NULL_TREE
|| TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)))
!= INTEGER_CST)
- && GET_MODE (x) == BLKmode))
+ && GET_MODE (x) == BLKmode)
+ /* If X is in the outgoing argument area, it is always safe. */
+ || (GET_CODE (x) == MEM
+ && (XEXP (x, 0) == virtual_outgoing_args_rtx
+ || (GET_CODE (XEXP (x, 0)) == PLUS
+ && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx))))
return 1;
- if (top_p && save_expr_size == 0)
- {
- int rtn;
-
- save_expr_count = 0;
- save_expr_size = sizeof (save_expr_trees) / sizeof (save_expr_trees[0]);
- save_expr_rewritten = &save_expr_trees[0];
-
- rtn = safe_from_p (x, exp, 1);
-
- for (i = 0; i < save_expr_count; ++i)
- {
- if (TREE_CODE (save_expr_trees[i]) != ERROR_MARK)
- abort ();
- TREE_SET_CODE (save_expr_trees[i], SAVE_EXPR);
- }
-
- save_expr_size = 0;
-
- return rtn;
- }
-
/* If this is a subreg of a hard register, declare it unsafe, otherwise,
find the underlying pseudo. */
if (GET_CODE (x) == SUBREG)
return 0;
}
- /* If X is a location in the outgoing argument area, it is always safe. */
- if (GET_CODE (x) == MEM
- && (XEXP (x, 0) == virtual_outgoing_args_rtx
- || (GET_CODE (XEXP (x, 0)) == PLUS
- && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx)))
- return 1;
+ /* A SAVE_EXPR might appear many times in the expression passed to the
+ top-level safe_from_p call, and if it has a complex subexpression,
+ examining it multiple times could result in a combinatorial explosion.
+ E.g. on an Alpha running at least 200MHz, a Fortran test case compiled
+ with optimization took about 28 minutes to compile -- even though it was
+ only a few lines long. So we mark each SAVE_EXPR we see with TREE_PRIVATE
+ and turn that off when we are done. We keep a list of the SAVE_EXPRs
+ we have processed. Note that the only test of top_p was above. */
+
+ if (top_p)
+ {
+ int rtn;
+ tree t;
+
+ save_expr_list = 0;
+
+ rtn = safe_from_p (x, exp, 0);
+
+ for (t = save_expr_list; t != 0; t = TREE_CHAIN (t))
+ TREE_PRIVATE (TREE_PURPOSE (t)) = 0;
+
+ return rtn;
+ }
+ /* Now look at our tree code and possibly recurse. */
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
case 'd':
{
case ADDR_EXPR:
return (staticp (TREE_OPERAND (exp, 0))
- || safe_from_p (x, TREE_OPERAND (exp, 0), 0)
- || TREE_STATIC (exp));
+ || TREE_STATIC (exp)
+ || safe_from_p (x, TREE_OPERAND (exp, 0), 0));
case INDIRECT_REF:
- if (GET_CODE (x) == MEM)
+ if (GET_CODE (x) == MEM
+ && alias_sets_conflict_p (MEM_ALIAS_SET (x),
+ get_alias_set (exp)))
return 0;
break;
case CALL_EXPR:
- exp_rtl = CALL_EXPR_RTL (exp);
- if (exp_rtl == 0)
- {
- /* Assume that the call will clobber all hard registers and
- all of memory. */
- if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
- || GET_CODE (x) == MEM)
- return 0;
- }
-
+ /* Assume that the call will clobber all hard registers and
+ all of memory. */
+ if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ || GET_CODE (x) == MEM)
+ return 0;
break;
case RTL_EXPR:
if (exp_rtl)
break;
- /* This SAVE_EXPR might appear many times in the top-level
- safe_from_p() expression, and if it has a complex
- subexpression, examining it multiple times could result
- in a combinatorial explosion. E.g. on an Alpha
- running at least 200MHz, a Fortran test case compiled with
- optimization took about 28 minutes to compile -- even though
- it was only a few lines long, and the complicated line causing
- so much time to be spent in the earlier version of safe_from_p()
- had only 293 or so unique nodes.
-
- So, turn this SAVE_EXPR into an ERROR_MARK for now, but remember
- where it is so we can turn it back in the top-level safe_from_p()
- when we're done. */
-
- /* For now, don't bother re-sizing the array. */
- if (save_expr_count >= save_expr_size)
- return 0;
- save_expr_rewritten[save_expr_count++] = exp;
+ /* If we've already scanned this, don't do it again. Otherwise,
+ show we've scanned it and record for clearing the flag if we're
+ going on. */
+ if (TREE_PRIVATE (exp))
+ return 1;
- nops = TREE_CODE_LENGTH (SAVE_EXPR);
- for (i = 0; i < nops; i++)
+ TREE_PRIVATE (exp) = 1;
+ if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0))
{
- tree operand = TREE_OPERAND (exp, i);
- if (operand == NULL_TREE)
- continue;
- TREE_SET_CODE (exp, ERROR_MARK);
- if (!safe_from_p (x, operand, 0))
- return 0;
- TREE_SET_CODE (exp, SAVE_EXPR);
+ TREE_PRIVATE (exp) = 0;
+ return 0;
}
- TREE_SET_CODE (exp, ERROR_MARK);
+
+ save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list);
return 1;
case BIND_EXPR:
if (exp_rtl)
break;
- nops = TREE_CODE_LENGTH (TREE_CODE (exp));
+ nops = first_rtl_op (TREE_CODE (exp));
for (i = 0; i < nops; i++)
if (TREE_OPERAND (exp, i) != 0
&& ! safe_from_p (x, TREE_OPERAND (exp, i), 0))
return 0;
+
+ /* If this is a language-specific tree code, it may require
+ special handling. */
+ if (TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE
+ && lang_safe_from_p
+ && !(*lang_safe_from_p) (x, exp))
+ return 0;
}
/* If we have an rtl, find any enclosed object. Then see if we conflict
}
/* If the rtl is X, then it is not safe. Otherwise, it is unless both
- are memory and EXP is not readonly. */
+ are memory and they conflict. */
return ! (rtx_equal_p (x, exp_rtl)
|| (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
- && ! TREE_READONLY (exp)));
+ && true_dependence (exp_rtl, GET_MODE (x), x,
+ rtx_addr_varies_p)));
}
/* If we reach here, it is safe. */
}
#ifdef MAX_INTEGER_COMPUTATION_MODE
+
void
check_max_integer_computation_mode (exp)
tree exp;
mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
}
/* Check operand of a unary op. */
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
}
/* Check operands of a binary/comparison op. */
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
}
}
#endif
\f
-/* Utility function used by expand_expr to see if TYPE, a RECORD_TYPE,
- has any readonly fields. If any of the fields have types that
- contain readonly fields, return true as well. */
-
-static int
-readonly_fields_p (type)
- tree type;
-{
- tree field;
-
- for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
- if (TREE_CODE (field) == FIELD_DECL
- && (TREE_READONLY (field)
- || (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
- && readonly_fields_p (TREE_TYPE (field)))))
- return 1;
-
- return 0;
-}
-\f
/* expand_expr: generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null.
In the case of a void EXP, const0_rtx is returned.
enum expand_modifier ro_modifier;
/* Handle ERROR_MARK before anybody tries to access its type. */
- if (TREE_CODE (exp) == ERROR_MARK)
+ if (TREE_CODE (exp) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
{
op0 = CONST0_RTX (tmode);
if (op0 != 0)
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
}
if (tmode != mode
&& TREE_CODE (exp) != RTL_EXPR
&& GET_MODE_CLASS (tmode) == MODE_INT
&& tmode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
check_max_integer_computation_mode (exp);
#endif
&& function != inline_function_decl && function != 0)
{
struct function *p = find_function_data (function);
- /* Allocate in the memory associated with the function
- that the label is in. */
- push_obstacks (p->function_obstack,
- p->function_maybepermanent_obstack);
-
p->expr->x_forced_labels
= gen_rtx_EXPR_LIST (VOIDmode, label_rtx (exp),
p->expr->x_forced_labels);
- pop_obstacks ();
}
else
{
if (DECL_SIZE (exp) == 0 && COMPLETE_TYPE_P (TREE_TYPE (exp))
&& (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
layout_decl (exp, 0);
PUT_MODE (DECL_RTL (exp), DECL_MODE (exp));
- pop_obstacks ();
}
/* Although static-storage variables start off initialized, according to
in_check_memory_usage = 1;
if (memory_usage != MEMORY_USE_DONT)
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ emit_library_call (chkr_check_addr_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
XEXP (DECL_RTL (exp), 0), Pmode,
GEN_INT (int_size_in_bytes (type)),
TYPE_MODE (sizetype),
case COMPLEX_CST:
case STRING_CST:
if (! TREE_CST_RTL (exp))
- output_constant_def (exp);
+ output_constant_def (exp, 1);
/* TREE_CST_RTL probably contains a constant address.
On RISC machines where a constant address isn't valid,
if (mode == VOIDmode)
temp = const0_rtx;
else
- temp = assign_temp (type, 3, 0, 0);
+ temp = assign_temp (build_qualified_type (type,
+ (TYPE_QUALS (type)
+ | TYPE_QUAL_CONST)),
+ 3, 0, 0);
SAVE_EXPR_RTL (exp) = temp;
if (!optimize && GET_CODE (temp) == REG)
&& ! mostly_zeros_p (exp))))
|| (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
{
- rtx constructor = output_constant_def (exp);
+ rtx constructor = output_constant_def (exp, 1);
if (modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
XEXP (constructor, 0));
return constructor;
}
-
else
{
/* Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */
if (target == 0 || ! safe_from_p (target, exp, 1)
|| GET_CODE (target) == PARALLEL)
- {
- if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
- target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
- else
- target = assign_temp (type, 0, 1, 1);
- }
-
- if (TREE_READONLY (exp))
- {
- if (GET_CODE (target) == MEM)
- target = copy_rtx (target);
-
- RTX_UNCHANGING_P (target) = 1;
- }
+ target
+ = assign_temp (build_qualified_type (type,
+ (TYPE_QUALS (type)
+ | (TREE_READONLY (exp)
+ * TYPE_QUAL_CONST))),
+ TREE_ADDRESSABLE (exp), 1, 1);
store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0,
int_size_in_bytes (TREE_TYPE (exp)));
if (memory_usage != MEMORY_USE_DONT)
{
in_check_memory_usage = 1;
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
- op0, Pmode,
- GEN_INT (int_size_in_bytes (type)),
+ emit_library_call (chkr_check_addr_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3, op0,
+ Pmode, GEN_INT (int_size_in_bytes (type)),
TYPE_MODE (sizetype),
GEN_INT (memory_usage),
TYPE_MODE (integer_type_node));
/* If we are writing to this object and its type is a record with
readonly fields, we must mark it as readonly so it will
conflict with readonly references to those fields. */
- if (modifier == EXPAND_MEMORY_USE_WO
- && TREE_CODE (type) == RECORD_TYPE && readonly_fields_p (type))
+ if (modifier == EXPAND_MEMORY_USE_WO && readonly_fields_p (type))
RTX_UNCHANGING_P (temp) = 1;
return temp;
else if (TREE_CODE (init) == STRING_CST
&& 0 > compare_tree_int (index,
TREE_STRING_LENGTH (init)))
- return (GEN_INT
- (TREE_STRING_POINTER
- (init)[TREE_INT_CST_LOW (index)]));
+ {
+ tree type = TREE_TYPE (TREE_TYPE (init));
+ enum machine_mode mode = TYPE_MODE (type);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) == 1)
+ return (GEN_INT
+ (TREE_STRING_POINTER
+ (init)[TREE_INT_CST_LOW (index)]));
+ }
}
}
}
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
{
- rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1);
+ tree nt = build_qualified_type (TREE_TYPE (tem),
+ (TYPE_QUALS (TREE_TYPE (tem))
+ | TYPE_QUAL_CONST));
+ rtx memloc = assign_temp (nt, 1, 1, 1);
mark_temp_addr_taken (memloc);
emit_move_insn (memloc, op0);
/* Check the access right of the pointer. */
in_check_memory_usage = 1;
if (size > BITS_PER_UNIT)
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
- to, Pmode,
- GEN_INT (size / BITS_PER_UNIT),
+ emit_library_call (chkr_check_addr_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3, to,
+ Pmode, GEN_INT (size / BITS_PER_UNIT),
TYPE_MODE (sizetype),
GEN_INT (memory_usage),
TYPE_MODE (integer_type_node));
target = assign_temp (type, 0, 1, 1);
emit_block_move (target, op0,
- GEN_INT ((bitsize + BITS_PER_UNIT - 1)
- / BITS_PER_UNIT),
+ bitsize == -1 ? expr_size (exp)
+ : GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+ / BITS_PER_UNIT),
BITS_PER_UNIT);
return target;
if (mode == BLKmode)
{
- rtx new = assign_stack_temp (ext_mode,
- bitsize / BITS_PER_UNIT, 0);
+ tree nt = build_qualified_type (type_for_mode (ext_mode, 0),
+ TYPE_QUAL_CONST);
+ rtx new = assign_temp (nt, 0, 1, 1);
emit_move_insn (new, op0);
op0 = copy_rtx (new);
PUT_MODE (op0, BLKmode);
- MEM_SET_IN_STRUCT_P (op0, 1);
}
return op0;
/* Get a reference to just this component. */
if (modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
- op0 = gen_rtx_MEM (mode1, plus_constant (XEXP (op0, 0),
- (bitpos / BITS_PER_UNIT)));
+ {
+ rtx new = gen_rtx_MEM (mode1,
+ plus_constant (XEXP (op0, 0),
+ (bitpos / BITS_PER_UNIT)));
+
+ MEM_COPY_ATTRIBUTES (new, op0);
+ op0 = new;
+ }
else
op0 = change_address (op0, mode1,
plus_constant (XEXP (op0, 0),
rtx rlow;
rtx diff, quo, rem, addr, bit, result;
- preexpand_calls (exp);
-
/* If domain is empty, answer is no. Likewise if index is constant
and out of bounds. */
if (((TREE_CODE (set_high_bound) == INTEGER_CST
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
== FUNCTION_DECL)
&& DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
- return expand_builtin (exp, target, subtarget, tmode, ignore);
-
- /* If this call was expanded already by preexpand_calls,
- just return the result we got. */
- if (CALL_EXPR_RTL (exp) != 0)
- return CALL_EXPR_RTL (exp);
+ {
+ if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+ == BUILT_IN_FRONTEND)
+ return (*lang_expand_expr) (exp, original_target, tmode, modifier);
+ else
+ return expand_builtin (exp, target, subtarget, tmode, ignore);
+ }
return expand_call (exp, target, ignore);
modifier);
if (target == 0)
- {
- if (mode != BLKmode)
- target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
- else
- target = assign_temp (type, 0, 1, 1);
- }
+ target = assign_temp (type, 0, 1, 1);
if (GET_CODE (target) == MEM)
/* Store data into beginning of memory target. */
MIN ((int_size_in_bytes (TREE_TYPE
(TREE_OPERAND (exp, 0)))
* BITS_PER_UNIT),
- GET_MODE_BITSIZE (mode)),
+ (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
VOIDmode, 0, BITS_PER_UNIT,
int_size_in_bytes (type), 0);
/* We come here from MINUS_EXPR when the second operand is a
constant. */
plus_expr:
- this_optab = add_optab;
+ this_optab = ! unsignedp && flag_trapv
+ && (GET_MODE_CLASS(mode) == MODE_INT)
+ ? addv_optab : add_optab;
/* If we are adding a constant, an RTL_EXPR that is sp, fp, or ap, and
something else, make sure we add the register to the constant and
If this is an EXPAND_SUM call, always return the sum. */
if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
- || mode == ptr_mode)
+ || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
{
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
|| mode != ptr_mode)
goto binop;
- preexpand_calls (exp);
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
goto plus_expr;
}
}
- this_optab = sub_optab;
+ this_optab = ! unsignedp && flag_trapv
+ && (GET_MODE_CLASS(mode) == MODE_INT)
+ ? subv_optab : sub_optab;
goto binop;
case MULT_EXPR:
- preexpand_calls (exp);
/* If first operand is constant, swap them.
Thus the following special case checks need only
check the second operand. */
case CEIL_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
- preexpand_calls (exp);
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
/* Possible optimization: compute the dividend with EXPAND_SUM
case FLOOR_MOD_EXPR:
case CEIL_MOD_EXPR:
case ROUND_MOD_EXPR:
- preexpand_calls (exp);
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
case NEGATE_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
- temp = expand_unop (mode, neg_optab, op0, target, 0);
+ temp = expand_unop (mode,
+ ! unsignedp && flag_trapv
+ && (GET_MODE_CLASS(mode) == MODE_INT)
+ ? negv_optab : neg_optab, op0, target, 0);
if (temp == 0)
abort ();
return temp;
if (TREE_UNSIGNED (type))
return op0;
- return expand_abs (mode, op0, target,
+ return expand_abs (mode, op0, target, unsignedp,
safe_from_p (target, TREE_OPERAND (exp, 0), 1));
case MAX_EXPR:
case RSHIFT_EXPR:
case LROTATE_EXPR:
case RROTATE_EXPR:
- preexpand_calls (exp);
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
- preexpand_calls (exp);
temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
if (temp != 0)
return temp;
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
{
rtx result;
- optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR ? add_optab
- : TREE_CODE (binary_op) == MINUS_EXPR ? sub_optab
- : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
- : xor_optab);
+ optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR
+ ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
+ ? addv_optab : add_optab)
+ : TREE_CODE (binary_op) == MINUS_EXPR
+ ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
+ ? subv_optab : sub_optab)
+ : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
+ : xor_optab);
/* If we had X ? A : A + 1, do this as A + (X == 0).
preserve_temp_slots (target);
DECL_RTL (slot) = target;
if (TREE_ADDRESSABLE (slot))
- {
- TREE_ADDRESSABLE (slot) = 0;
- mark_addressable (slot);
- }
+ put_var_into_stack (slot);
/* Since SLOT is not known to the called function
to belong to its stack frame, we must build an explicit
/* If we must have an addressable slot, then make sure that
the RTL that we just stored in slot is OK. */
if (TREE_ADDRESSABLE (slot))
- {
- TREE_ADDRESSABLE (slot) = 0;
- mark_addressable (slot);
- }
+ put_var_into_stack (slot);
}
}
&& TREE_CODE (lhs) != PARM_DECL
&& ! (TREE_CODE (lhs) == INDIRECT_REF
&& TYPE_READONLY (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
- preexpand_calls (exp);
/* Check for |= or &= of a bitfield of size one into another bitfield
of size 1. In this case, (unless we need the result of the
}
else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
- || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
+ || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
+ || GET_CODE (op0) == PARALLEL)
{
/* If this object is in a register, it must be not
be BLKmode. */
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
- rtx memloc = assign_temp (inner_type, 1, 1, 1);
+ tree nt = build_qualified_type (inner_type,
+ (TYPE_QUALS (inner_type)
+ | TYPE_QUAL_CONST));
+ rtx memloc = assign_temp (nt, 1, 1, 1);
mark_temp_addr_taken (memloc);
- emit_move_insn (memloc, op0);
+ if (GET_CODE (op0) == PARALLEL)
+ /* Handle calls that pass values in multiple non-contiguous
+ locations. The Irix 6 ABI has examples of this. */
+ emit_group_store (memloc, op0,
+ int_size_in_bytes (inner_type),
+ TYPE_ALIGN (inner_type));
+ else
+ emit_move_insn (memloc, op0);
op0 = memloc;
}
gen_realpart (partmode, op0));
imag_t = gen_imagpart (partmode, target);
- temp = expand_unop (partmode, neg_optab,
+ temp = expand_unop (partmode,
+ ! unsignedp && flag_trapv
+ && (GET_MODE_CLASS(partmode) == MODE_INT)
+ ? negv_optab : neg_optab,
gen_imagpart (partmode, op0), imag_t, 0);
if (temp != imag_t)
emit_move_insn (imag_t, temp);
/* Here to do an ordinary binary operator, generating an instruction
from the optab already placed in `this_optab'. */
binop:
- preexpand_calls (exp);
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
that was declared const. */
if (TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
+ && host_integerp (index, 0)
&& 0 > compare_tree_int (index,
list_length (CONSTRUCTOR_ELTS
(TREE_OPERAND (exp, 0)))))
tree elem;
for (elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
- i = TREE_INT_CST_LOW (index);
+ i = tree_low_cst (index, 0);
elem != 0 && i != 0; i--, elem = TREE_CHAIN (elem))
;
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
{
- rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1);
+ tree nt = build_qualified_type (TREE_TYPE (tem),
+ (TYPE_QUALS (TREE_TYPE (tem))
+ | TYPE_QUAL_CONST));
+ rtx memloc = assign_temp (nt, 1, 1, 1);
mark_temp_addr_taken (memloc);
emit_move_insn (memloc, op0);
/* Check the access right of the pointer. */
in_check_memory_usage = 1;
if (size > BITS_PER_UNIT)
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ emit_library_call (chkr_check_addr_libfunc,
+ LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
to, ptr_mode, GEN_INT (size / BITS_PER_UNIT),
TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RO),
}
else
{
- rtx new = assign_stack_temp (ext_mode,
- bitsize / BITS_PER_UNIT, 0);
+ tree nt = build_qualified_type (type_for_mode (ext_mode, 0),
+ TYPE_QUAL_CONST);
+ rtx new = assign_temp (nt, 0, 1, 1);
op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
unsignedp, NULL_RTX, ext_mode,
this_optab = add_optab;
}
+ if (TYPE_TRAP_SIGNED (TREE_TYPE (exp)))
+ this_optab = this_optab == add_optab ? addv_optab : subv_optab;
+
/* For a preincrement, see if we can do this with a single instruction. */
if (!post)
{
return temp;
}
\f
-/* Expand all function calls contained within EXP, innermost ones first.
- But don't look within expressions that have sequence points.
- For each CALL_EXPR, record the rtx for its value
- in the CALL_EXPR_RTL field. */
-
-static void
-preexpand_calls (exp)
- tree exp;
-{
- register int nops, i;
- int class = TREE_CODE_CLASS (TREE_CODE (exp));
-
- if (! do_preexpand_calls)
- return;
-
- /* Only expressions and references can contain calls. */
-
- if (! IS_EXPR_CODE_CLASS (class) && class != 'r')
- return;
-
- switch (TREE_CODE (exp))
- {
- case CALL_EXPR:
- /* Do nothing if already expanded. */
- if (CALL_EXPR_RTL (exp) != 0
- /* Do nothing if the call returns a variable-sized object. */
- || (TREE_CODE (TREE_TYPE (exp)) != VOID_TYPE
- && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
- /* Do nothing to built-in functions. */
- || (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
- && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
- == FUNCTION_DECL)
- && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
- return;
-
- CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0);
- return;
-
- case COMPOUND_EXPR:
- case COND_EXPR:
- case TRUTH_ANDIF_EXPR:
- case TRUTH_ORIF_EXPR:
- /* If we find one of these, then we can be sure
- the adjust will be done for it (since it makes jumps).
- Do it now, so that if this is inside an argument
- of a function, we don't get the stack adjustment
- after some other args have already been pushed. */
- do_pending_stack_adjust ();
- return;
-
- case BLOCK:
- case RTL_EXPR:
- case WITH_CLEANUP_EXPR:
- case CLEANUP_POINT_EXPR:
- case TRY_CATCH_EXPR:
- return;
-
- case SAVE_EXPR:
- if (SAVE_EXPR_RTL (exp) != 0)
- return;
-
- default:
- break;
- }
-
- nops = TREE_CODE_LENGTH (TREE_CODE (exp));
- for (i = 0; i < nops; i++)
- if (TREE_OPERAND (exp, i) != 0)
- {
- if (TREE_CODE (exp) == TARGET_EXPR && i == 2)
- /* We don't need to preexpand the cleanup for a TARGET_EXPR.
- It doesn't happen before the call is made. */
- ;
- else
- {
- class = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
- if (IS_EXPR_CODE_CLASS (class) || class == 'r')
- preexpand_calls (TREE_OPERAND (exp, i));
- }
- }
-}
-\f
/* At the start of a function, record that we have no previously-pushed
arguments waiting to be popped. */
/* Do any postincrements in the expression that was tested. */
emit_queue ();
- if (GET_CODE (temp) == CONST_INT || GET_CODE (temp) == LABEL_REF)
+ if (GET_CODE (temp) == CONST_INT
+ || (GET_CODE (temp) == CONST_DOUBLE && GET_MODE (temp) == VOIDmode)
+ || GET_CODE (temp) == LABEL_REF)
{
rtx target = temp == const0_rtx ? if_false_label : if_true_label;
if (target)
return;
op1 = expand_expr_unaligned (TREE_OPERAND (exp, 1), &align1);
+ if (TREE_CODE (TREE_OPERAND (exp, 1)) == ERROR_MARK)
+ return;
+
type = TREE_TYPE (TREE_OPERAND (exp, 0));
mode = TYPE_MODE (type);
+ if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
+ && (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
+ || (GET_MODE_BITSIZE (mode)
+ > GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp,
+ 1)))))))
+ {
+ /* op0 might have been replaced by promoted constant, in which
+ case the type of second argument should be used. */
+ type = TREE_TYPE (TREE_OPERAND (exp, 1));
+ mode = TYPE_MODE (type);
+ }
unsignedp = TREE_UNSIGNED (type);
code = unsignedp ? unsigned_code : signed_code;
arg0 = TREE_OPERAND (exp, 0);
arg1 = TREE_OPERAND (exp, 1);
+
+ /* Don't crash if the comparison was erroneous. */
+ if (arg0 == error_mark_node || arg1 == error_mark_node)
+ return const0_rtx;
+
type = TREE_TYPE (arg0);
operand_mode = TYPE_MODE (type);
unsignedp = TREE_UNSIGNED (type);
op0 = expand_expr (inner, subtarget, VOIDmode, 0);
if (bitnum != 0)
- op0 = expand_shift (RSHIFT_EXPR, GET_MODE (op0), op0,
+ op0 = expand_shift (RSHIFT_EXPR, operand_mode, op0,
size_int (bitnum), subtarget, ops_unsignedp);
if (GET_MODE (op0) != mode)
return 0;
}
- preexpand_calls (exp);
if (! get_subtarget (target)
|| GET_MODE (subtarget) != operand_mode
|| ! safe_from_p (subtarget, arg1, 1))