/* Convert tree expression to rtl instructions, for GNU compiler.
- Copyright (C) 1988-2014 Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "machmode.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "stringpool.h"
#include "stor-layout.h"
#include "attribs.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "except.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "input.h"
#include "function.h"
#include "insn-config.h"
#include "insn-attr.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "libfuncs.h"
#include "recog.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "gimple-expr.h"
-#include "is-a.h"
#include "gimple.h"
#include "gimple-ssa.h"
-#include "hash-map.h"
-#include "plugin-api.h"
-#include "ipa-ref.h"
#include "cgraph.h"
#include "tree-ssanames.h"
#include "target.h"
#include "tree-ssa-address.h"
#include "cfgexpand.h"
#include "builtins.h"
-
-#ifndef STACK_PUSH_CODE
-#ifdef STACK_GROWS_DOWNWARD
-#define STACK_PUSH_CODE PRE_DEC
-#else
-#define STACK_PUSH_CODE PRE_INC
-#endif
-#endif
+#include "tree-chkp.h"
+#include "rtl-chkp.h"
+#include "ccmp.h"
/* If this is nonzero, we do not bother generating VOLATILE
static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (const_tree, const_tree);
static int is_aligning_offset (const_tree, const_tree);
-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 (sepops, rtx, machine_mode);
#ifdef PUSH_ROUNDING
#endif
static void do_tablejump (rtx, machine_mode, rtx, rtx, rtx, int);
static rtx const_vector_from_tree (tree);
-static void write_complex_part (rtx, rtx, bool);
+static tree tree_expr_size (const_tree);
+static HOST_WIDE_INT int_expr_size (tree);
\f
/* This is run to set up which modes can be used
/* Try indexing by frame ptr and try by stack ptr.
It is known that on the Convex the stack ptr isn't a valid index.
With luck, one or the other is valid on any machine. */
- mem = gen_rtx_MEM (VOIDmode, stack_pointer_rtx);
- mem1 = gen_rtx_MEM (VOIDmode, frame_pointer_rtx);
+ mem = gen_rtx_MEM (word_mode, stack_pointer_rtx);
+ mem1 = gen_rtx_MEM (word_mode, frame_pointer_rtx);
/* A scratch register we can modify in-place below to avoid
useless RTL allocations. */
- reg = gen_rtx_REG (VOIDmode, -1);
+ reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
insn = rtx_alloc (INSN);
- pat = gen_rtx_SET (VOIDmode, NULL_RTX, NULL_RTX);
+ pat = gen_rtx_SET (NULL_RTX, NULL_RTX);
PATTERN (insn) = pat;
for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
direct_load[(int) mode] = direct_store[(int) mode] = 0;
PUT_MODE (mem, mode);
PUT_MODE (mem1, mode);
- PUT_MODE (reg, mode);
/* See if there is some register that can be used in this mode and
directly loaded or stored from memory. */
if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
- SET_REGNO (reg, regno);
+ set_mode_and_regno (reg, mode, regno);
SET_SRC (pat) = mem;
SET_DEST (pat) = reg;
}
}
- mem = gen_rtx_MEM (VOIDmode, gen_rtx_raw_REG (Pmode, 10000));
+ mem = gen_rtx_MEM (VOIDmode, gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1));
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
to_addr = NULL_RTX;
data.to = NULL_RTX;
data.autinc_to = 1;
-#ifdef STACK_GROWS_DOWNWARD
- data.reverse = 1;
-#else
- data.reverse = 0;
-#endif
+ if (STACK_GROWS_DOWNWARD)
+ data.reverse = 1;
+ else
+ data.reverse = 0;
}
data.to_addr = to_addr;
data.from = from;
move_block_to_reg (int regno, rtx x, int nregs, machine_mode mode)
{
int i;
-#ifdef HAVE_load_multiple
rtx pat;
rtx_insn *last;
-#endif
if (nregs == 0)
return;
x = validize_mem (force_const_mem (mode, x));
/* See if the machine can do this with a load multiple insn. */
-#ifdef HAVE_load_multiple
if (HAVE_load_multiple)
{
last = get_last_insn ();
else
delete_insns_since (last);
}
-#endif
for (i = 0; i < nregs; i++)
emit_move_insn (gen_rtx_REG (word_mode, regno + i),
return;
/* See if the machine can do this with a store multiple insn. */
-#ifdef HAVE_store_multiple
if (HAVE_store_multiple)
{
rtx_insn *last = get_last_insn ();
else
delete_insns_since (last);
}
-#endif
for (i = 0; i < nregs; i++)
{
void
use_reg_mode (rtx *call_fusage, rtx reg, machine_mode mode)
{
- gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
+ gcc_assert (REG_P (reg));
+
+ if (!HARD_REGISTER_P (reg))
+ return;
*call_fusage
= gen_rtx_EXPR_LIST (mode, gen_rtx_USE (VOIDmode, reg), *call_fusage);
return def_stmt;
}
-#ifdef HAVE_conditional_move
/* Return the defining gimple statement for SSA_NAME NAME if it is an
assigment and the class of the expresion on the RHS is CLASS. Return
NULL otherwise. */
return def_stmt;
}
-#endif
\f
/* Determine whether the LEN bytes generated by CONSTFUN can be
/* Write to one of the components of the complex value CPLX. Write VAL to
the real part if IMAG_P is false, and the imaginary part if its true. */
-static void
+void
write_complex_part (rtx cplx, rtx val, bool imag_p)
{
machine_mode cmode;
where the natural size of floating-point regs is 32-bit. */
|| (REG_P (cplx)
&& REGNO (cplx) < FIRST_PSEUDO_REGISTER
- && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
+ && REG_NREGS (cplx) % 2 == 0))
{
rtx part = simplify_gen_subreg (imode, cplx, cmode,
imag_p ? GET_MODE_SIZE (imode) : 0);
where the natural size of floating-point regs is 32-bit. */
|| (REG_P (cplx)
&& REGNO (cplx) < FIRST_PSEUDO_REGISTER
- && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
+ && REG_NREGS (cplx) % 2 == 0))
{
rtx ret = simplify_gen_subreg (imode, cplx, cmode,
imag_p ? GET_MODE_SIZE (imode) : 0);
&& optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing
&& !(REG_P (x)
&& HARD_REGISTER_P (x)
- && hard_regno_nregs[REGNO (x)][mode] == 1)
+ && REG_NREGS (x) == 1)
&& !(REG_P (y)
&& HARD_REGISTER_P (y)
- && hard_regno_nregs[REGNO (y)][mode] == 1))
+ && REG_NREGS (y) == 1))
try_int = false;
/* Not possible if the values are inherently not adjacent. */
else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
return last_insn;
}
+/* Generate the body of an instruction to copy Y into X.
+ It may be a list of insns, if one insn isn't enough. */
+
+rtx_insn *
+gen_move_insn (rtx x, rtx y)
+{
+ rtx_insn *seq;
+
+ start_sequence ();
+ emit_move_insn_1 (x, y);
+ seq = get_insns ();
+ end_sequence ();
+ return seq;
+}
+
+/* Same as above, but return rtx (used as a callback, which must have
+ prototype compatible with other functions returning rtx). */
+
+rtx
+gen_move_insn_uncast (rtx x, rtx y)
+{
+ return gen_move_insn (x, y);
+}
+
/* If Y is representable exactly in a narrower mode, and the target can
perform the extension directly from constant or memory, then emit the
move as an extension. */
anti_adjust_stack (temp);
}
-#ifndef STACK_GROWS_DOWNWARD
- if (0)
-#else
- if (1)
-#endif
+ if (STACK_GROWS_DOWNWARD)
{
temp = virtual_outgoing_args_rtx;
if (extra != 0 && below)
saw_unknown = true;
add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (args_size));
-#ifdef STACK_GROWS_DOWNWARD
- this_delta = -(unsigned HOST_WIDE_INT) this_delta;
-#endif
+ if (STACK_GROWS_DOWNWARD)
+ this_delta = -(unsigned HOST_WIDE_INT) this_delta;
+
args_size -= this_delta;
}
emit_move_insn (stack_pointer_rtx,
expand_binop (Pmode,
-#ifdef STACK_GROWS_DOWNWARD
- sub_optab,
-#else
- add_optab,
-#endif
+ STACK_GROWS_DOWNWARD ? sub_optab
+ : add_optab,
stack_pointer_rtx,
gen_int_mode (rounded_size, Pmode),
NULL_RTX, 0, OPTAB_LIB_WIDEN));
offset = (HOST_WIDE_INT) padding_size;
-#ifdef STACK_GROWS_DOWNWARD
- if (STACK_PUSH_CODE == POST_DEC)
+ if (STACK_GROWS_DOWNWARD && STACK_PUSH_CODE == POST_DEC)
/* We have already decremented the stack pointer, so get the
previous value. */
offset += (HOST_WIDE_INT) rounded_size;
-#else
- if (STACK_PUSH_CODE == POST_INC)
+
+ if (!STACK_GROWS_DOWNWARD && STACK_PUSH_CODE == POST_INC)
/* We have already incremented the stack pointer, so get the
previous value. */
offset -= (HOST_WIDE_INT) rounded_size;
-#endif
+
dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
gen_int_mode (offset, Pmode));
}
else
{
-#ifdef STACK_GROWS_DOWNWARD
- /* ??? This seems wrong if STACK_PUSH_CODE == POST_DEC. */
- dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- gen_int_mode (-(HOST_WIDE_INT) rounded_size,
- Pmode));
-#else
- /* ??? This seems wrong if STACK_PUSH_CODE == POST_INC. */
- dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- gen_int_mode (rounded_size, Pmode));
-#endif
+ if (STACK_GROWS_DOWNWARD)
+ /* ??? This seems wrong if STACK_PUSH_CODE == POST_DEC. */
+ dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ gen_int_mode (-(HOST_WIDE_INT) rounded_size,
+ Pmode));
+ else
+ /* ??? This seems wrong if STACK_PUSH_CODE == POST_INC. */
+ dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ gen_int_mode (rounded_size, Pmode));
+
dest_addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, dest_addr);
}
}
#endif
+/* If reading SIZE bytes from X will end up reading from
+ Y return the number of bytes that overlap. Return -1
+ if there is no overlap or -2 if we can't determine
+ (for example when X and Y have different base registers). */
+
+static int
+memory_load_overlap (rtx x, rtx y, HOST_WIDE_INT size)
+{
+ rtx tmp = plus_constant (Pmode, x, size);
+ rtx sub = simplify_gen_binary (MINUS, Pmode, tmp, y);
+
+ if (!CONST_INT_P (sub))
+ return -2;
+
+ HOST_WIDE_INT val = INTVAL (sub);
+
+ return IN_RANGE (val, 1, size) ? val : -1;
+}
+
/* Generate code to push X onto the stack, assuming it has mode MODE and
type TYPE.
MODE is redundant except when X is a CONST_INT (since they don't
carry mode info).
SIZE is an rtx for the size of data to be copied (in bytes),
needed only if X is BLKmode.
+ Return true if successful. May return false if asked to push a
+ partial argument during a sibcall optimization (as specified by
+ SIBCALL_P) and the incoming and outgoing pointers cannot be shown
+ to not overlap.
ALIGN (in bits) is maximum alignment we can assume.
for arguments passed in registers. If nonzero, it will be the number
of bytes required. */
-void
+bool
emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
unsigned int align, int partial, rtx reg, int extra,
rtx args_addr, rtx args_so_far, int reg_parm_stack_space,
- rtx alignment_pad)
+ rtx alignment_pad, bool sibcall_p)
{
rtx xinner;
- enum direction stack_direction
-#ifdef STACK_GROWS_DOWNWARD
- = downward;
-#else
- = upward;
-#endif
+ enum direction stack_direction = STACK_GROWS_DOWNWARD ? downward : upward;
/* Decide where to pad the argument: `downward' for below,
`upward' for above, or `none' for don't pad it.
xinner = x;
+ int nregs = partial / UNITS_PER_WORD;
+ rtx *tmp_regs = NULL;
+ int overlapping = 0;
+
if (mode == BLKmode
|| (STRICT_ALIGNMENT && align < GET_MODE_ALIGNMENT (mode)))
{
PARM_BOUNDARY. Assume the caller isn't lying. */
set_mem_align (target, align);
+ /* If part should go in registers and pushing to that part would
+ overwrite some of the values that need to go into regs, load the
+ overlapping values into temporary pseudos to be moved into the hard
+ regs at the end after the stack pushing has completed.
+ We cannot load them directly into the hard regs here because
+ they can be clobbered by the block move expansions.
+ See PR 65358. */
+
+ if (partial > 0 && reg != 0 && mode == BLKmode
+ && GET_CODE (reg) != PARALLEL)
+ {
+ overlapping = memory_load_overlap (XEXP (x, 0), temp, partial);
+ if (overlapping > 0)
+ {
+ gcc_assert (overlapping % UNITS_PER_WORD == 0);
+ overlapping /= UNITS_PER_WORD;
+
+ tmp_regs = XALLOCAVEC (rtx, overlapping);
+
+ for (int i = 0; i < overlapping; i++)
+ tmp_regs[i] = gen_reg_rtx (word_mode);
+
+ for (int i = 0; i < overlapping; i++)
+ emit_move_insn (tmp_regs[i],
+ operand_subword_force (target, i, mode));
+ }
+ else if (overlapping == -1)
+ overlapping = 0;
+ /* Could not determine whether there is overlap.
+ Fail the sibcall. */
+ else
+ {
+ overlapping = 0;
+ if (sibcall_p)
+ return false;
+ }
+ }
emit_block_move (target, xinner, size, BLOCK_OP_CALL_PARM);
}
}
has a size a multiple of a word. */
for (i = size - 1; i >= not_stack; i--)
if (i >= not_stack + offset)
- emit_push_insn (operand_subword_force (x, i, mode),
+ if (!emit_push_insn (operand_subword_force (x, i, mode),
word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
0, args_addr,
GEN_INT (args_offset + ((i - not_stack + skip)
* UNITS_PER_WORD)),
- reg_parm_stack_space, alignment_pad);
+ reg_parm_stack_space, alignment_pad, sibcall_p))
+ return false;
}
else
{
}
}
- /* If part should go in registers, copy that part
- into the appropriate registers. Do this now, at the end,
- since mem-to-mem copies above may do function calls. */
+ /* Move the partial arguments into the registers and any overlapping
+ values that we moved into the pseudos in tmp_regs. */
if (partial > 0 && reg != 0)
{
/* Handle calls that pass values in multiple non-contiguous locations.
if (GET_CODE (reg) == PARALLEL)
emit_group_load (reg, x, type, -1);
else
- {
+ {
gcc_assert (partial % UNITS_PER_WORD == 0);
- move_block_to_reg (REGNO (reg), x, partial / UNITS_PER_WORD, mode);
+ move_block_to_reg (REGNO (reg), x, nregs - overlapping, mode);
+
+ for (int i = 0; i < overlapping; i++)
+ emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg)
+ + nregs - overlapping + i),
+ tmp_regs[i]);
+
}
}
if (alignment_pad && args_addr == 0)
anti_adjust_stack (alignment_pad);
+
+ return true;
}
\f
/* Return X if X can be used as a subtarget in a sequence of arithmetic
offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
address_mode = get_address_mode (to_rtx);
if (GET_MODE (offset_rtx) != address_mode)
- offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+ {
+ /* We cannot be sure that the RTL in offset_rtx is valid outside
+ of a memory address context, so force it into a register
+ before attempting to convert it to the desired mode. */
+ offset_rtx = force_operand (offset_rtx, NULL_RTX);
+ offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+ }
/* If we have an expression in OFFSET_RTX and a non-zero
byte offset in BITPOS, adding the byte offset before the
|| TREE_CODE (to) == SSA_NAME))
{
rtx value;
+ rtx bounds;
push_temp_slots ();
value = expand_normal (from);
+
+ /* Split value and bounds to store them separately. */
+ chkp_split_slot (value, &value, &bounds);
+
if (to_rtx == 0)
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
emit_move_insn (to_rtx, value);
}
+
+ /* Store bounds if required. */
+ if (bounds
+ && (BOUNDED_P (to) || chkp_type_has_pointer (TREE_TYPE (to))))
+ {
+ gcc_assert (MEM_P (to_rtx));
+ chkp_emit_bounds_store (bounds, value, to_rtx);
+ }
+
preserve_temp_slots (to_rtx);
pop_temp_slots ();
return;
/* Compute FROM and store the value in the rtx we got. */
push_temp_slots ();
- result = store_expr (from, to_rtx, 0, nontemporal);
+ result = store_expr_with_bounds (from, to_rtx, 0, nontemporal, to);
preserve_temp_slots (result);
pop_temp_slots ();
return;
If CALL_PARAM_P is nonzero, this is a store into a call param on the
stack, and block moves may need to be treated specially.
- If NONTEMPORAL is true, try using a nontemporal store instruction. */
+ If NONTEMPORAL is true, try using a nontemporal store instruction.
+
+ If BTARGET is not NULL then computed bounds of EXP are
+ associated with BTARGET. */
rtx
-store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
+store_expr_with_bounds (tree exp, rtx target, int call_param_p,
+ bool nontemporal, tree btarget)
{
rtx temp;
rtx alt_rtl = NULL_RTX;
part. */
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
- return store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
- nontemporal);
+ return store_expr_with_bounds (TREE_OPERAND (exp, 1), target,
+ call_param_p, nontemporal, btarget);
}
else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
{
do_pending_stack_adjust ();
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1, -1);
- store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
- nontemporal);
+ store_expr_with_bounds (TREE_OPERAND (exp, 1), target, call_param_p,
+ nontemporal, btarget);
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
- store_expr (TREE_OPERAND (exp, 2), target, call_param_p,
- nontemporal);
+ store_expr_with_bounds (TREE_OPERAND (exp, 2), target, call_param_p,
+ nontemporal, btarget);
emit_label (lab2);
OK_DEFER_POP;
temp = expand_expr (exp, inner_target, VOIDmode,
call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
+ /* Handle bounds returned by call. */
+ if (TREE_CODE (exp) == CALL_EXPR)
+ {
+ rtx bounds;
+ chkp_split_slot (temp, &temp, &bounds);
+ if (bounds && btarget)
+ {
+ gcc_assert (TREE_CODE (btarget) == SSA_NAME);
+ rtx tmp = targetm.calls.load_returned_bounds (bounds);
+ chkp_set_rtl_bounds (btarget, tmp);
+ }
+ }
+
/* If TEMP is a VOIDmode constant, use convert_modes to make
sure that we properly convert it. */
if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode)
(call_param_p
? EXPAND_STACK_PARM : EXPAND_NORMAL),
&alt_rtl, false);
+
+ /* Handle bounds returned by call. */
+ if (TREE_CODE (exp) == CALL_EXPR)
+ {
+ rtx bounds;
+ chkp_split_slot (temp, &temp, &bounds);
+ if (bounds && btarget)
+ {
+ gcc_assert (TREE_CODE (btarget) == SSA_NAME);
+ rtx tmp = targetm.calls.load_returned_bounds (bounds);
+ chkp_set_rtl_bounds (btarget, tmp);
+ }
+ }
}
/* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
return NULL_RTX;
}
+
+/* Same as store_expr_with_bounds but ignoring bounds of EXP. */
+rtx
+store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
+{
+ return store_expr_with_bounds (exp, target, call_param_p, nontemporal, NULL);
+}
\f
/* Return true if field F of structure TYPE is a flexible array. */
&& mode != TYPE_MODE (TREE_TYPE (exp)))
temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
- /* If the modes of TEMP and TARGET are both BLKmode, both
- must be in memory and BITPOS must be aligned on a byte
- boundary. If so, we simply do a block copy. Likewise
- for a BLKmode-like TARGET. */
- if (GET_MODE (temp) == BLKmode
+ /* If TEMP is not a PARALLEL (see below) and its mode and that of TARGET
+ are both BLKmode, both must be in memory and BITPOS must be aligned
+ on a byte boundary. If so, we simply do a block copy. Likewise for
+ a BLKmode-like TARGET. */
+ if (GET_CODE (temp) != PARALLEL
+ && GET_MODE (temp) == BLKmode
&& (GET_MODE (target) == BLKmode
|| (MEM_P (target)
&& GET_MODE_CLASS (GET_MODE (target)) == MODE_INT
if (offset)
{
/* Avoid returning a negative bitpos as this may wreak havoc later. */
- if (wi::neg_p (bit_offset))
+ if (wi::neg_p (bit_offset) || !wi::fits_shwi_p (bit_offset))
{
offset_int mask = wi::mask <offset_int> (LOG2_BITS_PER_UNIT, false);
offset_int tem = bit_offset.and_not (mask);
return exp;
}
-/* Return a tree of sizetype representing the size, in bytes, of the element
- of EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */
-
-tree
-array_ref_element_size (tree exp)
-{
- tree aligned_size = TREE_OPERAND (exp, 3);
- tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
- location_t loc = EXPR_LOCATION (exp);
-
- /* If a size was specified in the ARRAY_REF, it's the size measured
- in alignment units of the element type. So multiply by that value. */
- if (aligned_size)
- {
- /* ??? tree_ssa_useless_type_conversion will eliminate casts to
- sizetype from another type of the same width and signedness. */
- if (TREE_TYPE (aligned_size) != sizetype)
- aligned_size = fold_convert_loc (loc, sizetype, aligned_size);
- return size_binop_loc (loc, MULT_EXPR, aligned_size,
- size_int (TYPE_ALIGN_UNIT (elmt_type)));
- }
-
- /* Otherwise, take the size from that of the element type. Substitute
- any PLACEHOLDER_EXPR that we have. */
- else
- return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (elmt_type), exp);
-}
-
-/* Return a tree representing the lower bound of the array mentioned in
- EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */
-
-tree
-array_ref_low_bound (tree exp)
-{
- tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
-
- /* If a lower bound is specified in EXP, use it. */
- if (TREE_OPERAND (exp, 2))
- return TREE_OPERAND (exp, 2);
-
- /* Otherwise, if there is a domain type and it has a lower bound, use it,
- substituting for a PLACEHOLDER_EXPR as needed. */
- if (domain_type && TYPE_MIN_VALUE (domain_type))
- return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MIN_VALUE (domain_type), exp);
-
- /* Otherwise, return a zero of the appropriate type. */
- return build_int_cst (TREE_TYPE (TREE_OPERAND (exp, 1)), 0);
-}
-
-/* Returns true if REF is an array reference to an array at the end of
- a structure. If this is the case, the array may be allocated larger
- than its upper bound implies. */
-
-bool
-array_at_struct_end_p (tree ref)
-{
- if (TREE_CODE (ref) != ARRAY_REF
- && TREE_CODE (ref) != ARRAY_RANGE_REF)
- return false;
-
- while (handled_component_p (ref))
- {
- /* If the reference chain contains a component reference to a
- non-union type and there follows another field the reference
- is not at the end of a structure. */
- if (TREE_CODE (ref) == COMPONENT_REF
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE)
- {
- tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1));
- while (nextf && TREE_CODE (nextf) != FIELD_DECL)
- nextf = DECL_CHAIN (nextf);
- if (nextf)
- return false;
- }
-
- ref = TREE_OPERAND (ref, 0);
- }
-
- /* If the reference is based on a declared entity, the size of the array
- is constrained by its given domain. */
- if (DECL_P (ref))
- return false;
-
- return true;
-}
-
-/* Return a tree representing the upper bound of the array mentioned in
- EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */
-
-tree
-array_ref_up_bound (tree exp)
-{
- tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
-
- /* If there is a domain type and it has an upper bound, use it, substituting
- for a PLACEHOLDER_EXPR as needed. */
- if (domain_type && TYPE_MAX_VALUE (domain_type))
- return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MAX_VALUE (domain_type), exp);
-
- /* Otherwise fail. */
- return NULL_TREE;
-}
-
-/* Return a tree representing the offset, in bytes, of the field referenced
- by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
-
-tree
-component_ref_field_offset (tree exp)
-{
- tree aligned_offset = TREE_OPERAND (exp, 2);
- tree field = TREE_OPERAND (exp, 1);
- location_t loc = EXPR_LOCATION (exp);
-
- /* If an offset was specified in the COMPONENT_REF, it's the offset measured
- in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT. So multiply by that
- value. */
- if (aligned_offset)
- {
- /* ??? tree_ssa_useless_type_conversion will eliminate casts to
- sizetype from another type of the same width and signedness. */
- if (TREE_TYPE (aligned_offset) != sizetype)
- aligned_offset = fold_convert_loc (loc, sizetype, aligned_offset);
- return size_binop_loc (loc, MULT_EXPR, aligned_offset,
- size_int (DECL_OFFSET_ALIGN (field)
- / BITS_PER_UNIT));
- }
-
- /* Otherwise, take the offset from that of the field. Substitute
- any PLACEHOLDER_EXPR that we have. */
- else
- return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
-}
-
/* Alignment in bits the TARGET of an assignment may be assumed to have. */
static unsigned HOST_WIDE_INT
return MAX (factor, talign);
}
\f
-#ifdef HAVE_conditional_move
/* Convert the tree comparison code TCODE to the rtl one where the
signedness is UNSIGNEDP. */
}
return code;
}
-#endif
/* 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
MODIFIER argument is as documented by expand_expr. */
-static void
+void
expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
enum expand_modifier modifier)
{
break;
case COMPOUND_LITERAL_EXPR:
- /* Allow COMPOUND_LITERAL_EXPR in initializers, if e.g.
- rtl_for_decl_init is called on DECL_INITIAL with
- COMPOUNT_LITERAL_EXPRs in it, they aren't gimplified. */
- if (modifier == EXPAND_INITIALIZER
- && COMPOUND_LITERAL_EXPR_DECL (exp))
+ /* Allow COMPOUND_LITERAL_EXPR in initializers or coming from
+ initializers, if e.g. rtl_for_decl_init is called on DECL_INITIAL
+ with COMPOUND_LITERAL_EXPRs in it, or ARRAY_REF on a const static
+ array with address of COMPOUND_LITERAL_EXPR in DECL_INITIAL;
+ the initializers aren't gimplified. */
+ if (COMPOUND_LITERAL_EXPR_DECL (exp)
+ && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
return expand_expr_addr_expr_1 (COMPOUND_LITERAL_EXPR_DECL (exp),
target, tmode, modifier, as);
/* FALLTHRU */
tree treeop1 ATTRIBUTE_UNUSED,
tree treeop2 ATTRIBUTE_UNUSED)
{
-#ifdef HAVE_conditional_move
rtx insn;
rtx op00, op01, op1, op2;
enum rtx_code comparison_code;
unsignedp = TYPE_UNSIGNED (type);
comparison_code = convert_tree_comp_to_rtx (cmpcode, unsignedp);
}
- else if (TREE_CODE_CLASS (TREE_CODE (treeop0)) == tcc_comparison)
+ else if (COMPARISON_CLASS_P (treeop0))
{
tree type = TREE_TYPE (TREE_OPERAND (treeop0, 0));
enum tree_code cmpcode = TREE_CODE (treeop0);
op00 = expand_normal (treeop0);
op01 = const0_rtx;
comparison_code = NE;
- comparison_mode = TYPE_MODE (TREE_TYPE (treeop0));
+ comparison_mode = GET_MODE (op00);
+ if (comparison_mode == VOIDmode)
+ comparison_mode = TYPE_MODE (TREE_TYPE (treeop0));
}
if (GET_MODE (op1) != mode)
/* Otherwise discard the sequence and fall back to code with
branches. */
end_sequence ();
-#endif
return NULL_RTX;
}
enum expand_modifier modifier)
{
rtx op0, op1, op2, temp;
+ rtx_code_label *lab;
tree type;
int unsignedp;
machine_mode mode;
Thus the following special case checks need only
check the second operand. */
if (TREE_CODE (treeop0) == INTEGER_CST)
- {
- tree t1 = treeop0;
- treeop0 = treeop1;
- treeop1 = t1;
- }
+ std::swap (treeop0, treeop1);
/* First, check if we have a multiplication of one signed and one
unsigned operand. */
}
def0 = get_def_for_expr (treeop0, NEGATE_EXPR);
+ /* The multiplication is commutative - look at its 2nd operand
+ if the first isn't fed by a negate. */
+ if (!def0)
+ {
+ def0 = get_def_for_expr (treeop1, NEGATE_EXPR);
+ /* Swap operands if the 2nd operand is fed by a negate. */
+ if (def0)
+ std::swap (treeop0, treeop1);
+ }
def2 = get_def_for_expr (treeop2, NEGATE_EXPR);
op0 = op2 = NULL;
Thus the following special case checks need only
check the second operand. */
if (TREE_CODE (treeop0) == INTEGER_CST)
- {
- tree t1 = treeop0;
- treeop0 = treeop1;
- treeop1 = t1;
- }
+ std::swap (treeop0, treeop1);
/* Attempt to return something suitable for generating an
indexed address, for machines that support that. */
/* If op1 was placed in target, swap op0 and op1. */
if (target != op0 && target == op1)
- {
- temp = op0;
- op0 = op1;
- op1 = temp;
- }
+ std::swap (op0, op1);
/* We generate better code and avoid problems with op1 mentioning
target by forcing op1 into a pseudo if it isn't a constant. */
if (code == MIN_EXPR)
comparison_code = LT;
}
-#ifdef HAVE_conditional_move
+
/* Use a conditional move if possible. */
if (can_conditionally_move_p (mode))
{
branches. */
end_sequence ();
}
-#endif
+
if (target != op0)
emit_move_insn (target, op0);
- temp = gen_label_rtx ();
+ lab = gen_label_rtx ();
do_compare_rtx_and_jump (target, cmpop1, comparison_code,
- unsignedp, mode, NULL_RTX, NULL_RTX, temp,
+ unsignedp, mode, NULL_RTX, NULL, lab,
-1);
}
emit_move_insn (target, op1);
- emit_label (temp);
+ emit_label (lab);
return target;
case BIT_NOT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
case LTGT_EXPR:
- temp = do_store_flag (ops,
- modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
- tmode != VOIDmode ? tmode : mode);
- if (temp)
- return temp;
-
- /* Use a compare and a jump for BLKmode comparisons, or for function
- type comparisons is HAVE_canonicalize_funcptr_for_compare. */
-
- if ((target == 0
- || modifier == EXPAND_STACK_PARM
- || ! safe_from_p (target, treeop0, 1)
- || ! safe_from_p (target, treeop1, 1)
- /* Make sure we don't have a hard reg (such as function's return
- value) live across basic blocks, if not optimizing. */
- || (!optimize && REG_P (target)
- && REGNO (target) < FIRST_PSEUDO_REGISTER)))
- target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+ {
+ temp = do_store_flag (ops,
+ modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
+ tmode != VOIDmode ? tmode : mode);
+ if (temp)
+ return temp;
- emit_move_insn (target, const0_rtx);
+ /* Use a compare and a jump for BLKmode comparisons, or for function
+ type comparisons is HAVE_canonicalize_funcptr_for_compare. */
+
+ if ((target == 0
+ || modifier == EXPAND_STACK_PARM
+ || ! safe_from_p (target, treeop0, 1)
+ || ! safe_from_p (target, treeop1, 1)
+ /* Make sure we don't have a hard reg (such as function's return
+ value) live across basic blocks, if not optimizing. */
+ || (!optimize && REG_P (target)
+ && REGNO (target) < FIRST_PSEUDO_REGISTER)))
+ target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
- op1 = gen_label_rtx ();
- jumpifnot_1 (code, treeop0, treeop1, op1, -1);
+ emit_move_insn (target, const0_rtx);
- if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
- emit_move_insn (target, constm1_rtx);
- else
- emit_move_insn (target, const1_rtx);
+ rtx_code_label *lab1 = gen_label_rtx ();
+ jumpifnot_1 (code, treeop0, treeop1, lab1, -1);
- emit_label (op1);
- return target;
+ if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+ emit_move_insn (target, constm1_rtx);
+ else
+ emit_move_insn (target, const1_rtx);
+ emit_label (lab1);
+ return target;
+ }
case COMPLEX_EXPR:
/* Get the rtx code of the operands. */
op0 = expand_normal (treeop0);
return temp;
}
- case VEC_RSHIFT_EXPR:
- {
- target = expand_vec_shift_expr (ops, target);
- return target;
- }
-
case VEC_UNPACK_HI_EXPR:
case VEC_UNPACK_LO_EXPR:
{
}
case COND_EXPR:
- /* A COND_EXPR with its type being VOID_TYPE represents a
- conditional jump and is handled in
- expand_gimple_cond_expr. */
- gcc_assert (!VOID_TYPE_P (type));
-
- /* Note that COND_EXPRs whose type is a structure or union
- are required to be constructed to contain assignments of
- a temporary variable, so that we can evaluate them here
- for side effect only. If type is void, we must do likewise. */
-
- gcc_assert (!TREE_ADDRESSABLE (type)
- && !ignore
- && TREE_TYPE (treeop1) != void_type_node
- && TREE_TYPE (treeop2) != void_type_node);
-
- temp = expand_cond_expr_using_cmove (treeop0, treeop1, treeop2);
- if (temp)
- return temp;
-
- /* If we are not to produce a result, we have no target. Otherwise,
- if a target was specified use it; it will not be used as an
- intermediate target unless it is safe. If no target, use a
- temporary. */
-
- if (modifier != EXPAND_STACK_PARM
- && original_target
- && safe_from_p (original_target, treeop0, 1)
- && GET_MODE (original_target) == mode
- && !MEM_P (original_target))
- temp = original_target;
- else
- temp = assign_temp (type, 0, 1);
-
- do_pending_stack_adjust ();
- NO_DEFER_POP;
- op0 = gen_label_rtx ();
- op1 = gen_label_rtx ();
- jumpifnot (treeop0, op0, -1);
- store_expr (treeop1, temp,
- modifier == EXPAND_STACK_PARM,
- false);
-
- emit_jump_insn (gen_jump (op1));
- emit_barrier ();
- emit_label (op0);
- store_expr (treeop2, temp,
- modifier == EXPAND_STACK_PARM,
- false);
+ {
+ /* A COND_EXPR with its type being VOID_TYPE represents a
+ conditional jump and is handled in
+ expand_gimple_cond_expr. */
+ gcc_assert (!VOID_TYPE_P (type));
+
+ /* Note that COND_EXPRs whose type is a structure or union
+ are required to be constructed to contain assignments of
+ a temporary variable, so that we can evaluate them here
+ for side effect only. If type is void, we must do likewise. */
+
+ gcc_assert (!TREE_ADDRESSABLE (type)
+ && !ignore
+ && TREE_TYPE (treeop1) != void_type_node
+ && TREE_TYPE (treeop2) != void_type_node);
+
+ temp = expand_cond_expr_using_cmove (treeop0, treeop1, treeop2);
+ if (temp)
+ return temp;
- emit_label (op1);
- OK_DEFER_POP;
- return temp;
+ /* If we are not to produce a result, we have no target. Otherwise,
+ if a target was specified use it; it will not be used as an
+ intermediate target unless it is safe. If no target, use a
+ temporary. */
+
+ if (modifier != EXPAND_STACK_PARM
+ && original_target
+ && safe_from_p (original_target, treeop0, 1)
+ && GET_MODE (original_target) == mode
+ && !MEM_P (original_target))
+ temp = original_target;
+ else
+ temp = assign_temp (type, 0, 1);
+
+ do_pending_stack_adjust ();
+ NO_DEFER_POP;
+ rtx_code_label *lab0 = gen_label_rtx ();
+ rtx_code_label *lab1 = gen_label_rtx ();
+ jumpifnot (treeop0, lab0, -1);
+ store_expr (treeop1, temp,
+ modifier == EXPAND_STACK_PARM,
+ false);
+
+ emit_jump_insn (gen_jump (lab1));
+ emit_barrier ();
+ emit_label (lab0);
+ store_expr (treeop2, temp,
+ modifier == EXPAND_STACK_PARM,
+ false);
+
+ emit_label (lab1);
+ OK_DEFER_POP;
+ return temp;
+ }
case VEC_COND_EXPR:
target = expand_vec_cond_expr (type, treeop0, treeop1, treeop2, target);
/* Fallthru */
case GIMPLE_BINARY_RHS:
ops.op1 = gimple_assign_rhs2 (g);
+
+ /* Try to expand conditonal compare. */
+ if (targetm.gen_ccmp_first)
+ {
+ gcc_checking_assert (targetm.gen_ccmp_next != NULL);
+ r = expand_ccmp_expr (g);
+ if (r)
+ break;
+ }
/* Fallthru */
case GIMPLE_UNARY_RHS:
ops.op0 = gimple_assign_rhs1 (g);
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode1, &unsignedp, &volatilep, true);
rtx orig_op0, memloc;
- bool mem_attrs_from_type = false;
+ bool clear_mem_expr = false;
/* If we got back the original object, something is wrong. Perhaps
we are evaluating an expression too early. In any event, don't
memloc = assign_temp (TREE_TYPE (tem), 1, 1);
emit_move_insn (memloc, op0);
op0 = memloc;
- mem_attrs_from_type = true;
+ clear_mem_expr = true;
}
if (offset)
address_mode = get_address_mode (op0);
if (GET_MODE (offset_rtx) != address_mode)
- offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+ {
+ /* We cannot be sure that the RTL in offset_rtx is valid outside
+ of a memory address context, so force it into a register
+ before attempting to convert it to the desired mode. */
+ offset_rtx = force_operand (offset_rtx, NULL_RTX);
+ offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+ }
/* See the comment in expand_assignment for the rationale. */
if (mode1 != VOIDmode
if (op0 == orig_op0)
op0 = copy_rtx (op0);
- /* If op0 is a temporary because of forcing to memory, pass only the
- type to set_mem_attributes so that the original expression is never
- marked as ADDRESSABLE through MEM_EXPR of the temporary. */
- if (mem_attrs_from_type)
- set_mem_attributes (op0, type, 0);
- else
- set_mem_attributes (op0, exp, 0);
+ set_mem_attributes (op0, exp, 0);
if (REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+ /* If op0 is a temporary because the original expressions was forced
+ to memory, clear MEM_EXPR so that the original expression cannot
+ be marked as addressable through MEM_EXPR of the temporary. */
+ if (clear_mem_expr)
+ set_mem_expr (op0, NULL_TREE);
+
MEM_VOLATILE_P (op0) |= volatilep;
if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
|| modifier == EXPAND_CONST_ADDRESS
if (fndecl && DECL_BUILT_IN (fndecl))
{
gcc_assert (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_FRONTEND);
- return expand_builtin (exp, target, subtarget, tmode, ignore);
+ if (CALL_WITH_BOUNDS_P (exp))
+ return expand_builtin_with_bounds (exp, target, subtarget,
+ tmode, ignore);
+ else
+ return expand_builtin (exp, target, subtarget, tmode, ignore);
}
}
return expand_call (exp, target, ignore);
if ((icode = optab_handler (movmisalign_optab, mode))
!= CODE_FOR_nothing)
{
- rtx reg, insn;
+ rtx reg;
op0 = adjust_address (op0, mode, 0);
/* We've already validated the memory, and we're creating a
reg = gen_reg_rtx (mode);
/* Nor can the insn generator. */
- insn = GEN_FCN (icode) (reg, op0);
+ rtx_insn *insn = GEN_FCN (icode) (reg, op0);
emit_insn (insn);
return reg;
}
{
enum rtx_code code;
tree arg0, arg1, type;
- tree tem;
machine_mode operand_mode;
int unsignedp;
rtx op0, op1;
if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST
|| TREE_CODE (arg0) == FIXED_CST)
{
- tem = arg0; arg0 = arg1; arg1 = tem;
+ std::swap (arg0, arg1);
code = swap_condition (code);
}
}
/* Attempt to generate a tablejump instruction; same concept. */
-#ifndef HAVE_tablejump
-#define HAVE_tablejump 0
-#define gen_tablejump(x, y) (0)
-#endif
-
/* Subroutine of the next function.
INDEX is the value being switched on, with the lowest value
return XEXP (DECL_RTL (personality), 0);
}
+/* Returns a tree for the size of EXP in bytes. */
+
+static tree
+tree_expr_size (const_tree exp)
+{
+ if (DECL_P (exp)
+ && DECL_SIZE_UNIT (exp) != 0)
+ return DECL_SIZE_UNIT (exp);
+ else
+ return size_in_bytes (TREE_TYPE (exp));
+}
+
+/* Return an rtx for the size in bytes of the value of EXP. */
+
+rtx
+expr_size (tree exp)
+{
+ tree size;
+
+ if (TREE_CODE (exp) == WITH_SIZE_EXPR)
+ size = TREE_OPERAND (exp, 1);
+ else
+ {
+ size = tree_expr_size (exp);
+ gcc_assert (size);
+ gcc_assert (size == SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, exp));
+ }
+
+ return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), EXPAND_NORMAL);
+}
+
+/* Return a wide integer for the size in bytes of the value of EXP, or -1
+ if the size can vary or is larger than an integer. */
+
+static HOST_WIDE_INT
+int_expr_size (tree exp)
+{
+ tree size;
+
+ if (TREE_CODE (exp) == WITH_SIZE_EXPR)
+ size = TREE_OPERAND (exp, 1);
+ else
+ {
+ size = tree_expr_size (exp);
+ gcc_assert (size);
+ }
+
+ if (size == 0 || !tree_fits_shwi_p (size))
+ return -1;
+
+ return tree_to_shwi (size);
+}
+
#include "gt-expr.h"