/* Convert tree expression to rtl instructions, for GNU compiler.
- Copyright (C) 1988, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1988, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
static tree init_noncopied_parts PROTO((tree, tree));
static int safe_from_p PROTO((rtx, tree));
static int fixed_type_p PROTO((tree));
+static rtx var_rtx PROTO((tree));
static int get_pointer_alignment PROTO((tree, unsigned));
static tree string_constant PROTO((tree, tree *));
static tree c_strlen PROTO((tree));
{
rtx value;
-#ifdef HAVE_extendqfhf2
- if (HAVE_extendqfhf2 && from_mode == QFmode && to_mode == HFmode)
+ if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
{
- emit_unop_insn (CODE_FOR_extendqfhf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendqfsf2
- if (HAVE_extendqfsf2 && from_mode == QFmode && to_mode == SFmode)
- {
- emit_unop_insn (CODE_FOR_extendqfsf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendqfdf2
- if (HAVE_extendqfdf2 && from_mode == QFmode && to_mode == DFmode)
- {
- emit_unop_insn (CODE_FOR_extendqfdf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendqfxf2
- if (HAVE_extendqfxf2 && from_mode == QFmode && to_mode == XFmode)
- {
- emit_unop_insn (CODE_FOR_extendqfxf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendqftf2
- if (HAVE_extendqftf2 && from_mode == QFmode && to_mode == TFmode)
- {
- emit_unop_insn (CODE_FOR_extendqftf2, to, from, UNKNOWN);
- return;
- }
-#endif
-
-#ifdef HAVE_extendhftqf2
- if (HAVE_extendhftqf2 && from_mode == HFmode && to_mode == TQFmode)
- {
- emit_unop_insn (CODE_FOR_extendhftqf2, to, from, UNKNOWN);
- return;
- }
-#endif
-
-#ifdef HAVE_extendhfsf2
- if (HAVE_extendhfsf2 && from_mode == HFmode && to_mode == SFmode)
- {
- emit_unop_insn (CODE_FOR_extendhfsf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendhfdf2
- if (HAVE_extendhfdf2 && from_mode == HFmode && to_mode == DFmode)
- {
- emit_unop_insn (CODE_FOR_extendhfdf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendhfxf2
- if (HAVE_extendhfxf2 && from_mode == HFmode && to_mode == XFmode)
- {
- emit_unop_insn (CODE_FOR_extendhfxf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendhftf2
- if (HAVE_extendhftf2 && from_mode == HFmode && to_mode == TFmode)
- {
- emit_unop_insn (CODE_FOR_extendhftf2, to, from, UNKNOWN);
- return;
- }
-#endif
-
-#ifdef HAVE_extendsfdf2
- if (HAVE_extendsfdf2 && from_mode == SFmode && to_mode == DFmode)
- {
- emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendsfxf2
- if (HAVE_extendsfxf2 && from_mode == SFmode && to_mode == XFmode)
- {
- emit_unop_insn (CODE_FOR_extendsfxf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendsftf2
- if (HAVE_extendsftf2 && from_mode == SFmode && to_mode == TFmode)
- {
- emit_unop_insn (CODE_FOR_extendsftf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extenddfxf2
- if (HAVE_extenddfxf2 && from_mode == DFmode && to_mode == XFmode)
- {
- emit_unop_insn (CODE_FOR_extenddfxf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extenddftf2
- if (HAVE_extenddftf2 && from_mode == DFmode && to_mode == TFmode)
- {
- emit_unop_insn (CODE_FOR_extenddftf2, to, from, UNKNOWN);
- return;
+ /* Try converting directly if the insn is supported. */
+ if ((code = can_extend_p (to_mode, from_mode, 0))
+ != CODE_FOR_nothing)
+ {
+ emit_unop_insn (code, to, from, UNKNOWN);
+ return;
+ }
}
-#endif
-
+
#ifdef HAVE_trunchfqf2
if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
{
return;
}
#endif
+
+#ifdef HAVE_truncsftqf2
+ if (HAVE_truncsftqf2 && from_mode == SFmode && to_mode == TQFmode)
+ {
+ emit_unop_insn (CODE_FOR_truncsftqf2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+#ifdef HAVE_truncdftqf2
+ if (HAVE_truncdftqf2 && from_mode == DFmode && to_mode == TQFmode)
+ {
+ emit_unop_insn (CODE_FOR_truncdftqf2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+#ifdef HAVE_truncxftqf2
+ if (HAVE_truncxftqf2 && from_mode == XFmode && to_mode == TQFmode)
+ {
+ emit_unop_insn (CODE_FOR_truncxftqf2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+#ifdef HAVE_trunctftqf2
+ if (HAVE_trunctftqf2 && from_mode == TFmode && to_mode == TQFmode)
+ {
+ emit_unop_insn (CODE_FOR_trunctftqf2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+
#ifdef HAVE_truncdfsf2
if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
{
if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
&& GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
- return immed_double_const (INTVAL (x), (HOST_WIDE_INT) 0, mode);
+ {
+ HOST_WIDE_INT val = INTVAL (x);
+
+ if (oldmode != VOIDmode
+ && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
+ {
+ int width = GET_MODE_BITSIZE (oldmode);
+
+ /* We need to zero extend VAL. */
+ val &= ((HOST_WIDE_INT) 1 << width) - 1;
+ }
+
+ return immed_double_const (val, (HOST_WIDE_INT) 0, mode);
+ }
/* We can do this with a gen_lowpart if both desired and current modes
are integer, and this is either a constant integer, a register, or a
}
/* The code above should have handled everything. */
- if (data.len != 0)
+ if (data.len > 0)
abort ();
}
{
int i;
rtx pat, last;
+ enum machine_mode mode;
+ /* If SIZE is that of a mode no bigger than a word, just use that
+ mode's store operation. */
+ if (size <= UNITS_PER_WORD
+ && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
+ {
+ emit_move_insn (change_address (x, mode, NULL),
+ gen_rtx (REG, mode, regno));
+ return;
+ }
+
/* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
- to the left before storing to memory. */
+ to the left before storing to memory. Note that the previous test
+ doesn't handle all cases (e.g. SIZE == 3). */
if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
{
rtx tem = operand_subword (x, 0, 1, BLKmode);
{
if (GET_MODE (target_reg) == GET_MODE (y))
source = y;
- else if (GET_MODE_SIZE (GET_MODE (target_reg))
- == GET_MODE_SIZE (GET_MODE (y)))
- source = gen_rtx (SUBREG, GET_MODE (target_reg), y, 0);
+ /* Allow for the target_reg to be smaller than the input register
+ to allow for AIX with 4 DF arguments after a single SI arg. The
+ last DF argument will only load 1 word into the integer registers,
+ but load a DF value into the float registers. */
+ else if ((GET_MODE_SIZE (GET_MODE (target_reg))
+ <= GET_MODE_SIZE (GET_MODE (y)))
+ && GET_MODE (target_reg) == word_mode)
+ /* This might be a const_double, so we can't just use SUBREG. */
+ source = operand_subword (y, 0, 0, VOIDmode);
else
abort ();
}
plus_constant (XEXP (x, 0),
INTVAL (XEXP (element, 1))));
else if (XEXP (element, 1) == const0_rtx)
- target = x;
+ {
+ target = x;
+ if (GET_MODE (target) != GET_MODE (source_reg))
+ target = gen_lowpart (GET_MODE (source_reg), target);
+ }
else
abort ();
Default is below for small data on big-endian machines; else above. */
enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
- /* If we're placing part of X into a register and part of X onto
- the stack, indicate that the entire register is clobbered to
- keep flow from thinking the unused part of the register is live. */
- if (partial > 0 && reg != 0)
- emit_insn (gen_rtx (CLOBBER, VOIDmode, reg));
-
/* Invert direction if stack is post-update. */
if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
if (where_pad != none)
int alignment;
push_temp_slots ();
- tem = get_inner_reference (to, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep);
+ tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
+ &unsignedp, &volatilep, &alignment);
/* If we are going to use store_bit_field and extract_bit_field,
make sure to_rtx will be safe for multiple use. */
if (mode1 == VOIDmode && want_value)
tem = stabilize_reference (tem);
- alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
if (offset != 0)
{
to_rtx = change_address (to_rtx, VOIDmode,
gen_rtx (PLUS, ptr_mode, XEXP (to_rtx, 0),
force_reg (ptr_mode, offset_rtx)));
- /* If we have a variable offset, the known alignment
- is only that of the innermost structure containing the field.
- (Actually, we could sometimes do better by using the
- align of an element of the innermost array, but no need.) */
- if (TREE_CODE (to) == COMPONENT_REF
- || TREE_CODE (to) == BIT_FIELD_REF)
- alignment
- = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (to, 0))) / BITS_PER_UNIT;
}
if (volatilep)
{
For non-BLKmode, it is more efficient not to do this. */
rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+ rtx flag = NULL_RTX;
+ tree left_cleanups = NULL_TREE;
+ tree right_cleanups = NULL_TREE;
+ tree old_cleanups = cleanups_this_call;
+
+ /* Used to save a pointer to the place to put the setting of
+ the flag that indicates if this side of the conditional was
+ taken. We backpatch the code, if we find out later that we
+ have any conditional cleanups that need to be performed. */
+ rtx dest_right_flag = NULL_RTX;
+ rtx dest_left_flag = NULL_RTX;
emit_queue ();
target = protect_from_queue (target, 1);
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1);
store_expr (TREE_OPERAND (exp, 1), target, 0);
+ dest_left_flag = get_last_insn ();
+ /* Handle conditional cleanups, if any. */
+ left_cleanups = defer_cleanups_to (old_cleanups);
emit_queue ();
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
store_expr (TREE_OPERAND (exp, 2), target, 0);
+ dest_right_flag = get_last_insn ();
+ /* Handle conditional cleanups, if any. */
+ right_cleanups = defer_cleanups_to (old_cleanups);
emit_queue ();
emit_label (lab2);
OK_DEFER_POP;
+
+ /* Add back in any conditional cleanups. */
+ if (left_cleanups || right_cleanups)
+ {
+ tree new_cleanups;
+ tree cond;
+ rtx last;
+
+ /* Now that we know that a flag is needed, go back and add in the
+ setting of the flag. */
+
+ flag = gen_reg_rtx (word_mode);
+
+ /* Do the left side flag. */
+ last = get_last_insn ();
+ /* Flag left cleanups as needed. */
+ emit_move_insn (flag, const1_rtx);
+ /* ??? deprecated, use sequences instead. */
+ reorder_insns (NEXT_INSN (last), get_last_insn (), dest_left_flag);
+
+ /* Do the right side flag. */
+ last = get_last_insn ();
+ /* Flag left cleanups as needed. */
+ emit_move_insn (flag, const0_rtx);
+ /* ??? deprecated, use sequences instead. */
+ reorder_insns (NEXT_INSN (last), get_last_insn (), dest_right_flag);
+
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+
+ /* convert flag, which is an rtx, into a tree. */
+ cond = make_node (RTL_EXPR);
+ TREE_TYPE (cond) = integer_type_node;
+ RTL_EXPR_RTL (cond) = flag;
+ RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
+ cond = save_expr (cond);
+
+ if (! left_cleanups)
+ left_cleanups = integer_zero_node;
+ if (! right_cleanups)
+ right_cleanups = integer_zero_node;
+ new_cleanups = build (COND_EXPR, void_type_node,
+ truthvalue_conversion (cond),
+ left_cleanups, right_cleanups);
+ new_cleanups = fold (new_cleanups);
+
+ pop_obstacks ();
+
+ /* Now add in the conditionalized cleanups. */
+ cleanups_this_call
+ = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
+ expand_eh_region_start ();
+ }
return want_value ? target : NULL_RTX;
}
else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
/* If we don't want a value, we can do the conversion inside EXP,
which will often result in some optimizations. Do the conversion
in two steps: first change the signedness, if needed, then
- the extend. */
- if (! want_value)
+ the extend. But don't do this if the type of EXP is a subtype
+ of something else since then the conversion might involve
+ more than just converting modes. */
+ if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+ && TREE_TYPE (TREE_TYPE (exp)) == 0)
{
if (TREE_UNSIGNED (TREE_TYPE (exp))
!= SUBREG_PROMOTED_UNSIGNED_P (target))
{
#ifdef TARGET_MEM_FUNCTIONS
emit_library_call (memset_libfunc, 0, VOIDmode, 3,
- addr, Pmode,
+ addr, ptr_mode,
const0_rtx, TYPE_MODE (integer_type_node),
convert_to_mode (TYPE_MODE (sizetype),
size,
TYPE_MODE (sizetype));
#else
emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
- addr, Pmode,
+ addr, ptr_mode,
convert_to_mode (TYPE_MODE (integer_type_node),
size,
TREE_UNSIGNED (integer_type_node)),
It is also needed to check for missing elements. */
for (elt = CONSTRUCTOR_ELTS (exp);
elt != NULL_TREE;
- elt = TREE_CHAIN (elt), i++)
+ elt = TREE_CHAIN (elt))
{
tree index = TREE_PURPOSE (elt);
HOST_WIDE_INT this_node_count;
{
rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+ /* If BITSIZE is narrower than the size of the type of EXP
+ we will be narrowing TEMP. Normally, what's wanted are the
+ low-order bits. However, if EXP's type is a record and this is
+ big-endian machine, we want the upper BITSIZE bits. */
+ if (BYTES_BIG_ENDIAN && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
+ && bitsize < GET_MODE_BITSIZE (GET_MODE (temp))
+ && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+ temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
+ size_int (GET_MODE_BITSIZE (GET_MODE (temp))
+ - bitsize),
+ temp, 1);
+
/* Unless MODE is VOIDmode or BLKmode, convert TEMP to
MODE. */
if (mode != VOIDmode && mode != BLKmode
giving the variable offset (in units) in *POFFSET.
This offset is in addition to the bit position.
If the position is not variable, we store 0 in *POFFSET.
+ We set *PALIGNMENT to the alignment in bytes of the address that will be
+ computed. This is the alignment of the thing we return if *POFFSET
+ is zero, but can be more less strictly aligned if *POFFSET is nonzero.
If any of the extraction expressions is volatile,
we store 1 in *PVOLATILEP. Otherwise we don't change that.
If the field describes a variable-sized object, *PMODE is set to
VOIDmode and *PBITSIZE is set to -1. An access cannot be made in
- this case, but the address of the object can be found. */
+ this case, but the address of the object can be found. */
tree
get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
- punsignedp, pvolatilep)
+ punsignedp, pvolatilep, palignment)
tree exp;
int *pbitsize;
int *pbitpos;
enum machine_mode *pmode;
int *punsignedp;
int *pvolatilep;
+ int *palignment;
{
tree orig_exp = exp;
tree size_tree = 0;
enum machine_mode mode = VOIDmode;
tree offset = integer_zero_node;
+ int alignment = BIGGEST_ALIGNMENT;
if (TREE_CODE (exp) == COMPONENT_REF)
{
}
index = fold (build (MULT_EXPR, index_type, index,
- TYPE_SIZE (TREE_TYPE (exp))));
+ convert (index_type,
+ TYPE_SIZE (TREE_TYPE (exp)))));
if (TREE_CODE (index) == INTEGER_CST
&& TREE_INT_CST_HIGH (index) == 0)
/* If any reference in the chain is volatile, the effect is volatile. */
if (TREE_THIS_VOLATILE (exp))
*pvolatilep = 1;
+
+ /* If the offset is non-constant already, then we can't assume any
+ alignment more than the alignment here. */
+ if (! integer_zerop (offset))
+ alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
+
exp = TREE_OPERAND (exp, 0);
}
+ if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
+ alignment = MIN (alignment, DECL_ALIGN (exp));
+ else if (TREE_TYPE (exp) != 0)
+ alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
+
if (integer_zerop (offset))
offset = 0;
*pmode = mode;
*poffset = offset;
+ *palignment = alignment / BITS_PER_UNIT;
return exp;
}
\f
return 1;
return 0;
}
+
+/* Subroutine of expand_expr: return rtx if EXP is a
+ variable or parameter; else return 0. */
+
+static rtx
+var_rtx (exp)
+ tree exp;
+{
+ STRIP_NOPS (exp);
+ switch (TREE_CODE (exp))
+ {
+ case PARM_DECL:
+ case VAR_DECL:
+ return DECL_RTL (exp);
+ default:
+ return 0;
+ }
+}
\f
/* expand_expr: generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null.
further information, see tree.def. */
if (placeholder_list)
{
- tree object;
+ tree need_type = TYPE_MAIN_VARIANT (type);
+ tree object = 0;
tree old_list = placeholder_list;
+ tree elt;
- for (object = TREE_PURPOSE (placeholder_list);
- (TYPE_MAIN_VARIANT (TREE_TYPE (object))
- != TYPE_MAIN_VARIANT (type))
- && (TREE_CODE_CLASS (TREE_CODE (object)) == 'r'
- || TREE_CODE_CLASS (TREE_CODE (object)) == '1'
- || TREE_CODE_CLASS (TREE_CODE (object)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (object)) == 'e');
- object = TREE_OPERAND (object, 0))
- ;
-
- if (object != 0
- && (TYPE_MAIN_VARIANT (TREE_TYPE (object))
- == TYPE_MAIN_VARIANT (type)))
+ /* See if the object is the type that we want. Then see if
+ the operand of any reference is the type we want. */
+ if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_PURPOSE (placeholder_list)))
+ == need_type))
+ object = TREE_PURPOSE (placeholder_list);
+
+ /* Find the innermost reference that is of the type we want. */
+ for (elt = TREE_PURPOSE (placeholder_list);
+ elt != 0
+ && (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e');
+ elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1) : TREE_OPERAND (elt, 0)))
+ if (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (elt, 0)))
+ == need_type))
+ object = TREE_OPERAND (elt, 0);
+
+ if (object != 0)
{
/* Expand this object skipping the list entries before
it was found in case it is also a PLACEHOLDER_EXPR.
else
{
- if (target == 0 || ! safe_from_p (target, exp))
+ /* 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)
+ || GET_CODE (target) == PARALLEL)
{
if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
elt = TREE_CHAIN (elt))
- if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
- return expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+ if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)
+ /* We can normally use the value of the field in the
+ CONSTRUCTOR. However, if this is a bitfield in
+ an integral mode that we can fit in a HOST_WIDE_INT,
+ we must mask only the number of bits in the bitfield,
+ since this is done implicitly by the constructor. If
+ the bitfield does not meet either of those conditions,
+ we can't do this optimization. */
+ && (! DECL_BIT_FIELD (TREE_PURPOSE (elt))
+ || ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt)))
+ == MODE_INT)
+ && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
+ <= HOST_BITS_PER_WIDE_INT))))
+ {
+ op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+ if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
+ {
+ int bitsize = DECL_FIELD_SIZE (TREE_PURPOSE (elt));
+ enum machine_mode imode
+ = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
+
+ if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+ {
+ op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
+ op0 = expand_and (op0, op1, target);
+ }
+ else
+ {
+ tree count
+ = build_int_2 (imode - bitsize, 0);
+
+ op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
+ target, 0);
+ op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
+ target, 0);
+ }
+ }
+
+ return op0;
+ }
}
{
int bitpos;
tree offset;
int volatilep = 0;
- tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep);
int alignment;
+ tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+ &mode1, &unsignedp, &volatilep,
+ &alignment);
/* If we got back the original object, something is wrong. Perhaps
we are evaluating an expression too early. In any event, don't
op0 = validize_mem (force_const_mem (mode, op0));
}
- alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
if (offset != 0)
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
op0 = change_address (op0, VOIDmode,
gen_rtx (PLUS, ptr_mode, XEXP (op0, 0),
force_reg (ptr_mode, offset_rtx)));
- /* If we have a variable offset, the known alignment
- is only that of the innermost structure containing the field.
- (Actually, we could sometimes do better by using the
- size of an element of the innermost array, but no need.) */
- if (TREE_CODE (exp) == COMPONENT_REF
- || TREE_CODE (exp) == BIT_FIELD_REF)
- alignment = (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
- / BITS_PER_UNIT);
}
/* Don't forget about volatility even if this is a bitfield. */
|| GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| (modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
- && ((mode1 != BLKmode && ! direct_load[(int) mode1])
+ && ((mode1 != BLKmode && ! direct_load[(int) mode1]
+ && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
/* If the field isn't aligned enough to fetch as a memref,
fetch it as a bit field. */
|| (SLOW_UNALIGNED_ACCESS
unsignedp, target, ext_mode, ext_mode,
alignment,
int_size_in_bytes (TREE_TYPE (tem)));
+
+ /* If the result is a record type and BITSIZE is narrower than
+ the mode of OP0, an integral mode, and this is a big endian
+ machine, we must put the field into the high-order bits. */
+ if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
+ && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+ && bitsize < GET_MODE_BITSIZE (GET_MODE (op0)))
+ op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
+ size_int (GET_MODE_BITSIZE (GET_MODE (op0))
+ - bitsize),
+ op0, 1);
+
if (mode == BLKmode)
{
rtx new = assign_stack_temp (ext_mode,
MEM_IN_STRUCT_P (op0) = 1;
MEM_VOLATILE_P (op0) |= volatilep;
- if (mode == mode1 || mode1 == BLKmode || mode1 == tmode)
+ if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
+ || modifier == EXPAND_CONST_ADDRESS
+ || modifier == EXPAND_INITIALIZER)
return op0;
- if (target == 0)
+ else if (target == 0)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+
convert_move (target, op0, unsignedp);
return target;
}
VOIDmode, 0);
case COND_EXPR:
+ /* If we would have a "singleton" (see below) were it not for a
+ conversion in each arm, bring that conversion back out. */
+ if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (exp, 2)) == NOP_EXPR
+ && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
+ == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
+ {
+ tree true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
+ tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
+
+ if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
+ && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
+ && operand_equal_p (true, TREE_OPERAND (false, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
+ && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
+ && operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
+ return expand_expr (build1 (NOP_EXPR, type,
+ build (COND_EXPR, TREE_TYPE (true),
+ TREE_OPERAND (exp, 0),
+ true, false)),
+ target, tmode, modifier);
+ }
+
{
rtx flag = NULL_RTX;
tree left_cleanups = NULL_TREE;
return target;
}
- /* If we are not to produce a result, we have no target. Otherwise,
- if a target was specified use it; it will not be used as an
- intermediate target unless it is safe. If no target, use a
- temporary. */
-
- if (ignore)
- temp = 0;
- else if (original_target
- && safe_from_p (original_target, TREE_OPERAND (exp, 0))
- && GET_MODE (original_target) == mode
- && ! (GET_CODE (original_target) == MEM
- && MEM_VOLATILE_P (original_target)))
- temp = original_target;
- else
- temp = assign_temp (type, 0, 0, 1);
-
- /* Check for X ? A + B : A. If we have this, we can copy
- A to the output and conditionally add B. Similarly for unary
- operations. Don't do this if X has side-effects because
- those side effects might affect A or B and the "?" operation is
- a sequence point in ANSI. (We test for side effects later.) */
+ /* Check for X ? A + B : A. If we have this, we can copy A to the
+ output and conditionally add B. Similarly for unary operations.
+ Don't do this if X has side-effects because those side effects
+ might affect A or B and the "?" operation is a sequence point in
+ ANSI. (operand_equal_p tests for side effects.) */
if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
&& operand_equal_p (TREE_OPERAND (exp, 2),
TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
- /* If we had X ? A + 1 : A and we can do the test of X as a store-flag
- operation, do this as A + (X != 0). Similarly for other simple
- binary operators. */
+ /* If we are not to produce a result, we have no target. Otherwise,
+ if a target was specified use it; it will not be used as an
+ intermediate target unless it is safe. If no target, use a
+ temporary. */
+
+ if (ignore)
+ temp = 0;
+ else if (original_target
+ && (safe_from_p (original_target, TREE_OPERAND (exp, 0))
+ || (singleton && GET_CODE (original_target) == REG
+ && REGNO (original_target) >= FIRST_PSEUDO_REGISTER
+ && original_target == var_rtx (singleton)))
+ && GET_MODE (original_target) == mode
+ && ! (GET_CODE (original_target) == MEM
+ && MEM_VOLATILE_P (original_target)))
+ temp = original_target;
+ else if (TREE_ADDRESSABLE (type))
+ abort ();
+ else
+ temp = assign_temp (type, 0, 0, 1);
+
+ /* If we had X ? A + C : A, with C a constant power of 2, and we can
+ do the test of X as a store-flag operation, do this as
+ A + ((X != 0) << log C). Similarly for other simple binary
+ operators. Only do for C == 1 if BRANCH_COST is low. */
if (temp && singleton && binary_op
- && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
&& (TREE_CODE (binary_op) == PLUS_EXPR
|| TREE_CODE (binary_op) == MINUS_EXPR
|| TREE_CODE (binary_op) == BIT_IOR_EXPR
|| TREE_CODE (binary_op) == BIT_XOR_EXPR)
- && integer_onep (TREE_OPERAND (binary_op, 1))
+ && (BRANCH_COST >= 3 ? integer_pow2p (TREE_OPERAND (binary_op, 1))
+ : integer_onep (TREE_OPERAND (binary_op, 1)))
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
{
rtx result;
? temp : NULL_RTX),
mode, BRANCH_COST <= 1);
+ if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
+ result = expand_shift (LSHIFT_EXPR, mode, result,
+ build_int_2 (tree_log2
+ (TREE_OPERAND
+ (binary_op, 1)),
+ 0),
+ (safe_from_p (temp, singleton)
+ ? temp : NULL_RTX), 0);
+
if (result)
{
op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
rtx
expand_builtin_return_addr (fndecl_code, count, tem)
enum built_in_function fndecl_code;
- rtx tem;
int count;
+ rtx tem;
{
int i;
enum machine_mode sa_mode = Pmode;
rtx stack_save;
int old_inhibit_defer_pop = inhibit_defer_pop;
- int return_pops = RETURN_POPS_ARGS (get_identifier ("__dummy"),
- get_identifier ("__dummy"), 0);
+ int return_pops
+ = RETURN_POPS_ARGS (get_identifier ("__dummy"),
+ build_function_type (void_type_node, NULL_TREE),
+ 0);
rtx next_arg_reg;
CUMULATIVE_ARGS args_so_far;
int i;
}
#endif
+#ifdef HAVE_nonlocal_goto_receiver
+ if (HAVE_nonlocal_goto_receiver)
+ emit_insn (gen_nonlocal_goto_receiver ());
+#endif
/* The static chain pointer contains the address of dummy function.
We need to call it here to handle some PIC cases of restoring
a global pointer. Then return 1. */
return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
}
+ if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM)
+ {
+ rtx addr = force_reg (Pmode, XEXP (op0, 0));
+ rtx temp, result;
+
+ op0 = change_address (op0, VOIDmode, addr);
+ temp = force_reg (GET_MODE (op0), op0);
+ if (! (*insn_operand_predicate[icode][2]) (op1, mode))
+ op1 = force_reg (mode, op1);
+
+ /* The increment queue is LIFO, thus we have to `queue'
+ the instructions in reverse order. */
+ enqueue_insn (op0, gen_move_insn (op0, temp));
+ result = enqueue_insn (temp, GEN_FCN (icode) (temp, temp, op1));
+ return result;
+ }
}
/* Preincrement, or we can't increment with one simple insn. */
start_sequence ();
do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
seq2 = get_insns ();
+ cleanups = defer_cleanups_to (old_cleanups);
end_sequence ();
- cleanups = defer_cleanups_to (old_cleanups);
if (cleanups)
{
rtx flag = gen_reg_rtx (word_mode);
start_sequence ();
do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
seq2 = get_insns ();
+ cleanups = defer_cleanups_to (old_cleanups);
end_sequence ();
- cleanups = defer_cleanups_to (old_cleanups);
if (cleanups)
{
rtx flag = gen_reg_rtx (word_mode);
tree type;
tree offset;
int volatilep = 0;
+ int alignment;
/* Get description of this reference. We don't actually care
about the underlying object here. */
get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode, &unsignedp, &volatilep);
+ &mode, &unsignedp, &volatilep,
+ &alignment);
type = type_for_size (bitsize, unsignedp);
if (! SLOW_BYTE_ACCESS
else
{
+ rtx seq1, seq2;
+ tree cleanups_left_side, cleanups_right_side, old_cleanups;
+
register rtx label1 = gen_label_rtx ();
drop_through_label = gen_label_rtx ();
+
do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
+
+ /* We need to save the cleanups for the lhs and rhs separately.
+ Keep track of the cleanups seen before the lhs. */
+ old_cleanups = cleanups_this_call;
+ start_sequence ();
/* Now the THEN-expression. */
do_jump (TREE_OPERAND (exp, 1),
if_false_label ? if_false_label : drop_through_label,
/* In case the do_jump just above never jumps. */
do_pending_stack_adjust ();
emit_label (label1);
+ seq1 = get_insns ();
+ /* Now grab the cleanups for the lhs. */
+ cleanups_left_side = defer_cleanups_to (old_cleanups);
+ end_sequence ();
+
+ /* And keep track of where we start before the rhs. */
+ old_cleanups = cleanups_this_call;
+ start_sequence ();
/* Now the ELSE-expression. */
do_jump (TREE_OPERAND (exp, 2),
if_false_label ? if_false_label : drop_through_label,
if_true_label ? if_true_label : drop_through_label);
+ seq2 = get_insns ();
+ /* Grab the cleanups for the rhs. */
+ cleanups_right_side = defer_cleanups_to (old_cleanups);
+ end_sequence ();
+
+ if (cleanups_left_side || cleanups_right_side)
+ {
+ /* Make the cleanups for the THEN and ELSE clauses
+ conditional based on which half is executed. */
+ rtx flag = gen_reg_rtx (word_mode);
+ tree new_cleanups;
+ tree cond;
+
+ /* Set the flag to 0 so that we know we executed the lhs. */
+ emit_move_insn (flag, const0_rtx);
+ emit_insns (seq1);
+
+ /* Set the flag to 1 so that we know we executed the rhs. */
+ emit_move_insn (flag, const1_rtx);
+ emit_insns (seq2);
+
+ /* Make sure the cleanup lives on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+
+ /* Now, build up a COND_EXPR that tests the value of the
+ flag, and then either do the cleanups for the lhs or the
+ rhs. */
+ cond = make_node (RTL_EXPR);
+ TREE_TYPE (cond) = integer_type_node;
+ RTL_EXPR_RTL (cond) = flag;
+ RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
+ cond = save_expr (cond);
+
+ new_cleanups = build (COND_EXPR, void_type_node,
+ truthvalue_conversion (cond),
+ cleanups_right_side, cleanups_left_side);
+ new_cleanups = fold (new_cleanups);
+
+ pop_obstacks ();
+
+ /* Now add in the conditionalized cleanups. */
+ cleanups_this_call
+ = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
+ expand_eh_region_start ();
+ }
+ else
+ {
+ /* No cleanups were needed, so emit the two sequences
+ directly. */
+ emit_insns (seq1);
+ emit_insns (seq2);
+ }
}
break;
}
/* If this failed, we have to do this with set/compare/jump/set code. */
- if (target == 0 || GET_CODE (target) != REG
+ if (GET_CODE (target) != REG
|| reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
target = gen_reg_rtx (GET_MODE (target));