#include "df.h"
#include "diagnostic.h"
#include "ssaexpand.h"
+#include "target-globals.h"
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
static rtx const_vector_from_tree (tree);
static void write_complex_part (rtx, rtx, bool);
-/* Record for each mode whether we can move a register directly to or
- from an object of that mode in memory. If we can't, we won't try
- to use that mode directly when accessing a field of that mode. */
-
-static char direct_load[NUM_MACHINE_MODES];
-static char direct_store[NUM_MACHINE_MODES];
-
-/* Record for each mode whether we can float-extend from memory. */
-
-static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
-
/* This macro is used to determine whether move_by_pieces should be called
to perform a structure copy. */
#ifndef MOVE_BY_PIECES_P
< (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 movmem_optab[NUM_MACHINE_MODES];
-
-/* This array records the insn_code of insns to perform block sets. */
-enum insn_code setmem_optab[NUM_MACHINE_MODES];
-
-/* These arrays record the insn_code of three different kinds of insns
- to perform block compares. */
-enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
-enum insn_code cmpstrn_optab[NUM_MACHINE_MODES];
-enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
-
-/* Synchronization primitives. */
-enum insn_code sync_add_optab[NUM_MACHINE_MODES];
-enum insn_code sync_sub_optab[NUM_MACHINE_MODES];
-enum insn_code sync_ior_optab[NUM_MACHINE_MODES];
-enum insn_code sync_and_optab[NUM_MACHINE_MODES];
-enum insn_code sync_xor_optab[NUM_MACHINE_MODES];
-enum insn_code sync_nand_optab[NUM_MACHINE_MODES];
-enum insn_code sync_old_add_optab[NUM_MACHINE_MODES];
-enum insn_code sync_old_sub_optab[NUM_MACHINE_MODES];
-enum insn_code sync_old_ior_optab[NUM_MACHINE_MODES];
-enum insn_code sync_old_and_optab[NUM_MACHINE_MODES];
-enum insn_code sync_old_xor_optab[NUM_MACHINE_MODES];
-enum insn_code sync_old_nand_optab[NUM_MACHINE_MODES];
-enum insn_code sync_new_add_optab[NUM_MACHINE_MODES];
-enum insn_code sync_new_sub_optab[NUM_MACHINE_MODES];
-enum insn_code sync_new_ior_optab[NUM_MACHINE_MODES];
-enum insn_code sync_new_and_optab[NUM_MACHINE_MODES];
-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_lock_test_and_set[NUM_MACHINE_MODES];
-enum insn_code sync_lock_release[NUM_MACHINE_MODES];
-
/* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow. */
#ifndef SLOW_UNALIGNED_ACCESS
/* Try converting directly if the insn is supported. */
- code = convert_optab_handler (tab, to_mode, from_mode)->insn_code;
+ code = convert_optab_handler (tab, to_mode, from_mode);
if (code != CODE_FOR_nothing)
{
emit_unop_insn (code, to, from,
enum machine_mode full_mode
= smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT);
- gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code
+ gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)
!= CODE_FOR_nothing);
if (full_mode != from_mode)
from = convert_to_mode (full_mode, from, unsignedp);
- emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code,
+ emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode),
to, from, UNKNOWN);
return;
}
enum machine_mode full_mode
= smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
- gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code
+ gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)
!= CODE_FOR_nothing);
if (to_mode == full_mode)
{
- emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
+ emit_unop_insn (convert_optab_handler (sext_optab, full_mode,
+ from_mode),
to, from, UNKNOWN);
return;
}
new_from = gen_reg_rtx (full_mode);
- emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
+ emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode),
new_from, from, UNKNOWN);
/* else proceed to integer conversions below. */
}
/* Support special truncate insns for certain modes. */
- if (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code != CODE_FOR_nothing)
+ if (convert_optab_handler (trunc_optab, to_mode,
+ from_mode) != CODE_FOR_nothing)
{
- emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code,
+ emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode),
to, from, UNKNOWN);
return;
}
if (mode == VOIDmode)
break;
- icode = optab_handler (mov_optab, mode)->insn_code;
+ icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
move_by_pieces_1 (GEN_FCN (icode), mode, &data);
if (mode == VOIDmode)
break;
- icode = optab_handler (mov_optab, mode)->insn_code;
+ icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
rtx retval = 0;
unsigned int align;
+ gcc_assert (size);
+ if (CONST_INT_P (size)
+ && INTVAL (size) == 0)
+ return 0;
+
switch (method)
{
case BLOCK_OP_NORMAL:
gcc_unreachable ();
}
+ gcc_assert (MEM_P (x) && MEM_P (y));
align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
gcc_assert (align >= BITS_PER_UNIT);
- gcc_assert (MEM_P (x));
- gcc_assert (MEM_P (y));
- gcc_assert (size);
-
/* Make sure we've got BLKmode addresses; store_one_arg can decide that
block copy is more efficient for other large modes, e.g. DCmode. */
x = adjust_address (x, BLKmode, 0);
can be incorrect is coming from __builtin_memcpy. */
if (CONST_INT_P (size))
{
- if (INTVAL (size) == 0)
- return 0;
-
x = shallow_copy_rtx (x);
y = shallow_copy_rtx (y);
set_mem_size (x, size);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
- enum insn_code code = movmem_optab[(int) mode];
+ enum insn_code code = direct_optab_handler (movmem_optab, mode);
insn_operand_predicate_fn pred;
if (code != CODE_FOR_nothing
if (mode == VOIDmode)
break;
- icode = optab_handler (mov_optab, mode)->insn_code;
+ icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing
&& align >= GET_MODE_ALIGNMENT (mode))
{
if (mode == VOIDmode)
break;
- icode = optab_handler (mov_optab, mode)->insn_code;
+ icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
store_by_pieces_2 (GEN_FCN (icode), mode, data);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
- enum insn_code code = setmem_optab[(int) mode];
+ enum insn_code code = direct_optab_handler (setmem_optab, mode);
insn_operand_predicate_fn pred;
if (code != CODE_FOR_nothing
return NULL_RTX;
/* The target must support moves in this mode. */
- code = optab_handler (mov_optab, imode)->insn_code;
+ code = optab_handler (mov_optab, imode);
if (code == CODE_FOR_nothing)
return NULL_RTX;
/* Move floating point as parts. */
if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
- && optab_handler (mov_optab, GET_MODE_INNER (mode))->insn_code != CODE_FOR_nothing)
+ && optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing)
try_int = false;
/* Not possible if the values are inherently not adjacent. */
else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
/* Assume all MODE_CC modes are equivalent; if we have movcc, use it. */
if (mode != CCmode)
{
- enum insn_code code = optab_handler (mov_optab, CCmode)->insn_code;
+ enum insn_code code = optab_handler (mov_optab, CCmode);
if (code != CODE_FOR_nothing)
{
x = emit_move_change_mode (CCmode, mode, x, true);
gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
- code = optab_handler (mov_optab, mode)->insn_code;
+ code = optab_handler (mov_optab, mode);
if (code != CODE_FOR_nothing)
return emit_insn (GEN_FCN (code) (x, y));
stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
/* If there is push pattern, use it. Otherwise try old way of throwing
MEM representing push operation to move expander. */
- icode = optab_handler (push_optab, mode)->insn_code;
+ icode = optab_handler (push_optab, mode);
if (icode != CODE_FOR_nothing)
{
if (((pred = insn_data[(int) icode].operand[0].predicate)
{
rtx to_rtx = 0;
rtx result;
+ enum machine_mode mode;
+ int align, icode;
/* Don't crash if the lhs of the assignment was erroneous. */
if (TREE_CODE (to) == ERROR_MARK)
if (operand_equal_p (to, from, 0))
return;
+ mode = TYPE_MODE (TREE_TYPE (to));
+ if ((TREE_CODE (to) == MEM_REF
+ || TREE_CODE (to) == TARGET_MEM_REF)
+ && mode != BLKmode
+ && ((align = MAX (TYPE_ALIGN (TREE_TYPE (to)),
+ get_object_alignment (to, BIGGEST_ALIGNMENT)))
+ < (signed) GET_MODE_ALIGNMENT (mode))
+ && ((icode = optab_handler (movmisalign_optab, mode))
+ != CODE_FOR_nothing))
+ {
+ enum machine_mode address_mode, op_mode1;
+ rtx insn, reg, op0, mem;
+
+ reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ reg = force_not_mem (reg);
+
+ if (TREE_CODE (to) == MEM_REF)
+ {
+ addr_space_t as
+ = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 1))));
+ tree base = TREE_OPERAND (to, 0);
+ address_mode = targetm.addr_space.address_mode (as);
+ op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op0 = convert_memory_address_addr_space (address_mode, op0, as);
+ if (!integer_zerop (TREE_OPERAND (to, 1)))
+ {
+ rtx off
+ = immed_double_int_const (mem_ref_offset (to), address_mode);
+ op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
+ }
+ op0 = memory_address_addr_space (mode, op0, as);
+ mem = gen_rtx_MEM (mode, op0);
+ set_mem_attributes (mem, to, 0);
+ set_mem_addr_space (mem, as);
+ }
+ else if (TREE_CODE (to) == TARGET_MEM_REF)
+ {
+ addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (to));
+ struct mem_address addr;
+
+ get_address_description (to, &addr);
+ op0 = addr_for_mem_ref (&addr, as, true);
+ op0 = memory_address_addr_space (mode, op0, as);
+ mem = gen_rtx_MEM (mode, op0);
+ set_mem_attributes (mem, to, 0);
+ set_mem_addr_space (mem, as);
+ }
+ else
+ gcc_unreachable ();
+ if (TREE_THIS_VOLATILE (to))
+ MEM_VOLATILE_P (mem) = 1;
+
+ 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;
+ }
+
/* Assignment of a structure component needs special treatment
if the structure component's rtx is not simply a MEM.
Assignment of an array element at a constant index, and assignment of
return;
}
- else if (TREE_CODE (to) == MISALIGNED_INDIRECT_REF)
- {
- addr_space_t as = ADDR_SPACE_GENERIC;
- enum machine_mode mode, op_mode1;
- enum insn_code icode;
- rtx reg, addr, mem, insn;
-
- if (POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (to, 0))))
- as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0))));
-
- 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_addr_space (mode, addr, as);
- mem = gen_rtx_MEM (mode, addr);
-
- set_mem_attributes (mem, to, 0);
- set_mem_addr_space (mem, as);
-
- 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
emit_storent_insn (rtx to, rtx from)
{
enum machine_mode mode = GET_MODE (to), imode;
- enum insn_code code = optab_handler (storent_optab, mode)->insn_code;
+ enum insn_code code = optab_handler (storent_optab, mode);
rtx pattern;
if (code == CODE_FOR_nothing)
{
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
if (GET_MODE (target) == BLKmode
- || GET_MODE (temp) == BLKmode)
+ && GET_MODE (temp) == BLKmode)
emit_block_move (target, temp, expr_size (exp),
(call_param_p
? BLOCK_OP_CALL_PARM
: BLOCK_OP_NORMAL));
+ else if (GET_MODE (target) == BLKmode)
+ store_bit_field (target, INTVAL (expr_size (exp)) * BITS_PER_UNIT,
+ 0, GET_MODE (temp), temp);
else
convert_move (target, temp, unsignedp);
}
HOST_WIDE_INT n = 0, t;
tree f;
- for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+ for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
if (TREE_CODE (f) == FIELD_DECL)
{
t = count_type_elements (TREE_TYPE (f), false);
/* Check for structures with flexible array member. */
tree tf = TREE_TYPE (f);
if (allow_flexarr
- && TREE_CHAIN (f) == NULL
+ && DECL_CHAIN (f) == NULL
&& TREE_CODE (tf) == ARRAY_TYPE
&& TYPE_DOMAIN (tf)
&& TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
{
enum machine_mode mode = GET_MODE (target);
- icode = (int) optab_handler (vec_init_optab, mode)->insn_code;
+ icode = (int) optab_handler (vec_init_optab, mode);
if (icode != CODE_FOR_nothing)
{
unsigned int i;
constructor_elt *ce;
unsigned HOST_WIDE_INT idx;
- for (idx = 0;
- VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce);
- idx++)
+ FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce)
if ((ce->index != NULL_TREE && !safe_from_p (x, ce->index, 0))
|| !safe_from_p (x, ce->value, 0))
return 0;
}
break;
- case MISALIGNED_INDIRECT_REF:
- case ALIGN_INDIRECT_REF:
- case INDIRECT_REF:
+ case MEM_REF:
if (MEM_P (x)
&& alias_sets_conflict_p (MEM_ALIAS_SET (x),
get_alias_set (exp)))
return MAX (factor, talign);
}
\f
-/* Return &VAR expression for emulated thread local VAR. */
-
-static tree
-emutls_var_address (tree var)
-{
- tree emuvar = emutls_decl (var);
- tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS];
- tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node);
- tree arglist = build_tree_list (NULL_TREE, arg);
- tree call = build_function_call_expr (UNKNOWN_LOCATION, fn, arglist);
- return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
-}
-\f
-
/* Subroutine of expand_expr. Expand the two operands of a binary
expression EXP0 and EXP1 placing the results in OP0 and OP1.
The value may be stored in TARGET if TARGET is nonzero. The
inner = TREE_OPERAND (exp, 0);
break;
- case VAR_DECL:
- /* TLS emulation hook - replace __thread VAR's &VAR with
- __emutls_get_address (&_emutls.VAR). */
- if (! targetm.have_tls
- && TREE_CODE (exp) == VAR_DECL
- && DECL_THREAD_LOCAL_P (exp))
- {
- exp = emutls_var_address (exp);
- return expand_expr (exp, target, tmode, modifier);
- }
- /* Fall through. */
-
default:
/* If the object is a DECL, then expand it for its rtl. Don't bypass
expand_expr, as that can have various side effects; LABEL_DECLs for
}
}
+ /* Use TER to expand pointer addition of a negated value
+ as pointer subtraction. */
+ if ((POINTER_TYPE_P (TREE_TYPE (treeop0))
+ || (TREE_CODE (TREE_TYPE (treeop0)) == VECTOR_TYPE
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (treeop0)))))
+ && TREE_CODE (treeop1) == SSA_NAME
+ && TYPE_MODE (TREE_TYPE (treeop0))
+ == TYPE_MODE (TREE_TYPE (treeop1)))
+ {
+ gimple def = get_def_for_expr (treeop1, NEGATE_EXPR);
+ if (def)
+ {
+ treeop1 = gimple_assign_rhs1 (def);
+ code = MINUS_EXPR;
+ goto do_minus;
+ }
+ }
+
/* No sense saving up arithmetic to be done
if it's all in the wrong mode to form part of an address.
And force_operand won't know whether to sign-extend or
return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
case MINUS_EXPR:
+ do_minus:
/* For initializers, we are allowed to return a MINUS of two
symbolic constants. Here we handle all cases when both operands
are constant. */
this_optab = usmul_widen_optab;
if (mode == GET_MODE_2XWIDER_MODE (innermode))
{
- if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
+ if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
{
if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
expand_operands (treeop0, treeop1, subtarget, &op0, &op1,
if (mode == GET_MODE_2XWIDER_MODE (innermode))
{
- if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
+ if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
{
expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
EXPAND_NORMAL);
unsignedp, this_optab);
return REDUCE_BIT_FIELD (temp);
}
- if (optab_handler (other_optab, mode)->insn_code != CODE_FOR_nothing
+ if (optab_handler (other_optab, mode) != CODE_FOR_nothing
&& innermode == word_mode)
{
rtx htem, hipart;
&& (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
layout_decl (exp, 0);
- /* TLS emulation hook - replace __thread vars with
- *__emutls_get_address (&_emutls.var). */
- if (! targetm.have_tls
- && TREE_CODE (exp) == VAR_DECL
- && DECL_THREAD_LOCAL_P (exp))
- {
- exp = build_fold_indirect_ref_loc (loc, emutls_var_address (exp));
- return expand_expr_real_1 (exp, target, tmode, modifier, NULL);
- }
-
/* ... fall through ... */
case FUNCTION_DECL:
return expand_constructor (exp, target, modifier, false);
- case MISALIGNED_INDIRECT_REF:
- case ALIGN_INDIRECT_REF:
- case INDIRECT_REF:
+ case TARGET_MEM_REF:
{
- tree exp1 = treeop0;
- addr_space_t as = ADDR_SPACE_GENERIC;
- enum machine_mode address_mode = Pmode;
-
- if (modifier != EXPAND_WRITE)
- {
- tree t;
-
- t = fold_read_from_constant_string (exp);
- if (t)
- return expand_expr (t, target, tmode, modifier);
- }
-
- if (POINTER_TYPE_P (TREE_TYPE (exp1)))
- {
- as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1)));
- address_mode = targetm.addr_space.address_mode (as);
- }
+ addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
+ struct mem_address addr;
+ int icode, align;
- op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
+ get_address_description (exp, &addr);
+ op0 = addr_for_mem_ref (&addr, as, true);
op0 = memory_address_addr_space (mode, op0, as);
-
- if (code == ALIGN_INDIRECT_REF)
- {
- int align = TYPE_ALIGN_UNIT (type);
- op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align));
- op0 = memory_address_addr_space (mode, op0, as);
- }
-
temp = gen_rtx_MEM (mode, op0);
-
set_mem_attributes (temp, exp, 0);
set_mem_addr_space (temp, as);
-
- /* Resolve the misalignment now, so that we don't have to remember
- to resolve it later. Of course, this only works for reads. */
- if (code == MISALIGNED_INDIRECT_REF)
+ align = MAX (TYPE_ALIGN (TREE_TYPE (exp)),
+ get_object_alignment (exp, BIGGEST_ALIGNMENT));
+ if (mode != BLKmode
+ && (unsigned) 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))
{
- int icode;
rtx reg, insn;
- gcc_assert (modifier == EXPAND_NORMAL
- || modifier == EXPAND_STACK_PARM);
-
- /* The vectorizer should have already checked the mode. */
- icode = optab_handler (movmisalign_optab, mode)->insn_code;
- gcc_assert (icode != CODE_FOR_nothing);
-
/* We've already validated the memory, and we're creating a
new pseudo destination. The predicates really can't fail. */
reg = gen_reg_rtx (mode);
return reg;
}
-
return temp;
}
- case TARGET_MEM_REF:
- {
- addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
- struct mem_address addr;
- tree base;
-
- get_address_description (exp, &addr);
- op0 = addr_for_mem_ref (&addr, as, true);
- op0 = memory_address_addr_space (mode, op0, as);
- temp = gen_rtx_MEM (mode, op0);
- set_mem_attributes (temp, TMR_ORIGINAL (exp), 0);
- set_mem_addr_space (temp, as);
- base = get_base_address (TMR_ORIGINAL (exp));
- if (INDIRECT_REF_P (base)
- && TMR_BASE (exp)
- && TREE_CODE (TMR_BASE (exp)) == SSA_NAME
- && POINTER_TYPE_P (TREE_TYPE (TMR_BASE (exp))))
- {
- set_mem_expr (temp, build1 (INDIRECT_REF,
- TREE_TYPE (exp), TMR_BASE (exp)));
- set_mem_offset (temp, NULL_RTX);
- }
- }
- return temp;
-
case MEM_REF:
{
addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))));
enum machine_mode address_mode;
tree base = TREE_OPERAND (exp, 0);
+ gimple def_stmt;
+ int icode, align;
/* Handle expansion of non-aliased memory with non-BLKmode. That
might end up in a register. */
if (TREE_CODE (base) == ADDR_EXPR)
}
}
address_mode = targetm.addr_space.address_mode (as);
- op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, address_mode,
- EXPAND_NORMAL);
+ base = TREE_OPERAND (exp, 0);
+ if ((def_stmt = get_def_for_expr (base, BIT_AND_EXPR)))
+ {
+ tree mask = gimple_assign_rhs2 (def_stmt);
+ base = build2 (BIT_AND_EXPR, TREE_TYPE (base),
+ gimple_assign_rhs1 (def_stmt), mask);
+ TREE_OPERAND (exp, 0) = base;
+ }
+ align = MAX (TYPE_ALIGN (TREE_TYPE (exp)),
+ get_object_alignment (exp, BIGGEST_ALIGNMENT));
+ op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op0 = convert_memory_address_addr_space (address_mode, op0, as);
if (!integer_zerop (TREE_OPERAND (exp, 1)))
{
- rtx off;
- off = immed_double_int_const (mem_ref_offset (exp), address_mode);
+ rtx off
+ = immed_double_int_const (mem_ref_offset (exp), address_mode);
op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
}
op0 = memory_address_addr_space (mode, op0, as);
set_mem_addr_space (temp, as);
if (TREE_THIS_VOLATILE (exp))
MEM_VOLATILE_P (temp) = 1;
+ if (mode != BLKmode
+ && (unsigned) 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))
+ {
+ rtx reg, insn;
+
+ /* We've already validated the memory, and we're creating a
+ new pseudo destination. The predicates really can't fail. */
+ reg = gen_reg_rtx (mode);
+
+ /* Nor can the insn generator. */
+ insn = GEN_FCN (icode) (reg, temp);
+ emit_insn (insn);
+
+ return reg;
+ }
return temp;
}
&& TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
&& TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
&& TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
- && targetm.binds_local_p (array))
+ && const_value_known_p (array))
{
if (TREE_CODE (index) == INTEGER_CST)
{
{
if (GET_CODE (op0) == SUBREG)
op0 = force_reg (GET_MODE (op0), op0);
- op0 = gen_lowpart (mode, op0);
+ temp = gen_lowpart_common (mode, op0);
+ if (temp)
+ op0 = temp;
+ else
+ {
+ if (!REG_P (op0) && !MEM_P (op0))
+ op0 = force_reg (GET_MODE (op0), op0);
+ op0 = gen_lowpart (mode, op0);
+ }
}
/* If both types are integral, convert from one mode to the other. */
else if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (TREE_TYPE (treeop0)))
*ptr_offset = fold_convert (sizetype, offset);
return array;
}
- else if (TREE_CODE (array) == VAR_DECL)
+ else if (TREE_CODE (array) == VAR_DECL
+ || TREE_CODE (array) == CONST_DECL)
{
int length;
/* Variables initialized to string literals can be handled too. */
- if (DECL_INITIAL (array) == NULL_TREE
+ if (!const_value_known_p (array)
+ || !DECL_INITIAL (array)
|| TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
return 0;
- /* If they are read-only, non-volatile and bind locally. */
- if (! TREE_READONLY (array)
- || TREE_SIDE_EFFECTS (array)
- || ! targetm.binds_local_p (array))
- return 0;
-
/* Avoid const char foo[4] = "abcde"; */
if (DECL_SIZE_UNIT (array) == NULL_TREE
|| TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
return 1;
}
-/* Nonzero if the mode is a valid vector mode for this architecture.
- This returns nonzero even if there is no hardware support for the
- vector mode, but we can emulate with narrower modes. */
-
-int
-vector_mode_valid_p (enum machine_mode mode)
-{
- enum mode_class mclass = GET_MODE_CLASS (mode);
- enum machine_mode innermode;
-
- /* Doh! What's going on? */
- if (mclass != MODE_VECTOR_INT
- && mclass != MODE_VECTOR_FLOAT
- && mclass != MODE_VECTOR_FRACT
- && mclass != MODE_VECTOR_UFRACT
- && mclass != MODE_VECTOR_ACCUM
- && mclass != MODE_VECTOR_UACCUM)
- return 0;
-
- /* Hardware support. Woo hoo! */
- if (targetm.vector_mode_supported_p (mode))
- return 1;
-
- innermode = GET_MODE_INNER (mode);
-
- /* We should probably return 1 if requesting V4DI and we have no DI,
- but we have V2DI, but this is probably very unlikely. */
-
- /* If we have support for the inner mode, we can safely emulate it.
- We may not have V2DI, but me can emulate with a pair of DIs. */
- return targetm.scalar_mode_supported_p (innermode);
-}
-
/* Return a CONST_VECTOR rtx for a VECTOR_CST tree. */
static rtx
const_vector_from_tree (tree exp)