/* Convert tree expression to rtl instructions, for GNU compiler.
- Copyright (C) 1988-2019 Free Software Foundation, Inc.
+ Copyright (C) 1988-2020 Free Software Foundation, Inc.
This file is part of GCC.
int cse_not_expected;
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,
- unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT);
+static bool emit_block_move_via_pattern (rtx, rtx, rtx, unsigned, unsigned,
+ HOST_WIDE_INT, unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, bool);
static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
static rtx_insn *compress_float_constant (rtx, rtx);
if (VECTOR_MODE_P (to_mode) || VECTOR_MODE_P (from_mode))
{
+ if (GET_MODE_UNIT_PRECISION (to_mode)
+ > GET_MODE_UNIT_PRECISION (from_mode))
+ {
+ optab op = unsignedp ? zext_optab : sext_optab;
+ insn_code icode = convert_optab_handler (op, to_mode, from_mode);
+ if (icode != CODE_FOR_nothing)
+ {
+ emit_unop_insn (icode, to, from,
+ unsignedp ? ZERO_EXTEND : SIGN_EXTEND);
+ return;
+ }
+ }
+
+ if (GET_MODE_UNIT_PRECISION (to_mode)
+ < GET_MODE_UNIT_PRECISION (from_mode))
+ {
+ insn_code icode = convert_optab_handler (trunc_optab,
+ to_mode, from_mode);
+ if (icode != CODE_FOR_nothing)
+ {
+ emit_unop_insn (icode, to, from, TRUNCATE);
+ return;
+ }
+ }
+
gcc_assert (known_eq (GET_MODE_BITSIZE (from_mode),
GET_MODE_BITSIZE (to_mode)));
}
else
{
- scalar_mode intermediate;
rtx tmp;
int shift_amount;
unsigned int expected_align, HOST_WIDE_INT expected_size,
unsigned HOST_WIDE_INT min_size,
unsigned HOST_WIDE_INT max_size,
- unsigned HOST_WIDE_INT probable_max_size)
+ unsigned HOST_WIDE_INT probable_max_size,
+ bool bail_out_libcall, bool *is_move_done,
+ bool might_overlap)
{
int may_use_call;
rtx retval = 0;
unsigned int align;
+ if (is_move_done)
+ *is_move_done = true;
+
gcc_assert (size);
if (CONST_INT_P (size) && INTVAL (size) == 0)
return 0;
set_mem_size (y, const_size);
}
- if (CONST_INT_P (size) && can_move_by_pieces (INTVAL (size), align))
- move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN);
- else if (emit_block_move_via_movmem (x, y, size, align,
+ bool pieces_ok = CONST_INT_P (size)
+ && can_move_by_pieces (INTVAL (size), align);
+ bool pattern_ok = false;
+
+ if (!pieces_ok || might_overlap)
+ {
+ pattern_ok
+ = emit_block_move_via_pattern (x, y, size, align,
expected_align, expected_size,
- min_size, max_size, probable_max_size))
+ min_size, max_size, probable_max_size,
+ might_overlap);
+ if (!pattern_ok && might_overlap)
+ {
+ /* Do not try any of the other methods below as they are not safe
+ for overlapping moves. */
+ *is_move_done = false;
+ return retval;
+ }
+ }
+
+ if (pattern_ok)
;
- else if (may_use_call
+ else if (pieces_ok)
+ move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN);
+ else if (may_use_call && !might_overlap
&& ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))
&& ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y)))
{
+ if (bail_out_libcall)
+ {
+ if (is_move_done)
+ *is_move_done = false;
+ return retval;
+ }
+
if (may_use_call < 0)
return pc_rtx;
retval = emit_block_copy_via_libcall (x, y, size,
method == BLOCK_OP_TAILCALL);
}
-
+ else if (might_overlap)
+ *is_move_done = false;
else
emit_block_move_via_loop (x, y, size, align);
static bool
block_move_libcall_safe_for_call_parm (void)
{
-#if defined (REG_PARM_STACK_SPACE)
tree fn;
-#endif
/* If arguments are pushed on the stack, then they're safe. */
if (PUSH_ARGS)
{
CUMULATIVE_ARGS args_so_far_v;
cumulative_args_t args_so_far;
- tree fn, arg;
+ tree arg;
fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
INIT_CUMULATIVE_ARGS (args_so_far_v, TREE_TYPE (fn), NULL_RTX, 0, 3);
for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
{
machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
- rtx tmp = targetm.calls.function_arg (args_so_far, mode,
- NULL_TREE, true);
+ function_arg_info arg_info (mode, /*named=*/true);
+ rtx tmp = targetm.calls.function_arg (args_so_far, arg_info);
if (!tmp || !REG_P (tmp))
return false;
- if (targetm.calls.arg_partial_bytes (args_so_far, mode, NULL, 1))
+ if (targetm.calls.arg_partial_bytes (args_so_far, arg_info))
return false;
- targetm.calls.function_arg_advance (args_so_far, mode,
- NULL_TREE, true);
+ targetm.calls.function_arg_advance (args_so_far, arg_info);
}
}
return true;
}
-/* A subroutine of emit_block_move. Expand a movmem pattern;
- return true if successful. */
+/* A subroutine of emit_block_move. Expand a cpymem or movmem pattern;
+ return true if successful.
+
+ X is the destination of the copy or move.
+ Y is the source of the copy or move.
+ SIZE is the size of the block to be moved.
+
+ MIGHT_OVERLAP indicates this originated with expansion of a
+ builtin_memmove() and the source and destination blocks may
+ overlap.
+ */
static bool
-emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
- unsigned int expected_align, HOST_WIDE_INT expected_size,
- unsigned HOST_WIDE_INT min_size,
- unsigned HOST_WIDE_INT max_size,
- unsigned HOST_WIDE_INT probable_max_size)
+emit_block_move_via_pattern (rtx x, rtx y, rtx size, unsigned int align,
+ unsigned int expected_align,
+ HOST_WIDE_INT expected_size,
+ unsigned HOST_WIDE_INT min_size,
+ unsigned HOST_WIDE_INT max_size,
+ unsigned HOST_WIDE_INT probable_max_size,
+ bool might_overlap)
{
- int save_volatile_ok = volatile_ok;
-
if (expected_align < align)
expected_align = align;
if (expected_size != -1)
}
/* Since this is a move insn, we don't care about volatility. */
- volatile_ok = 1;
+ temporary_volatile_ok v (true);
/* Try the most limited insn first, because there's no point
including more than one in the machine description unless
FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_INT)
{
scalar_int_mode mode = mode_iter.require ();
- enum insn_code code = direct_optab_handler (movmem_optab, mode);
+ enum insn_code code;
+ if (might_overlap)
+ code = direct_optab_handler (movmem_optab, mode);
+ else
+ code = direct_optab_handler (cpymem_optab, mode);
if (code != CODE_FOR_nothing
/* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT
|| max_size <= (GET_MODE_MASK (mode) >> 1)
|| GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
{
- struct expand_operand ops[9];
+ class expand_operand ops[9];
unsigned int nops;
/* ??? When called via emit_block_move_for_call, it'd be
create_fixed_operand (&ops[8], NULL);
}
if (maybe_expand_insn (code, nops, ops))
- {
- volatile_ok = save_volatile_ok;
- return true;
- }
+ return true;
}
}
- volatile_ok = save_volatile_ok;
return false;
}
if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
target = NULL_RTX;
- struct expand_operand ops[5];
+ class expand_operand ops[5];
create_output_operand (&ops[0], target, insn_mode);
create_fixed_operand (&ops[1], arg1_rtx);
create_fixed_operand (&ops[2], arg2_rtx);
|| max_size <= (GET_MODE_MASK (mode) >> 1)
|| GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
{
- struct expand_operand ops[9];
+ class expand_operand ops[9];
unsigned int nops;
nops = insn_data[(int) code].n_generator_args;
rtx_insn *ret;
/* For memory to memory moves, optimal behavior can be had with the
- existing block move logic. */
+ existing block move logic. But use normal expansion if optimizing
+ for size. */
if (MEM_P (x) && MEM_P (y))
{
emit_block_move (x, y, gen_int_mode (GET_MODE_SIZE (mode), Pmode),
- BLOCK_OP_NO_LIBCALL);
+ (optimize_insn_for_speed_p()
+ ? BLOCK_OP_NO_LIBCALL : BLOCK_OP_NORMAL));
return get_last_insn ();
}
icode = optab_handler (push_optab, mode);
if (icode != CODE_FOR_nothing)
{
- struct expand_operand ops[1];
+ class expand_operand ops[1];
create_input_operand (&ops[0], x, mode);
if (maybe_expand_insn (icode, 1, ops))
/* Get the address of the stack space.
In this case, we do not deal with EXTRA separately.
A single stack adjust will do. */
- poly_int64 offset;
+ poly_int64 const_args_so_far;
if (! args_addr)
{
temp = push_block (size, extra, where_pad == PAD_DOWNWARD);
extra = 0;
}
- else if (poly_int_rtx_p (args_so_far, &offset))
+ else if (poly_int_rtx_p (args_so_far, &const_args_so_far))
temp = memory_address (BLKmode,
plus_constant (Pmode, args_addr,
- skip + offset));
+ skip + const_args_so_far));
else
temp = memory_address (BLKmode,
plus_constant (Pmode,
{
/* Scalar partly in registers. This case is only supported
for fixed-wdth modes. */
- int size = GET_MODE_SIZE (mode).to_constant ();
- size /= UNITS_PER_WORD;
+ int num_words = GET_MODE_SIZE (mode).to_constant ();
+ num_words /= UNITS_PER_WORD;
int i;
int not_stack;
/* # bytes of start of argument
/* Loop over all the words allocated on the stack for this arg. */
/* We can do it by words, because any scalar bigger than a word
has a size a multiple of a word. */
- for (i = size - 1; i >= not_stack; i--)
+ for (i = num_words - 1; i >= not_stack; i--)
if (i >= not_stack + offset)
if (!emit_push_insn (operand_subword_force (x, i, mode),
word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
*bitend = *bitstart + tree_to_poly_uint64 (DECL_SIZE (repr)) - 1;
}
-/* Returns true if ADDR is an ADDR_EXPR of a DECL that does not reside
- in memory and has non-BLKmode. DECL_RTL must not be a MEM; if
- DECL_RTL was not set yet, return NORTL. */
+/* Returns true if BASE is a DECL that does not reside in memory and
+ has non-BLKmode. DECL_RTL must not be a MEM; if
+ DECL_RTL was not set yet, return false. */
static inline bool
-addr_expr_of_non_mem_decl_p_1 (tree addr, bool nortl)
+non_mem_decl_p (tree base)
{
- if (TREE_CODE (addr) != ADDR_EXPR)
- return false;
-
- tree base = TREE_OPERAND (addr, 0);
-
if (!DECL_P (base)
|| TREE_ADDRESSABLE (base)
|| DECL_MODE (base) == BLKmode)
return false;
if (!DECL_RTL_SET_P (base))
- return nortl;
+ return false;
return (!MEM_P (DECL_RTL (base)));
}
-/* Returns true if the MEM_REF REF refers to an object that does not
+/* Returns true if REF refers to an object that does not
reside in memory and has non-BLKmode. */
static inline bool
mem_ref_refers_to_non_mem_p (tree ref)
{
- tree base = TREE_OPERAND (ref, 0);
- return addr_expr_of_non_mem_decl_p_1 (base, false);
+ tree base;
+
+ if (TREE_CODE (ref) == MEM_REF
+ || TREE_CODE (ref) == TARGET_MEM_REF)
+ {
+ tree addr = TREE_OPERAND (ref, 0);
+
+ if (TREE_CODE (addr) != ADDR_EXPR)
+ return false;
+
+ base = TREE_OPERAND (addr, 0);
+ }
+ else
+ base = ref;
+
+ return non_mem_decl_p (base);
}
/* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL
/* Handle misaligned stores. */
mode = TYPE_MODE (TREE_TYPE (to));
if ((TREE_CODE (to) == MEM_REF
- || TREE_CODE (to) == TARGET_MEM_REF)
+ || TREE_CODE (to) == TARGET_MEM_REF
+ || DECL_P (to))
&& mode != BLKmode
&& !mem_ref_refers_to_non_mem_p (to)
&& ((align = get_object_alignment (to))
if (icode != CODE_FOR_nothing)
{
- struct expand_operand ops[2];
+ class expand_operand ops[2];
create_fixed_operand (&ops[0], mem);
create_input_operand (&ops[1], reg, mode);
}
else
{
+ machine_mode from_mode
+ = GET_MODE (result) == VOIDmode
+ ? TYPE_MODE (TREE_TYPE (from))
+ : GET_MODE (result);
rtx from_rtx;
if (MEM_P (result))
from_rtx = change_address (result, to_mode, NULL_RTX);
else
from_rtx
- = simplify_gen_subreg (to_mode, result,
- TYPE_MODE (TREE_TYPE (from)), 0);
+ = simplify_gen_subreg (to_mode, result, from_mode, 0);
if (from_rtx)
{
emit_move_insn (XEXP (to_rtx, 0),
}
else
{
- machine_mode to_mode
- = GET_MODE_INNER (GET_MODE (to_rtx));
+ to_mode = GET_MODE_INNER (to_mode);
rtx from_real
- = simplify_gen_subreg (to_mode, result,
- TYPE_MODE (TREE_TYPE (from)),
- 0);
+ = simplify_gen_subreg (to_mode, result, from_mode, 0);
rtx from_imag
- = simplify_gen_subreg (to_mode, result,
- TYPE_MODE (TREE_TYPE (from)),
+ = simplify_gen_subreg (to_mode, result, from_mode,
GET_MODE_SIZE (to_mode));
if (!from_real || !from_imag)
goto concat_store_slow;
else
{
concat_store_slow:;
- rtx temp = assign_stack_temp (to_mode,
+ rtx temp = assign_stack_temp (GET_MODE (to_rtx),
GET_MODE_SIZE (GET_MODE (to_rtx)));
write_complex_part (temp, XEXP (to_rtx, 0), false);
write_complex_part (temp, XEXP (to_rtx, 1), true);
bool
emit_storent_insn (rtx to, rtx from)
{
- struct expand_operand ops[2];
+ class expand_operand ops[2];
machine_mode mode = GET_MODE (to);
enum insn_code code = optab_handler (storent_optab, mode);
copy_blkmode_from_reg (target, temp, TREE_TYPE (exp));
else
store_bit_field (target,
- INTVAL (expr_size (exp)) * BITS_PER_UNIT,
+ rtx_to_poly_int64 (expr_size (exp))
+ * BITS_PER_UNIT,
0, 0, 0, GET_MODE (temp), temp, reverse);
}
else
&& exp_size >= 0
&& bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
{
- tree type = TREE_TYPE (value);
+ type = TREE_TYPE (value);
if (TYPE_PRECISION (type) < BITS_PER_WORD)
{
else
{
unsigned HOST_WIDE_INT idx;
- tree index, value;
HOST_WIDE_INT count = 0, zero_count = 0;
need_to_clear = ! const_bounds_p;
!= CODE_FOR_nothing)
&& (elt = uniform_vector_p (exp)))
{
- struct expand_operand ops[2];
+ class expand_operand ops[2];
create_output_operand (&ops[0], target, mode);
create_input_operand (&ops[1], expand_normal (elt), eltmode);
expand_insn (icode, 2, ops);
&& n_elts.is_constant (&const_n_elts))
{
machine_mode emode = eltmode;
+ bool vector_typed_elts_p = false;
if (CONSTRUCTOR_NELTS (exp)
&& (TREE_CODE (TREE_TYPE (CONSTRUCTOR_ELT (exp, 0)->value))
* TYPE_VECTOR_SUBPARTS (etype),
n_elts));
emode = TYPE_MODE (etype);
+ vector_typed_elts_p = true;
}
icode = convert_optab_handler (vec_init_optab, mode, emode);
if (icode != CODE_FOR_nothing)
{
- unsigned int i, n = const_n_elts;
+ unsigned int n = const_n_elts;
- if (emode != eltmode)
+ if (vector_typed_elts_p)
{
n = CONSTRUCTOR_NELTS (exp);
vec_vec_init_p = true;
}
vector = rtvec_alloc (n);
- for (i = 0; i < n; i++)
- RTVEC_ELT (vector, i) = CONST0_RTX (emode);
+ for (unsigned int k = 0; k < n; k++)
+ RTVEC_ELT (vector, k) = CONST0_RTX (emode);
}
}
word size, we need to load the value (see again store_bit_field). */
if (GET_MODE (temp) == BLKmode && known_le (bitsize, BITS_PER_WORD))
{
- scalar_int_mode temp_mode = smallest_int_mode_for_size (bitsize);
+ temp_mode = smallest_int_mode_for_size (bitsize);
temp = extract_bit_field (temp, bitsize, 0, 1, NULL_RTX, temp_mode,
temp_mode, false, NULL);
}
*punsignedp = (! INTEGRAL_TYPE_P (TREE_TYPE (exp))
|| TYPE_UNSIGNED (TREE_TYPE (exp)));
- /* For vector types, with the correct size of access, use the mode of
- inner type. */
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE
- && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))
- && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp))))
- mode = TYPE_MODE (TREE_TYPE (exp));
+ /* For vector element types with the correct size of access or for
+ vector typed accesses use the mode of the access type. */
+ if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE
+ && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))
+ && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp))))
+ || VECTOR_TYPE_P (TREE_TYPE (exp)))
+ mode = TYPE_MODE (TREE_TYPE (exp));
}
else
{
DECL_RTL of the VAR_DECL. *ALT_RTL is also set if EXP is a
COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
recursively.
+ If the result can be stored at TARGET, and ALT_RTL is non-NULL,
+ then *ALT_RTL is set to TARGET (before legitimziation).
If INNER_REFERENCE_P is true, we are expanding an inner reference.
In this case, we don't adjust a returned MEM rtx that wouldn't be
if (TREE_CODE (treeop0) == SSA_NAME
&& (srcstmt = get_def_for_expr_class (treeop0, tcc_comparison)))
{
- tree type = TREE_TYPE (gimple_assign_rhs1 (srcstmt));
+ type = TREE_TYPE (gimple_assign_rhs1 (srcstmt));
enum tree_code cmpcode = gimple_assign_rhs_code (srcstmt);
op00 = expand_normal (gimple_assign_rhs1 (srcstmt));
op01 = expand_normal (gimple_assign_rhs2 (srcstmt));
}
else if (COMPARISON_CLASS_P (treeop0))
{
- tree type = TREE_TYPE (TREE_OPERAND (treeop0, 0));
+ type = TREE_TYPE (TREE_OPERAND (treeop0, 0));
enum tree_code cmpcode = TREE_CODE (treeop0);
op00 = expand_normal (TREE_OPERAND (treeop0, 0));
op01 = expand_normal (TREE_OPERAND (treeop0, 1));
return NULL_RTX;
}
+/* A helper function for expand_expr_real_2 to be used with a
+ misaligned mem_ref TEMP. Assume an unsigned type if UNSIGNEDP
+ is nonzero, with alignment ALIGN in bits.
+ Store the value at TARGET if possible (if TARGET is nonzero).
+ Regardless of TARGET, we return the rtx for where the value is placed.
+ If the result can be stored at TARGET, and ALT_RTL is non-NULL,
+ then *ALT_RTL is set to TARGET (before legitimziation). */
+
+static rtx
+expand_misaligned_mem_ref (rtx temp, machine_mode mode, int unsignedp,
+ unsigned int align, rtx target, rtx *alt_rtl)
+{
+ enum insn_code icode;
+
+ if ((icode = optab_handler (movmisalign_optab, mode))
+ != CODE_FOR_nothing)
+ {
+ class expand_operand ops[2];
+
+ /* We've already validated the memory, and we're creating a
+ new pseudo destination. The predicates really can't fail,
+ nor can the generator. */
+ create_output_operand (&ops[0], NULL_RTX, mode);
+ create_fixed_operand (&ops[1], temp);
+ expand_insn (icode, 2, ops);
+ temp = ops[0].value;
+ }
+ else if (targetm.slow_unaligned_access (mode, align))
+ temp = extract_bit_field (temp, GET_MODE_BITSIZE (mode),
+ 0, unsignedp, target,
+ mode, mode, false, alt_rtl);
+ return temp;
+}
+
rtx
expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
enum expand_modifier modifier)
!= INTEGER_CST check. Handle it. */
if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
goto widen_mult_const;
- if (TREE_CODE (treeop1) == INTEGER_CST)
- op1 = convert_modes (mode, word_mode, op1,
- TYPE_UNSIGNED (TREE_TYPE (treeop1)));
temp = expand_binop (mode, other_optab, op0, op1, target,
unsignedp, OPTAB_LIB_WIDEN);
hipart = gen_highpart (word_mode, temp);
&& mode == TYPE_MODE (TREE_TYPE (treeop0))
&& SCALAR_INT_MODE_P (mode))
{
- struct expand_operand eops[4];
+ class expand_operand eops[4];
machine_mode imode = TYPE_MODE (TREE_TYPE (treeop0));
expand_operands (treeop0, treeop1,
subtarget, &op0, &op1, EXPAND_NORMAL);
tree oprnd0 = treeop0;
tree oprnd1 = treeop1;
tree oprnd2 = treeop2;
- rtx op2;
expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
op2 = expand_normal (oprnd2);
tree oprnd0 = treeop0;
tree oprnd1 = treeop1;
tree oprnd2 = treeop2;
- rtx op2;
expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
op2 = expand_normal (oprnd2);
tree oprnd0 = treeop0;
tree oprnd1 = treeop1;
tree oprnd2 = treeop2;
- rtx op2;
this_optab = optab_for_tree_code (code, type, optab_default);
expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
bitsize = TYPE_PRECISION (TREE_TYPE (treeop1));
else
bitsize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (treeop1)));
- rtx op0 = expand_normal (treeop0);
- rtx op1 = expand_normal (treeop1);
+ op0 = expand_normal (treeop0);
+ op1 = expand_normal (treeop1);
rtx dst = gen_reg_rtx (mode);
emit_move_insn (dst, op0);
store_bit_field (dst, bitsize, bitpos, 0, 0,
{
rtx r;
location_t saved_loc = curr_insn_location ();
- location_t loc = gimple_location (g);
+ loc = gimple_location (g);
if (loc != UNKNOWN_LOCATION)
set_curr_insn_location (loc);
ops.code = gimple_assign_rhs_code (g);
{
if (exp && MEM_P (temp) && REG_P (XEXP (temp, 0)))
mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
+ }
+ else if (MEM_P (decl_rtl))
+ temp = decl_rtl;
+
+ if (temp != 0)
+ {
+ if (MEM_P (temp)
+ && modifier != EXPAND_WRITE
+ && modifier != EXPAND_MEMORY
+ && modifier != EXPAND_INITIALIZER
+ && modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_SUM
+ && !inner_reference_p
+ && mode != BLKmode
+ && MEM_ALIGN (temp) < GET_MODE_ALIGNMENT (mode))
+ temp = expand_misaligned_mem_ref (temp, mode, unsignedp,
+ MEM_ALIGN (temp), NULL_RTX, NULL);
return temp;
}
GET_MODE_PRECISION (TYPE_MODE (type)), we need to extend from
the former to the latter according to the signedness of the
type. */
- scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);
+ scalar_int_mode int_mode = SCALAR_INT_TYPE_MODE (type);
temp = immed_wide_int_const
- (wi::to_wide (exp, GET_MODE_PRECISION (mode)), mode);
+ (wi::to_wide (exp, GET_MODE_PRECISION (int_mode)), int_mode);
return temp;
}
/* Handle evaluating a complex constant in a CONCAT target. */
if (original_target && GET_CODE (original_target) == CONCAT)
{
- machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
rtx rtarg, itarg;
+ mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
rtarg = XEXP (original_target, 0);
itarg = XEXP (original_target, 1);
{
addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
- enum insn_code icode;
unsigned int align;
op0 = addr_for_mem_ref (exp, as, true);
if (modifier != EXPAND_WRITE
&& modifier != EXPAND_MEMORY
&& mode != BLKmode
- && align < GET_MODE_ALIGNMENT (mode)
- /* If the target does not have special handling for unaligned
- loads of mode then it can use regular moves for them. */
- && ((icode = optab_handler (movmisalign_optab, mode))
- != CODE_FOR_nothing))
- {
- struct expand_operand ops[2];
-
- /* We've already validated the memory, and we're creating a
- new pseudo destination. The predicates really can't fail,
- nor can the generator. */
- create_output_operand (&ops[0], NULL_RTX, mode);
- create_fixed_operand (&ops[1], temp);
- expand_insn (icode, 2, ops);
- temp = ops[0].value;
- }
+ && align < GET_MODE_ALIGNMENT (mode))
+ temp = expand_misaligned_mem_ref (temp, mode, unsignedp,
+ align, NULL_RTX, NULL);
return temp;
}
machine_mode address_mode;
tree base = TREE_OPERAND (exp, 0);
gimple *def_stmt;
- enum insn_code icode;
unsigned align;
/* Handle expansion of non-aliased memory with non-BLKmode. That
might end up in a register. */
return expand_expr (exp, target, tmode, modifier);
}
address_mode = targetm.addr_space.address_mode (as);
- base = TREE_OPERAND (exp, 0);
if ((def_stmt = get_def_for_expr (base, BIT_AND_EXPR)))
{
tree mask = gimple_assign_rhs2 (def_stmt);
&& !inner_reference_p
&& mode != BLKmode
&& align < GET_MODE_ALIGNMENT (mode))
- {
- if ((icode = optab_handler (movmisalign_optab, mode))
- != CODE_FOR_nothing)
- {
- struct expand_operand ops[2];
-
- /* We've already validated the memory, and we're creating a
- new pseudo destination. The predicates really can't fail,
- nor can the generator. */
- create_output_operand (&ops[0], NULL_RTX, mode);
- create_fixed_operand (&ops[1], temp);
- expand_insn (icode, 2, ops);
- temp = ops[0].value;
- }
- else if (targetm.slow_unaligned_access (mode, align))
- temp = extract_bit_field (temp, GET_MODE_BITSIZE (mode),
- 0, TYPE_UNSIGNED (TREE_TYPE (exp)),
- (modifier == EXPAND_STACK_PARM
- ? NULL_RTX : target),
- mode, mode, false, alt_rtl);
- }
+ temp = expand_misaligned_mem_ref (temp, mode, unsignedp, align,
+ modifier == EXPAND_STACK_PARM
+ ? NULL_RTX : target, alt_rtl);
if (reverse
&& modifier != EXPAND_MEMORY
&& modifier != EXPAND_WRITE)
if (tree_fits_uhwi_p (index1)
&& compare_tree_int (index1, TREE_STRING_LENGTH (init)) < 0)
{
- tree type = TREE_TYPE (TREE_TYPE (init));
- scalar_int_mode mode;
+ tree char_type = TREE_TYPE (TREE_TYPE (init));
+ scalar_int_mode char_mode;
- if (is_int_mode (TYPE_MODE (type), &mode)
- && GET_MODE_SIZE (mode) == 1)
+ if (is_int_mode (TYPE_MODE (char_type), &char_mode)
+ && GET_MODE_SIZE (char_mode) == 1)
return gen_int_mode (TREE_STRING_POINTER (init)
[TREE_INT_CST_LOW (index1)],
- mode);
+ char_mode);
}
}
}
rtx op = read_complex_part (op0, i != 0);
if (GET_CODE (op) == SUBREG)
op = force_reg (GET_MODE (op), op);
- rtx temp = gen_lowpart_common (GET_MODE_INNER (mode1),
- op);
+ temp = gen_lowpart_common (GET_MODE_INNER (mode1), op);
if (temp)
op = temp;
else
MEM_VOLATILE_P (op0) = 1;
}
+ if (MEM_P (op0) && TREE_CODE (tem) == FUNCTION_DECL)
+ {
+ if (op0 == orig_op0)
+ op0 = copy_rtx (op0);
+
+ set_mem_align (op0, BITS_PER_UNIT);
+ }
+
/* In cases where an aligned union has an unaligned object
as a field, we might be extracting a BLKmode value from
an integer-mode (e.g., SImode) object. Handle this case
if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
- /* If the result has a record type and the extraction is done in
+ /* If the result has aggregate type and the extraction is done in
an integral mode, then the field may be not aligned on a byte
boundary; in this case, if it has reverse storage order, it
needs to be extracted as a scalar field with reverse storage
order and put back into memory order afterwards. */
- if (TREE_CODE (type) == RECORD_TYPE
+ if (AGGREGATE_TYPE_P (type)
&& GET_MODE_CLASS (ext_mode) == MODE_INT)
reversep = TYPE_REVERSE_STORAGE_ORDER (type);
? NULL_RTX : target),
ext_mode, ext_mode, reversep, alt_rtl);
- /* If the result has a record type and the mode of OP0 is an
+ /* If the result has aggregate type and the mode of OP0 is an
integral mode then, if BITSIZE is narrower than this mode
and this is for big-endian data, we must put the field
into the high-order bits. And we must also put it back
into memory order if it has been previously reversed. */
scalar_int_mode op0_mode;
- if (TREE_CODE (type) == RECORD_TYPE
+ if (AGGREGATE_TYPE_P (type)
&& is_int_mode (GET_MODE (op0), &op0_mode))
{
HOST_WIDE_INT size = GET_MODE_BITSIZE (op0_mode);
op0 = copy_rtx (op0);
/* Don't set memory attributes if the base expression is
- SSA_NAME that got expanded as a MEM. In that case, we should
- just honor its original memory attributes. */
- if (TREE_CODE (tem) != SSA_NAME || !MEM_P (orig_op0))
+ SSA_NAME that got expanded as a MEM or a CONSTANT. In that case,
+ we should just honor its original memory attributes. */
+ if (!(TREE_CODE (tem) == SSA_NAME
+ && (MEM_P (orig_op0) || CONSTANT_P (orig_op0))))
set_mem_attributes (op0, exp, 0);
if (REG_P (XEXP (op0, 0)))
machine_mode mode1;
poly_int64 bitsize, bitpos, bytepos;
tree offset;
- int unsignedp, reversep, volatilep = 0;
+ int reversep, volatilep = 0;
tree tem
= get_inner_reference (treeop0, &bitsize, &bitpos, &offset, &mode1,
&unsignedp, &reversep, &volatilep);
- rtx orig_op0;
/* ??? We should work harder and deal with non-zero offsets. */
if (!offset
&& known_eq (wi::to_poly_offset (TYPE_SIZE (type)), bitsize))
{
/* See the normal_inner_ref case for the rationale. */
- orig_op0
+ rtx orig_op0
= expand_expr_real (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
case CATCH_EXPR:
case EH_FILTER_EXPR:
case TRY_FINALLY_EXPR:
+ case EH_ELSE_EXPR:
/* Lowered by tree-eh.c. */
gcc_unreachable ();
tree
string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
{
+ tree dummy = NULL_TREE;;
+ if (!mem_size)
+ mem_size = &dummy;
+
+ /* Store the type of the original expression before conversions
+ via NOP_EXPR or POINTER_PLUS_EXPR to other types have been
+ removed. */
+ tree argtype = TREE_TYPE (arg);
+
tree array;
STRIP_NOPS (arg);
&& TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == ARRAY_TYPE
&& !(decl && !*decl)
&& !(decl && tree_fits_uhwi_p (DECL_SIZE_UNIT (*decl))
- && mem_size && tree_fits_uhwi_p (*mem_size)
+ && tree_fits_uhwi_p (*mem_size)
&& tree_int_cst_equal (*mem_size, DECL_SIZE_UNIT (*decl))))
return NULL_TREE;
&& TREE_CODE (TREE_TYPE (TREE_TYPE (rhs1))) == ARRAY_TYPE
&& !(decl && !*decl)
&& !(decl && tree_fits_uhwi_p (DECL_SIZE_UNIT (*decl))
- && mem_size && tree_fits_uhwi_p (*mem_size)
+ && tree_fits_uhwi_p (*mem_size)
&& tree_int_cst_equal (*mem_size, DECL_SIZE_UNIT (*decl))))
return NULL_TREE;
if (TREE_CODE (array) == STRING_CST)
{
*ptr_offset = fold_convert (sizetype, offset);
- if (mem_size)
- *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (array));
+ *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (array));
if (decl)
*decl = NULL_TREE;
gcc_checking_assert (tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (array)))
base_off = wioff.to_uhwi ();
unsigned HOST_WIDE_INT fieldoff = 0;
- init = fold_ctor_reference (NULL_TREE, init, base_off, 0, array,
+ init = fold_ctor_reference (TREE_TYPE (arg), init, base_off, 0, array,
&fieldoff);
HOST_WIDE_INT cstoff;
if (!base_off.is_constant (&cstoff))
*ptr_offset = offset;
- tree eltype = TREE_TYPE (init);
- tree initsize = TYPE_SIZE_UNIT (eltype);
- if (mem_size)
- *mem_size = initsize;
-
- if (decl)
- *decl = array;
+ tree inittype = TREE_TYPE (init);
if (TREE_CODE (init) == INTEGER_CST
&& (TREE_CODE (TREE_TYPE (array)) == INTEGER_TYPE
- || TYPE_MAIN_VARIANT (eltype) == char_type_node))
+ || TYPE_MAIN_VARIANT (inittype) == char_type_node))
{
/* For a reference to (address of) a single constant character,
store the native representation of the character in CHARBUF.
int len = native_encode_expr (init, charbuf, sizeof charbuf, 0);
if (len > 0)
{
- /* Construct a string literal with elements of ELTYPE and
+ /* Construct a string literal with elements of INITTYPE and
the representation above. Then strip
the ADDR_EXPR (ARRAY_REF (...)) around the STRING_CST. */
- init = build_string_literal (len, (char *)charbuf, eltype);
+ init = build_string_literal (len, (char *)charbuf, inittype);
init = TREE_OPERAND (TREE_OPERAND (init, 0), 0);
}
}
+ tree initsize = TYPE_SIZE_UNIT (inittype);
+
+ if (TREE_CODE (init) == CONSTRUCTOR && initializer_zerop (init))
+ {
+ /* Fold an empty/zero constructor for an implicitly initialized
+ object or subobject into the empty string. */
+
+ /* Determine the character type from that of the original
+ expression. */
+ tree chartype = argtype;
+ if (POINTER_TYPE_P (chartype))
+ chartype = TREE_TYPE (chartype);
+ while (TREE_CODE (chartype) == ARRAY_TYPE)
+ chartype = TREE_TYPE (chartype);
+ /* Convert a char array to an empty STRING_CST having an array
+ of the expected type. */
+ if (!initsize)
+ initsize = integer_zero_node;
+
+ unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize);
+ init = build_string_literal (size ? 1 : 0, "", chartype, size);
+ init = TREE_OPERAND (init, 0);
+ init = TREE_OPERAND (init, 0);
+
+ *ptr_offset = integer_zero_node;
+ }
+
+ if (decl)
+ *decl = array;
+
if (TREE_CODE (init) != STRING_CST)
return NULL_TREE;
+ *mem_size = initsize;
+
gcc_checking_assert (tree_to_shwi (initsize) >= TREE_STRING_LENGTH (init));
return init;
&& TREE_CODE (arg0) == SSA_NAME
&& TREE_CODE (arg1) == INTEGER_CST)
{
- enum tree_code code = maybe_optimize_mod_cmp (ops->code, &arg0, &arg1);
- if (code != ops->code)
+ enum tree_code new_code = maybe_optimize_mod_cmp (ops->code,
+ &arg0, &arg1);
+ if (new_code != ops->code)
{
struct separate_ops nops = *ops;
- nops.code = ops->code = code;
+ nops.code = ops->code = new_code;
nops.op0 = arg0;
nops.op1 = arg1;
nops.type = TREE_TYPE (arg0);
&& integer_pow2p (gimple_assign_rhs2 (srcstmt)))
{
enum tree_code tcode = code == NE ? NE_EXPR : EQ_EXPR;
- tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
+ type = lang_hooks.types.type_for_mode (mode, unsignedp);
tree temp = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg1),
gimple_assign_rhs1 (srcstmt),
gimple_assign_rhs2 (srcstmt));
rtx table_label, rtx default_label, rtx fallback_label,
profile_probability default_probability)
{
- struct expand_operand ops[5];
+ class expand_operand ops[5];
scalar_int_mode index_mode = SImode;
rtx op1, op2, index;
name = ACONCAT (("__", lang, "_personality", unwind_and_version, NULL));
- type = build_function_type_list (integer_type_node, integer_type_node,
+ type = build_function_type_list (unsigned_type_node,
+ integer_type_node, integer_type_node,
long_long_unsigned_type_node,
ptr_type_node, ptr_type_node, NULL_TREE);
decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,