/* Convert tree expression to rtl instructions, for GNU compiler.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
#include "timevar.h"
#include "df.h"
#include "diagnostic.h"
+#include "ssaexpand.h"
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
/* This structure is used by move_by_pieces to describe the move to
be performed. */
-struct move_by_pieces
+struct move_by_pieces_d
{
rtx to;
rtx to_addr;
/* This structure is used by store_by_pieces to describe the clear to
be performed. */
-struct store_by_pieces
+struct store_by_pieces_d
{
rtx to;
rtx to_addr;
unsigned int,
unsigned int);
static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
- struct move_by_pieces *);
+ struct move_by_pieces_d *);
static bool block_move_libcall_safe_for_call_parm (void);
static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT);
static tree emit_block_move_libcall_fn (int);
static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
-static void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
+static void store_by_pieces_1 (struct store_by_pieces_d *, unsigned int);
static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
- struct store_by_pieces *);
+ struct store_by_pieces_d *);
static tree clear_storage_libcall_fn (int);
static rtx compress_float_constant (rtx, rtx);
static rtx get_subtarget (rtx);
static void expand_operands (tree, tree, rtx, rtx*, rtx*,
enum expand_modifier);
static rtx reduce_to_bit_field_precision (rtx, rtx, tree);
-static rtx do_store_flag (tree, rtx, enum machine_mode, int);
+static rtx do_store_flag (tree, rtx, enum machine_mode);
#ifdef PUSH_ROUNDING
static void emit_single_push_insn (enum machine_mode, rtx, tree);
#endif
#ifndef MOVE_BY_PIECES_P
#define MOVE_BY_PIECES_P(SIZE, ALIGN) \
(move_by_pieces_ninsns (SIZE, ALIGN, MOVE_MAX_PIECES + 1) \
- < (unsigned int) MOVE_RATIO)
+ < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
#endif
/* This macro is used to determine whether clear_by_pieces should be
#ifndef CLEAR_BY_PIECES_P
#define CLEAR_BY_PIECES_P(SIZE, ALIGN) \
(move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
- < (unsigned int) CLEAR_RATIO)
+ < (unsigned int) CLEAR_RATIO (optimize_insn_for_speed_p ()))
#endif
/* This macro is used to determine whether store_by_pieces should be
#ifndef SET_BY_PIECES_P
#define SET_BY_PIECES_P(SIZE, ALIGN) \
(move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
- < (unsigned int) SET_RATIO)
+ < (unsigned int) SET_RATIO (optimize_insn_for_speed_p ()))
#endif
/* This macro is used to determine whether store_by_pieces should be
#ifndef STORE_BY_PIECES_P
#define STORE_BY_PIECES_P(SIZE, ALIGN) \
(move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
- < (unsigned int) MOVE_RATIO)
+ < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
#endif
/* This array records the insn_code of insns to perform block moves. */
enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES];
enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
-enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];
enum insn_code sync_lock_release[NUM_MACHINE_MODES];
reg = gen_rtx_REG (VOIDmode, -1);
insn = rtx_alloc (INSN);
- pat = gen_rtx_SET (0, NULL_RTX, NULL_RTX);
+ pat = gen_rtx_SET (VOIDmode, NULL_RTX, NULL_RTX);
PATTERN (insn) = pat;
for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
if (unsignedp)
fill_value = const0_rtx;
else
- {
-#ifdef HAVE_slt
- if (HAVE_slt
- && insn_data[(int) CODE_FOR_slt].operand[0].mode == word_mode
- && STORE_FLAG_VALUE == -1)
- {
- emit_cmp_insn (lowfrom, const0_rtx, NE, NULL_RTX,
- lowpart_mode, 0);
- fill_value = gen_reg_rtx (word_mode);
- emit_insn (gen_slt (fill_value));
- }
- else
-#endif
- {
- fill_value
- = expand_shift (RSHIFT_EXPR, lowpart_mode, lowfrom,
- size_int (GET_MODE_BITSIZE (lowpart_mode) - 1),
- NULL_RTX, 0);
- fill_value = convert_to_mode (word_mode, fill_value, 1);
- }
- }
+ fill_value = emit_store_flag (gen_reg_rtx (word_mode),
+ LT, lowfrom, const0_rtx,
+ VOIDmode, 0, -1);
/* Fill the remaining words. */
for (i = GET_MODE_SIZE (lowpart_mode) / UNITS_PER_WORD; i < nwords; i++)
move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
unsigned int align, int endp)
{
- struct move_by_pieces data;
+ struct move_by_pieces_d data;
rtx to_addr, from_addr = XEXP (from, 0);
unsigned int max_size = MOVE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode;
static void
move_by_pieces_1 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
- struct move_by_pieces *data)
+ struct move_by_pieces_d *data)
{
unsigned int size = GET_MODE_SIZE (mode);
rtx to1 = NULL_RTX, from1;
const_ptr_type_node, sizetype,
NULL_TREE);
- fn = build_decl (FUNCTION_DECL, fn, args);
+ fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
enum machine_mode mode = GET_MODE (tmps[i]);
unsigned int bytelen = GET_MODE_SIZE (mode);
+ unsigned int adj_bytelen = bytelen;
rtx dest = dst;
/* Handle trailing fragments that run over the size of the struct. */
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
- {
- /* store_bit_field always takes its value from the lsb.
- Move the fragment to the lsb if it's not already there. */
- if (
-#ifdef BLOCK_REG_PADDING
- BLOCK_REG_PADDING (GET_MODE (orig_dst), type, i == start)
- == (BYTES_BIG_ENDIAN ? upward : downward)
-#else
- BYTES_BIG_ENDIAN
-#endif
- )
- {
- int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
- tmps[i] = expand_shift (RSHIFT_EXPR, mode, tmps[i],
- build_int_cst (NULL_TREE, shift),
- tmps[i], 0);
- }
- bytelen = ssize - bytepos;
- }
+ adj_bytelen = ssize - bytepos;
if (GET_CODE (dst) == CONCAT)
{
- if (bytepos + bytelen <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
+ if (bytepos + adj_bytelen
+ <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
dest = XEXP (dst, 0);
else if (bytepos >= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
{
{
enum machine_mode dest_mode = GET_MODE (dest);
enum machine_mode tmp_mode = GET_MODE (tmps[i]);
- int dest_size = GET_MODE_SIZE (dest_mode);
- int tmp_size = GET_MODE_SIZE (tmp_mode);
- gcc_assert (bytepos == 0
- && XVECLEN (src, 0)
- && dest_size == tmp_size);
+ gcc_assert (bytepos == 0 && XVECLEN (src, 0));
if (GET_MODE_ALIGNMENT (dest_mode)
>= GET_MODE_ALIGNMENT (tmp_mode))
{
- dest = assign_stack_temp (dest_mode, dest_size, 0);
+ dest = assign_stack_temp (dest_mode,
+ GET_MODE_SIZE (dest_mode),
+ 0);
emit_move_insn (adjust_address (dest,
tmp_mode,
bytepos),
}
else
{
- dest = assign_stack_temp (tmp_mode, tmp_size, 0);
+ dest = assign_stack_temp (tmp_mode,
+ GET_MODE_SIZE (tmp_mode),
+ 0);
emit_move_insn (dest, tmps[i]);
dst = adjust_address (dest, dest_mode, bytepos);
}
}
}
+ if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
+ {
+ /* store_bit_field always takes its value from the lsb.
+ Move the fragment to the lsb if it's not already there. */
+ if (
+#ifdef BLOCK_REG_PADDING
+ BLOCK_REG_PADDING (GET_MODE (orig_dst), type, i == start)
+ == (BYTES_BIG_ENDIAN ? upward : downward)
+#else
+ BYTES_BIG_ENDIAN
+#endif
+ )
+ {
+ int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
+ tmps[i] = expand_shift (RSHIFT_EXPR, mode, tmps[i],
+ build_int_cst (NULL_TREE, shift),
+ tmps[i], 0);
+ }
+ bytelen = adj_bytelen;
+ }
+
/* Optimize the access just a bit. */
if (MEM_P (dest)
&& (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (dest))
use_reg (call_fusage, reg);
}
}
+
+/* Return the defining gimple statement for SSA_NAME NAME if it is an
+ assigment and the code of the expresion on the RHS is CODE. Return
+ NULL otherwise. */
+
+static gimple
+get_def_for_expr (tree name, enum tree_code code)
+{
+ gimple def_stmt;
+
+ if (TREE_CODE (name) != SSA_NAME)
+ return NULL;
+
+ def_stmt = get_gimple_for_ssa_name (name);
+ if (!def_stmt
+ || gimple_assign_rhs_code (def_stmt) != code)
+ return NULL;
+
+ return def_stmt;
+}
\f
/* Determine whether the LEN bytes generated by CONSTFUN can be
rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
void *constfundata, unsigned int align, bool memsetp, int endp)
{
- struct store_by_pieces data;
+ struct store_by_pieces_d data;
if (len == 0)
{
static void
clear_by_pieces (rtx to, unsigned HOST_WIDE_INT len, unsigned int align)
{
- struct store_by_pieces data;
+ struct store_by_pieces_d data;
if (len == 0)
return;
rtx with BLKmode). ALIGN is maximum alignment we can assume. */
static void
-store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
+store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED,
unsigned int align ATTRIBUTE_UNUSED)
{
rtx to_addr = XEXP (data->to, 0);
static void
store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
- struct store_by_pieces *data)
+ struct store_by_pieces_d *data)
{
unsigned int size = GET_MODE_SIZE (mode);
rtx to1, cst;
for the function we use for block clears. The first time FOR_CALL
is true, we call assemble_external. */
-static GTY(()) tree block_clear_fn;
+tree block_clear_fn;
void
init_block_clear_fn (const char *asmspec)
integer_type_node, sizetype,
NULL_TREE);
- fn = build_decl (FUNCTION_DECL, fn, args);
+ fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
enum machine_mode srcmode;
REAL_VALUE_TYPE r;
int oldcost, newcost;
+ bool speed = optimize_insn_for_speed_p ();
REAL_VALUE_FROM_CONST_DOUBLE (r, y);
if (LEGITIMATE_CONSTANT_P (y))
- oldcost = rtx_cost (y, SET);
+ oldcost = rtx_cost (y, SET, speed);
else
- oldcost = rtx_cost (force_const_mem (dstmode, y), SET);
+ oldcost = rtx_cost (force_const_mem (dstmode, y), SET, speed);
for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode));
srcmode != orig_srcmode;
if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
continue;
/* This is valid, but may not be cheaper than the original. */
- newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+ newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET, speed);
if (oldcost < newcost)
continue;
}
{
trunc_y = force_const_mem (srcmode, trunc_y);
/* This is valid, but may not be cheaper than the original. */
- newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+ newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET, speed);
if (oldcost < newcost)
continue;
trunc_y = validize_mem (trunc_y);
/* Handle expand_expr of a complex value returning a CONCAT. */
if (GET_CODE (to_rtx) == CONCAT)
{
- if (TREE_CODE (TREE_TYPE (from)) == COMPLEX_TYPE)
+ if (COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (from))))
{
gcc_assert (bitpos == 0);
result = store_expr (from, to_rtx, false, nontemporal);
return;
}
+ else if (TREE_CODE (to) == MISALIGNED_INDIRECT_REF)
+ {
+ enum machine_mode mode, op_mode1;
+ enum insn_code icode;
+ rtx reg, addr, mem, insn;
+
+ reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ reg = force_not_mem (reg);
+
+ mode = TYPE_MODE (TREE_TYPE (to));
+ addr = expand_expr (TREE_OPERAND (to, 0), NULL_RTX, VOIDmode,
+ EXPAND_SUM);
+ addr = memory_address (mode, addr);
+ mem = gen_rtx_MEM (mode, addr);
+
+ set_mem_attributes (mem, to, 0);
+
+ icode = movmisalign_optab->handlers[mode].insn_code;
+ gcc_assert (icode != CODE_FOR_nothing);
+
+ op_mode1 = insn_data[icode].operand[1].mode;
+ if (! (*insn_data[icode].operand[1].predicate) (reg, op_mode1)
+ && op_mode1 != VOIDmode)
+ reg = copy_to_mode_reg (op_mode1, reg);
+
+ insn = GEN_FCN (icode) (mem, reg);
+ emit_insn (insn);
+ return;
+ }
+
/* If the rhs is a function call and its value is not an aggregate,
call the function before we start to compute the lhs.
This is needed for correct code for cases such as
Don't do this if TO is a VAR_DECL or PARM_DECL whose DECL_RTL is REG
since it might be a promoted variable where the zero- or sign- extension
needs to be done. Handling this in the normal way is safe because no
- computation is done before the call. */
+ computation is done before the call. The same is true for SSA names. */
if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from)
&& COMPLETE_TYPE_P (TREE_TYPE (from))
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
- && ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
- && REG_P (DECL_RTL (to))))
+ && ! (((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
+ && REG_P (DECL_RTL (to)))
+ || TREE_CODE (to) == SSA_NAME))
{
rtx value;
case REFERENCE_TYPE:
return 1;
+ case ERROR_MARK:
+ return 0;
+
case VOID_TYPE:
case METHOD_TYPE:
case FUNCTION_TYPE:
expand_normal (hi_index);
unsignedp = TYPE_UNSIGNED (domain);
- index = build_decl (VAR_DECL, NULL_TREE, domain);
+ index = build_decl (EXPR_LOCATION (exp),
+ VAR_DECL, NULL_TREE, domain);
index_r
= gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
HOST_WIDE_INT bitpos;
rtvec vector = NULL;
unsigned n_elts;
+ alias_set_type alias;
gcc_assert (eltmode != BLKmode);
if (need_to_clear && size > 0 && !vector)
{
if (REG_P (target))
- emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
+ emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
else
clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
cleared = 1;
if (!cleared && !vector && REG_P (target))
emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
+ if (MEM_P (target))
+ alias = MEM_ALIAS_SET (target);
+ else
+ alias = get_alias_set (elttype);
+
/* Store each element of the constructor into the corresponding
element of TARGET, determined by counting the elements. */
for (idx = 0, i = 0;
bitpos = eltpos * elt_size;
store_constructor_field (target, bitsize, bitpos,
value_mode, value, type,
- cleared, get_alias_set (elttype));
+ cleared, alias);
}
}
&& compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
{
rtx temp;
+ gimple nop_def;
/* If EXP is a NOP_EXPR of precision less than its mode, then that
implies a mask operation. If the precision is the same size as
the field we're storing into, that mask is redundant. This is
particularly common with bit field assignments generated by the
C front end. */
- if (TREE_CODE (exp) == NOP_EXPR)
+ nop_def = get_def_for_expr (exp, NOP_EXPR);
+ if (nop_def)
{
tree type = TREE_TYPE (exp);
if (INTEGRAL_TYPE_P (type)
&& TYPE_PRECISION (type) < GET_MODE_BITSIZE (TYPE_MODE (type))
&& bitsize == TYPE_PRECISION (type))
{
- type = TREE_TYPE (TREE_OPERAND (exp, 0));
+ tree op = gimple_assign_rhs1 (nop_def);
+ type = TREE_TYPE (op);
if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) >= bitsize)
- exp = TREE_OPERAND (exp, 0);
+ exp = op;
}
}
return exp;
}
-/* Given an expression EXP that may be a COMPONENT_REF or an ARRAY_REF,
- look for whether EXP or any nested component-refs within EXP is marked
- as PACKED. */
+/* Given an expression EXP that may be a COMPONENT_REF, an ARRAY_REF or an
+ ARRAY_RANGE_REF, look for whether EXP or any nested component-refs within
+ EXP is marked as PACKED. */
bool
contains_packed_reference (const_tree exp)
}
/* Return a tree of sizetype representing the size, in bytes, of the element
- of EXP, an ARRAY_REF. */
+ of EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */
tree
array_ref_element_size (tree exp)
}
/* Return a tree representing the lower bound of the array mentioned in
- EXP, an ARRAY_REF. */
+ EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */
tree
array_ref_low_bound (tree exp)
}
/* Return a tree representing the upper bound of the array mentioned in
- EXP, an ARRAY_REF. */
+ EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */
tree
array_ref_up_bound (tree exp)
return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
}
-/* Return 1 if T is an expression that get_inner_reference handles. */
+/* Alignment in bits the TARGET of an assignment may be assumed to have. */
-int
-handled_component_p (const_tree t)
+static unsigned HOST_WIDE_INT
+target_align (const_tree target)
{
- switch (TREE_CODE (t))
+ /* We might have a chain of nested references with intermediate misaligning
+ bitfields components, so need to recurse to find out. */
+
+ unsigned HOST_WIDE_INT this_align, outer_align;
+
+ switch (TREE_CODE (target))
{
case BIT_FIELD_REF:
+ return 1;
+
case COMPONENT_REF:
+ this_align = DECL_ALIGN (TREE_OPERAND (target, 1));
+ outer_align = target_align (TREE_OPERAND (target, 0));
+ return MIN (this_align, outer_align);
+
case ARRAY_REF:
case ARRAY_RANGE_REF:
+ this_align = TYPE_ALIGN (TREE_TYPE (target));
+ outer_align = target_align (TREE_OPERAND (target, 0));
+ return MIN (this_align, outer_align);
+
+ CASE_CONVERT:
+ case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- return 1;
+ this_align = TYPE_ALIGN (TREE_TYPE (target));
+ outer_align = target_align (TREE_OPERAND (target, 0));
+ return MAX (this_align, outer_align);
default:
- return 0;
+ return TYPE_ALIGN (TREE_TYPE (target));
}
}
+
\f
/* Given an rtx VALUE that may contain additions and multiplications, return
an equivalent value that just refers to a register, memory, or constant.
static unsigned HOST_WIDE_INT
highest_pow2_factor_for_target (const_tree target, const_tree exp)
{
- unsigned HOST_WIDE_INT target_align, factor;
-
- factor = highest_pow2_factor (exp);
- if (TREE_CODE (target) == COMPONENT_REF)
- target_align = DECL_ALIGN_UNIT (TREE_OPERAND (target, 1));
- else
- target_align = TYPE_ALIGN_UNIT (TREE_TYPE (target));
- return MAX (factor, target_align);
+ unsigned HOST_WIDE_INT talign = target_align (target) / BITS_PER_UNIT;
+ unsigned HOST_WIDE_INT factor = highest_pow2_factor (exp);
+
+ return MAX (factor, talign);
}
\f
/* Return &VAR expression for emulated thread local VAR. */
CONSTRUCTORs too, which should yield a memory reference for the
constructor's contents. Assume language specific tree nodes can
be expanded in some interesting way. */
+ gcc_assert (TREE_CODE (exp) < LAST_AND_UNUSED_TREE_CODE);
if (DECL_P (exp)
|| TREE_CODE (exp) == CONSTRUCTOR
- || TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE)
+ || TREE_CODE (exp) == COMPOUND_LITERAL_EXPR)
{
result = expand_expr (exp, target, tmode,
modifier == EXPAND_INITIALIZER
gcc_assert (inner != exp);
subtarget = offset || bitpos ? NULL_RTX : target;
+ /* For VIEW_CONVERT_EXPR, where the outer alignment is bigger than
+ inner alignment, force the inner to be sufficiently aligned. */
+ if (CONSTANT_CLASS_P (inner)
+ && TYPE_ALIGN (TREE_TYPE (inner)) < TYPE_ALIGN (TREE_TYPE (exp)))
+ {
+ inner = copy_node (inner);
+ TREE_TYPE (inner) = copy_node (TREE_TYPE (inner));
+ TYPE_ALIGN (TREE_TYPE (inner)) = TYPE_ALIGN (TREE_TYPE (exp));
+ TYPE_USER_ALIGN (TREE_TYPE (inner)) = 1;
+ }
result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier);
if (offset)
int ignore;
tree context, subexp0, subexp1;
bool reduce_bit_field;
+ gimple subexp0_def, subexp1_def;
+ tree top0, top1;
#define REDUCE_BIT_FIELD(expr) (reduce_bit_field \
? reduce_to_bit_field_precision ((expr), \
target, \
unsignedp = TYPE_UNSIGNED (type);
ignore = (target == const0_rtx
- || ((code == NOP_EXPR || code == CONVERT_EXPR
+ || ((CONVERT_EXPR_CODE_P (code)
|| code == COND_EXPR || code == VIEW_CONVERT_EXPR)
&& TREE_CODE (type) == VOID_TYPE));
}
case SSA_NAME:
- return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier,
- NULL);
+ /* ??? ivopts calls expander, without any preparation from
+ out-of-ssa. So fake instructions as if this was an access to the
+ base variable. This unnecessarily allocates a pseudo, see how we can
+ reuse it, if partition base vars have it set already. */
+ if (!currently_expanding_to_rtl)
+ return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier, NULL);
+ {
+ gimple g = get_gimple_for_ssa_name (exp);
+ if (g)
+ return expand_expr_real_1 (gimple_assign_rhs_to_tree (g), target,
+ tmode, modifier, NULL);
+ }
+ decl_rtl = get_rtx_for_ssa_name (exp);
+ exp = SSA_NAME_VAR (exp);
+ goto expand_decl_rtl;
case PARM_DECL:
case VAR_DECL:
case FUNCTION_DECL:
case RESULT_DECL:
decl_rtl = DECL_RTL (exp);
+ expand_decl_rtl:
gcc_assert (decl_rtl);
decl_rtl = copy_rtx (decl_rtl);
with non-BLKmode values. */
gcc_assert (GET_MODE (ret) != BLKmode);
- val = build_decl (VAR_DECL, NULL, TREE_TYPE (exp));
+ val = build_decl (EXPR_LOCATION (exp),
+ VAR_DECL, NULL, TREE_TYPE (exp));
DECL_ARTIFICIAL (val) = 1;
DECL_IGNORED_P (val) = 1;
TREE_OPERAND (exp, 0) = val;
/* Resolve the misalignment now, so that we don't have to remember
to resolve it later. Of course, this only works for reads. */
- /* ??? When we get around to supporting writes, we'll have to handle
- this in store_expr directly. The vectorizer isn't generating
- those yet, however. */
if (code == MISALIGNED_INDIRECT_REF)
{
int icode;
case ARRAY_RANGE_REF:
normal_inner_ref:
{
- enum machine_mode mode1;
+ enum machine_mode mode1, mode2;
HOST_WIDE_INT bitsize, bitpos;
tree offset;
- int volatilep = 0;
+ int volatilep = 0, must_force_mem;
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode1, &unsignedp, &volatilep, true);
- rtx orig_op0;
+ rtx orig_op0, memloc;
/* If we got back the original object, something is wrong. Perhaps
we are evaluating an expression too early. In any event, don't
/* If TEM's type is a union of variable size, pass TARGET to the inner
computation, since it will need a temporary and TARGET is known
to have to do. This occurs in unchecked conversion in Ada. */
-
orig_op0 = op0
= expand_expr (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
|| modifier == EXPAND_STACK_PARM)
? modifier : EXPAND_NORMAL);
- /* If this is a constant, put it into a register if it is a legitimate
- constant, OFFSET is 0, and we won't try to extract outside the
- register (in case we were passed a partially uninitialized object
- or a view_conversion to a larger size) or a BLKmode piece of it
- (e.g. if it is unchecked-converted to a record type in Ada). Force
- the constant to memory otherwise. */
- if (CONSTANT_P (op0))
- {
- enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
- if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
- && offset == 0
- && mode1 != BLKmode
- && bitpos + bitsize <= GET_MODE_BITSIZE (mode))
- op0 = force_reg (mode, op0);
- else
- op0 = validize_mem (force_const_mem (mode, op0));
- }
-
- /* Otherwise, if this object not in memory and we either have an
- offset, a BLKmode result, or a reference outside the object, put it
- there. Such cases can occur in Ada if we have unchecked conversion
- of an expression from a scalar type to an array or record type or
- for an ARRAY_RANGE_REF whose type is BLKmode. */
- else if (!MEM_P (op0)
- && (offset != 0
- || mode1 == BLKmode
- || (bitpos + bitsize
- > GET_MODE_BITSIZE (GET_MODE (op0)))))
+ mode2
+ = CONSTANT_P (op0) ? TYPE_MODE (TREE_TYPE (tem)) : GET_MODE (op0);
+
+ /* If we have either an offset, a BLKmode result, or a reference
+ outside the underlying object, we must force it to memory.
+ Such a case can occur in Ada if we have unchecked conversion
+ of an expression from a scalar type to an aggregate type or
+ for an ARRAY_RANGE_REF whose type is BLKmode, or if we were
+ passed a partially uninitialized object or a view-conversion
+ to a larger size. */
+ must_force_mem = (offset
+ || mode1 == BLKmode
+ || bitpos + bitsize > GET_MODE_BITSIZE (mode2));
+
+ /* If this is a constant, put it in a register if it is a legitimate
+ constant and we don't need a memory reference. */
+ if (CONSTANT_P (op0)
+ && mode2 != BLKmode
+ && LEGITIMATE_CONSTANT_P (op0)
+ && !must_force_mem)
+ op0 = force_reg (mode2, op0);
+
+ /* Otherwise, if this is a constant, try to force it to the constant
+ pool. Note that back-ends, e.g. MIPS, may refuse to do so if it
+ is a legitimate constant. */
+ else if (CONSTANT_P (op0) && (memloc = force_const_mem (mode2, op0)))
+ op0 = validize_mem (memloc);
+
+ /* Otherwise, if this is a constant or the object is not in memory
+ and need be, put it there. */
+ else if (CONSTANT_P (op0) || (!MEM_P (op0) && must_force_mem))
{
tree nt = build_qualified_type (TREE_TYPE (tem),
(TYPE_QUALS (TREE_TYPE (tem))
| TYPE_QUAL_CONST));
- rtx memloc = assign_temp (nt, 1, 1, 1);
-
+ memloc = assign_temp (nt, 1, 1, 1);
emit_move_insn (memloc, op0);
op0 = memloc;
}
- if (offset != 0)
+ if (offset)
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
EXPAND_SUM);
&& (attr = lookup_attribute ("error",
DECL_ATTRIBUTES (fndecl))) != NULL)
error ("%Kcall to %qs declared with attribute error: %s",
- exp, lang_hooks.decl_printable_name (fndecl, 1),
+ exp, identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 1)),
TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
if (fndecl
&& (attr = lookup_attribute ("warning",
DECL_ATTRIBUTES (fndecl))) != NULL)
- warning (0, "%Kcall to %qs declared with attribute warning: %s",
- exp, lang_hooks.decl_printable_name (fndecl, 1),
- TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+ warning_at (tree_nonartificial_location (exp),
+ 0, "%Kcall to %qs declared with attribute warning: %s",
+ exp, identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 1)),
+ TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
/* Check for a built-in function. */
if (fndecl && DECL_BUILT_IN (fndecl))
{
- if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND)
- return lang_hooks.expand_expr (exp, original_target,
- tmode, modifier, alt_rtl);
- else
- return expand_builtin (exp, target, subtarget, tmode, ignore);
+ gcc_assert (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_FRONTEND);
+ return expand_builtin (exp, target, subtarget, tmode, ignore);
}
}
return expand_call (exp, target, ignore);
}
if (!op0)
- op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+ op0 = expand_expr (TREE_OPERAND (exp, 0),
+ NULL_RTX, VOIDmode, modifier);
/* If the input and output modes are both the same, we are done. */
if (mode == GET_MODE (op0))
/* If neither mode is BLKmode, and both modes are the same size
then we can use gen_lowpart. */
else if (mode != BLKmode && GET_MODE (op0) != BLKmode
- && GET_MODE_SIZE (mode) == GET_MODE_SIZE (GET_MODE (op0)))
+ && GET_MODE_SIZE (mode) == GET_MODE_SIZE (GET_MODE (op0))
+ && !COMPLEX_MODE_P (GET_MODE (op0)))
{
if (GET_CODE (op0) == SUBREG)
op0 = force_reg (GET_MODE (op0), op0);
/* Even though the sizetype mode and the pointer's mode can be different
expand is able to handle this correctly and get the correct result out
of the PLUS_EXPR code. */
+ /* Make sure to sign-extend the sizetype offset in a POINTER_PLUS_EXPR
+ if sizetype precision is smaller than pointer precision. */
+ if (TYPE_PRECISION (sizetype) < TYPE_PRECISION (type))
+ exp = build2 (PLUS_EXPR, type,
+ TREE_OPERAND (exp, 0),
+ fold_convert (type,
+ fold_convert (ssizetype,
+ TREE_OPERAND (exp, 1))));
case PLUS_EXPR:
/* Check if this is a case for multiplication and addition. */
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == FIXED_POINT_TYPE)
- && TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR)
+ && (subexp0_def = get_def_for_expr (TREE_OPERAND (exp, 0),
+ MULT_EXPR)))
{
tree subsubexp0, subsubexp1;
- enum tree_code code0, code1, this_code;
+ gimple subsubexp0_def, subsubexp1_def;
+ enum tree_code this_code;
- subexp0 = TREE_OPERAND (exp, 0);
- subsubexp0 = TREE_OPERAND (subexp0, 0);
- subsubexp1 = TREE_OPERAND (subexp0, 1);
- code0 = TREE_CODE (subsubexp0);
- code1 = TREE_CODE (subsubexp1);
this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
: FIXED_CONVERT_EXPR;
- if (code0 == this_code && code1 == this_code
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+ subsubexp0 = gimple_assign_rhs1 (subexp0_def);
+ subsubexp0_def = get_def_for_expr (subsubexp0, this_code);
+ subsubexp1 = gimple_assign_rhs2 (subexp0_def);
+ subsubexp1_def = get_def_for_expr (subsubexp1, this_code);
+ if (subsubexp0_def && subsubexp1_def
+ && (top0 = gimple_assign_rhs1 (subsubexp0_def))
+ && (top1 = gimple_assign_rhs1 (subsubexp1_def))
+ && (TYPE_PRECISION (TREE_TYPE (top0))
< TYPE_PRECISION (TREE_TYPE (subsubexp0)))
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
- && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
- == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
+ && (TYPE_PRECISION (TREE_TYPE (top0))
+ == TYPE_PRECISION (TREE_TYPE (top1)))
+ && (TYPE_UNSIGNED (TREE_TYPE (top0))
+ == TYPE_UNSIGNED (TREE_TYPE (top1))))
{
- tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
+ tree op0type = TREE_TYPE (top0);
enum machine_mode innermode = TYPE_MODE (op0type);
bool zextend_p = TYPE_UNSIGNED (op0type);
bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
&& (optab_handler (this_optab, mode)->insn_code
!= CODE_FOR_nothing))
{
- expand_operands (TREE_OPERAND (subsubexp0, 0),
- TREE_OPERAND (subsubexp1, 0),
- NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+ EXPAND_NORMAL);
op2 = expand_expr (TREE_OPERAND (exp, 1), subtarget,
VOIDmode, EXPAND_NORMAL);
temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
|| mode != ptr_mode)
{
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
- subtarget, &op0, &op1, 0);
+ subtarget, &op0, &op1, EXPAND_NORMAL);
if (op0 == const0_rtx)
return op1;
if (op1 == const0_rtx)
/* Check if this is a case for multiplication and subtraction. */
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == FIXED_POINT_TYPE)
- && TREE_CODE (TREE_OPERAND (exp, 1)) == MULT_EXPR)
+ && (subexp1_def = get_def_for_expr (TREE_OPERAND (exp, 1),
+ MULT_EXPR)))
{
tree subsubexp0, subsubexp1;
- enum tree_code code0, code1, this_code;
+ gimple subsubexp0_def, subsubexp1_def;
+ enum tree_code this_code;
- subexp1 = TREE_OPERAND (exp, 1);
- subsubexp0 = TREE_OPERAND (subexp1, 0);
- subsubexp1 = TREE_OPERAND (subexp1, 1);
- code0 = TREE_CODE (subsubexp0);
- code1 = TREE_CODE (subsubexp1);
this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
: FIXED_CONVERT_EXPR;
- if (code0 == this_code && code1 == this_code
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+ subsubexp0 = gimple_assign_rhs1 (subexp1_def);
+ subsubexp0_def = get_def_for_expr (subsubexp0, this_code);
+ subsubexp1 = gimple_assign_rhs2 (subexp1_def);
+ subsubexp1_def = get_def_for_expr (subsubexp1, this_code);
+ if (subsubexp0_def && subsubexp1_def
+ && (top0 = gimple_assign_rhs1 (subsubexp0_def))
+ && (top1 = gimple_assign_rhs1 (subsubexp1_def))
+ && (TYPE_PRECISION (TREE_TYPE (top0))
< TYPE_PRECISION (TREE_TYPE (subsubexp0)))
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
- && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
- == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
+ && (TYPE_PRECISION (TREE_TYPE (top0))
+ == TYPE_PRECISION (TREE_TYPE (top1)))
+ && (TYPE_UNSIGNED (TREE_TYPE (top0))
+ == TYPE_UNSIGNED (TREE_TYPE (top1))))
{
- tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
+ tree op0type = TREE_TYPE (top0);
enum machine_mode innermode = TYPE_MODE (op0type);
bool zextend_p = TYPE_UNSIGNED (op0type);
bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
&& (optab_handler (this_optab, mode)->insn_code
!= CODE_FOR_nothing))
{
- expand_operands (TREE_OPERAND (subsubexp0, 0),
- TREE_OPERAND (subsubexp1, 0),
- NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+ EXPAND_NORMAL);
op2 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
VOIDmode, EXPAND_NORMAL);
temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
subexp0 = TREE_OPERAND (exp, 0);
subexp1 = TREE_OPERAND (exp, 1);
+ subexp0_def = get_def_for_expr (subexp0, NOP_EXPR);
+ subexp1_def = get_def_for_expr (subexp1, NOP_EXPR);
+ top0 = top1 = NULL_TREE;
+
/* First, check if we have a multiplication of one signed and one
unsigned operand. */
- if (TREE_CODE (subexp0) == NOP_EXPR
- && TREE_CODE (subexp1) == NOP_EXPR
+ if (subexp0_def
+ && (top0 = gimple_assign_rhs1 (subexp0_def))
+ && subexp1_def
+ && (top1 = gimple_assign_rhs1 (subexp1_def))
&& TREE_CODE (type) == INTEGER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
- < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp1, 0))))
- && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
- != TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp1, 0)))))
+ && (TYPE_PRECISION (TREE_TYPE (top0))
+ < TYPE_PRECISION (TREE_TYPE (subexp0)))
+ && (TYPE_PRECISION (TREE_TYPE (top0))
+ == TYPE_PRECISION (TREE_TYPE (top1)))
+ && (TYPE_UNSIGNED (TREE_TYPE (top0))
+ != TYPE_UNSIGNED (TREE_TYPE (top1))))
{
enum machine_mode innermode
- = TYPE_MODE (TREE_TYPE (TREE_OPERAND (subexp0, 0)));
+ = TYPE_MODE (TREE_TYPE (top0));
this_optab = usmul_widen_optab;
if (mode == GET_MODE_WIDER_MODE (innermode))
{
if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
{
- if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))))
- expand_operands (TREE_OPERAND (subexp0, 0),
- TREE_OPERAND (subexp1, 0),
- NULL_RTX, &op0, &op1, 0);
+ if (TYPE_UNSIGNED (TREE_TYPE (top0)))
+ expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+ EXPAND_NORMAL);
else
- expand_operands (TREE_OPERAND (subexp0, 0),
- TREE_OPERAND (subexp1, 0),
- NULL_RTX, &op1, &op0, 0);
+ expand_operands (top0, top1, NULL_RTX, &op1, &op0,
+ EXPAND_NORMAL);
goto binop3;
}
}
}
- /* Check for a multiplication with matching signedness. */
- else if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
+ /* Check for a multiplication with matching signedness. If
+ valid, TOP0 and TOP1 were set in the previous if
+ condition. */
+ else if (top0
&& TREE_CODE (type) == INTEGER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
- < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
- && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
- && int_fits_type_p (TREE_OPERAND (exp, 1),
- TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
+ && (TYPE_PRECISION (TREE_TYPE (top0))
+ < TYPE_PRECISION (TREE_TYPE (subexp0)))
+ && ((TREE_CODE (subexp1) == INTEGER_CST
+ && int_fits_type_p (subexp1, TREE_TYPE (top0))
/* Don't use a widening multiply if a shift will do. */
- && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+ && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (subexp1)))
> HOST_BITS_PER_WIDE_INT)
- || exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
+ || exact_log2 (TREE_INT_CST_LOW (subexp1)) < 0))
||
- (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
- && (TYPE_PRECISION (TREE_TYPE
- (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
- == TYPE_PRECISION (TREE_TYPE
- (TREE_OPERAND
- (TREE_OPERAND (exp, 0), 0))))
+ (top1
+ && (TYPE_PRECISION (TREE_TYPE (top1))
+ == TYPE_PRECISION (TREE_TYPE (top0))
/* If both operands are extended, they must either both
be zero-extended or both be sign-extended. */
- && (TYPE_UNSIGNED (TREE_TYPE
- (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
- == TYPE_UNSIGNED (TREE_TYPE
- (TREE_OPERAND
- (TREE_OPERAND (exp, 0), 0)))))))
+ && (TYPE_UNSIGNED (TREE_TYPE (top1))
+ == TYPE_UNSIGNED (TREE_TYPE (top0)))))))
{
- tree op0type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
+ tree op0type = TREE_TYPE (top0);
enum machine_mode innermode = TYPE_MODE (op0type);
bool zextend_p = TYPE_UNSIGNED (op0type);
optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
{
if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
{
- if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
- expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
- TREE_OPERAND (exp, 1),
- NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ if (TREE_CODE (subexp1) == INTEGER_CST)
+ expand_operands (top0, subexp1, NULL_RTX, &op0, &op1,
+ EXPAND_NORMAL);
else
- expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
- TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
- NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+ EXPAND_NORMAL);
goto binop3;
}
else if (optab_handler (other_optab, mode)->insn_code != CODE_FOR_nothing
&& innermode == word_mode)
{
rtx htem, hipart;
- op0 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
- if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
+ op0 = expand_normal (top0);
+ if (TREE_CODE (subexp1) == INTEGER_CST)
op1 = convert_modes (innermode, mode,
- expand_normal (TREE_OPERAND (exp, 1)),
- unsignedp);
+ expand_normal (subexp1), unsignedp);
else
- op1 = expand_normal (TREE_OPERAND (TREE_OPERAND (exp, 1), 0));
+ op1 = expand_normal (top1);
temp = expand_binop (mode, other_optab, op0, op1, target,
unsignedp, OPTAB_LIB_WIDEN);
hipart = gen_highpart (innermode, temp);
}
}
}
- expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
- subtarget, &op0, &op1, 0);
+ expand_operands (subexp0, subexp1, subtarget, &op0, &op1, EXPAND_NORMAL);
return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
case TRUNC_DIV_EXPR:
then if the divisor is constant can optimize the case
where some terms of the dividend have coeffs divisible by it. */
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
- subtarget, &op0, &op1, 0);
+ subtarget, &op0, &op1, EXPAND_NORMAL);
return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
case RDIV_EXPR:
if (modifier == EXPAND_STACK_PARM)
target = 0;
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
- subtarget, &op0, &op1, 0);
+ subtarget, &op0, &op1, EXPAND_NORMAL);
return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
case FIXED_CONVERT_EXPR:
&& REGNO (target) < FIRST_PSEUDO_REGISTER))
target = gen_reg_rtx (mode);
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
- target, &op0, &op1, 0);
+ target, &op0, &op1, EXPAND_NORMAL);
/* First try to do it with a special MIN or MAX instruction.
If that does not win, use a conditional jump to select the proper
case LTGT_EXPR:
temp = do_store_flag (exp,
modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
- tmode != VOIDmode ? tmode : mode, 0);
+ tmode != VOIDmode ? tmode : mode);
if (temp != 0)
return temp;
/* Lowered by gimplify.c. */
gcc_unreachable ();
- case CHANGE_DYNAMIC_TYPE_EXPR:
- /* This is ignored at the RTL level. The tree level set
- DECL_POINTER_ALIAS_SET of any variable to be 0, which is
- overkill for the RTL layer but is all that we can
- represent. */
- return const0_rtx;
-
case EXC_PTR_EXPR:
return get_exception_pointer ();
tree oprnd0 = TREE_OPERAND (exp, 0);
tree oprnd1 = TREE_OPERAND (exp, 1);
- expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+ expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
target = expand_widen_pattern_expr (exp, op0, NULL_RTX, op1,
target, unsignedp);
return target;
case VEC_EXTRACT_ODD_EXPR:
{
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
- NULL_RTX, &op0, &op1, 0);
+ NULL_RTX, &op0, &op1, EXPAND_NORMAL);
this_optab = optab_for_tree_code (code, type, optab_default);
temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
OPTAB_WIDEN);
case VEC_INTERLEAVE_LOW_EXPR:
{
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
- NULL_RTX, &op0, &op1, 0);
+ NULL_RTX, &op0, &op1, EXPAND_NORMAL);
this_optab = optab_for_tree_code (code, type, optab_default);
temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
OPTAB_WIDEN);
tree oprnd0 = TREE_OPERAND (exp, 0);
tree oprnd1 = TREE_OPERAND (exp, 1);
- expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+ expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX,
target, unsignedp);
gcc_assert (target);
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
goto binop;
+ case COMPOUND_LITERAL_EXPR:
+ {
+ /* Initialize the anonymous variable declared in the compound
+ literal, then return the variable. */
+ tree decl = COMPOUND_LITERAL_EXPR_DECL (exp);
+
+ /* Create RTL for this variable. */
+ if (!DECL_RTL_SET_P (decl))
+ {
+ if (DECL_HARD_REGISTER (decl))
+ /* The user specified an assembler name for this variable.
+ Set that up now. */
+ rest_of_decl_compilation (decl, 0, 0);
+ else
+ expand_decl (decl);
+ }
+
+ return expand_expr_real (decl, original_target, tmode,
+ modifier, alt_rtl);
+ }
+
default:
- return lang_hooks.expand_expr (exp, original_target, tmode,
- modifier, alt_rtl);
+ gcc_unreachable ();
}
/* Here to do an ordinary binary operator. */
binop:
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
- subtarget, &op0, &op1, 0);
+ subtarget, &op0, &op1, EXPAND_NORMAL);
binop2:
this_optab = optab_for_tree_code (code, type, optab_default);
binop3:
If TARGET is nonzero, store the result there if convenient.
- If ONLY_CHEAP is nonzero, only do this if it is likely to be very
- cheap.
-
Return zero if there is no suitable set-flag instruction
available on this machine.
set/jump/set sequence. */
static rtx
-do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
+do_store_flag (tree exp, rtx target, enum machine_mode mode)
{
enum rtx_code code;
tree arg0, arg1, type;
int invert = 0;
int unsignedp;
rtx op0, op1;
- enum insn_code icode;
rtx subtarget = target;
rtx result, label;
if (! can_compare_p (code, operand_mode, ccp_store_flag))
return 0;
- icode = setcc_gen_code[(int) code];
-
- if (icode == CODE_FOR_nothing)
- {
- enum machine_mode wmode;
-
- for (wmode = operand_mode;
- icode == CODE_FOR_nothing && wmode != VOIDmode;
- wmode = GET_MODE_WIDER_MODE (wmode))
- icode = optab_handler (cstore_optab, wmode)->insn_code;
- }
-
- if (icode == CODE_FOR_nothing
- || (only_cheap && insn_data[(int) icode].operand[0].mode != mode))
- {
- /* We can only do this if it is one of the special cases that
- can be handled without an scc insn. */
- if ((code == LT && integer_zerop (arg1))
- || (! only_cheap && code == GE && integer_zerop (arg1)))
- ;
- else if (! only_cheap && (code == NE || code == EQ)
- && TREE_CODE (type) != REAL_TYPE
- && ((optab_handler (abs_optab, operand_mode)->insn_code
- != CODE_FOR_nothing)
- || (optab_handler (ffs_optab, operand_mode)->insn_code
- != CODE_FOR_nothing)))
- ;
- else
- return 0;
- }
-
if (! get_subtarget (target)
|| GET_MODE (subtarget) != operand_mode)
subtarget = 0;
- expand_operands (arg0, arg1, subtarget, &op0, &op1, 0);
+ expand_operands (arg0, arg1, subtarget, &op0, &op1, EXPAND_NORMAL);
if (target == 0)
target = gen_reg_rtx (mode);
# define CODE_FOR_casesi CODE_FOR_nothing
#endif
-/* If the machine does not have a case insn that compares the bounds,
- this means extra overhead for dispatch tables, which raises the
- threshold for using them. */
-#ifndef CASE_VALUES_THRESHOLD
-#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
-#endif /* CASE_VALUES_THRESHOLD */
-
-unsigned int
-case_values_threshold (void)
-{
- return CASE_VALUES_THRESHOLD;
-}
-
/* Attempt to generate a casesi instruction. Returns 1 if successful,
0 otherwise (i.e. if there is no casesi instruction). */
int