struct move_by_pieces *);
static bool block_move_libcall_safe_for_call_parm (void);
static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned);
-static rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool);
static tree emit_block_move_libcall_fn (int);
static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
static void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
struct store_by_pieces *);
-static rtx clear_storage_via_libcall (rtx, rtx, bool);
static tree clear_storage_libcall_fn (int);
static rtx compress_float_constant (rtx, rtx);
static rtx get_subtarget (rtx);
/* A subroutine of emit_block_move. Expand a call to memcpy.
Return the return value from memcpy, 0 otherwise. */
-static rtx
+rtx
emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall)
{
rtx dst_addr, src_addr;
else if (set_storage_via_setmem (object, size, const0_rtx, align))
;
else
- return clear_storage_via_libcall (object, size,
- method == BLOCK_OP_TAILCALL);
+ return set_storage_via_libcall (object, size, const0_rtx,
+ method == BLOCK_OP_TAILCALL);
return NULL;
}
/* A subroutine of clear_storage. Expand a call to memset.
Return the return value of memset, 0 otherwise. */
-static rtx
-clear_storage_via_libcall (rtx object, rtx size, bool tailcall)
+rtx
+set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
{
- tree call_expr, arg_list, fn, object_tree, size_tree;
+ tree call_expr, arg_list, fn, object_tree, size_tree, val_tree;
enum machine_mode size_mode;
rtx retval;
for returning pointers, we could end up generating incorrect code. */
object_tree = make_tree (ptr_type_node, object);
+ if (GET_CODE (val) != CONST_INT)
+ val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1);
size_tree = make_tree (sizetype, size);
+ val_tree = make_tree (integer_type_node, val);
fn = clear_storage_libcall_fn (true);
arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
- arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list);
+ arg_list = tree_cons (NULL_TREE, val_tree, arg_list);
arg_list = tree_cons (NULL_TREE, object_tree, arg_list);
/* Now we have to build up the CALL_EXPR itself. */
return retval;
}
-/* A subroutine of clear_storage_via_libcall. Create the tree node
+/* A subroutine of set_storage_via_libcall. Create the tree node
for the function we use for block clears. The first time FOR_CALL
is true, we call assemble_external. */
return NULL_RTX;
}
\f
-/* Examine CTOR to discover:
- * how many scalar fields are set to nonzero values,
- and place it in *P_NZ_ELTS;
- * how many scalar fields are set to non-constant values,
- and place it in *P_NC_ELTS; and
- * how many scalar fields in total are in CTOR,
- and place it in *P_ELT_COUNT.
- * if a type is a union, and the initializer from the constructor
- is not the largest element in the union, then set *p_must_clear. */
+/* Helper for categorize_ctor_elements. Identical interface. */
-static void
+static bool
categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
- HOST_WIDE_INT *p_nc_elts,
HOST_WIDE_INT *p_elt_count,
bool *p_must_clear)
{
unsigned HOST_WIDE_INT idx;
- HOST_WIDE_INT nz_elts, nc_elts, elt_count;
+ HOST_WIDE_INT nz_elts, elt_count;
tree value, purpose;
+ /* Whether CTOR is a valid constant initializer, in accordance with what
+ initializer_constant_valid_p does. If inferred from the constructor
+ elements, true until proven otherwise. */
+ bool const_from_elts_p = constructor_static_from_elts_p (ctor);
+ bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor);
+
nz_elts = 0;
- nc_elts = 0;
elt_count = 0;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
{
case CONSTRUCTOR:
{
- HOST_WIDE_INT nz = 0, nc = 0, ic = 0;
- categorize_ctor_elements_1 (value, &nz, &nc, &ic, p_must_clear);
+ HOST_WIDE_INT nz = 0, ic = 0;
+
+ bool const_elt_p
+ = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear);
+
nz_elts += mult * nz;
- nc_elts += mult * nc;
- elt_count += mult * ic;
+ elt_count += mult * ic;
+
+ if (const_from_elts_p && const_p)
+ const_p = const_elt_p;
}
break;
default:
nz_elts += mult;
elt_count += mult;
- if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
- nc_elts += mult;
+
+ if (const_from_elts_p && const_p)
+ const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
+ != NULL_TREE;
break;
}
}
}
*p_nz_elts += nz_elts;
- *p_nc_elts += nc_elts;
*p_elt_count += elt_count;
+
+ return const_p;
}
-void
+/* Examine CTOR to discover:
+ * how many scalar fields are set to nonzero values,
+ and place it in *P_NZ_ELTS;
+ * how many scalar fields in total are in CTOR,
+ and place it in *P_ELT_COUNT.
+ * if a type is a union, and the initializer from the constructor
+ is not the largest element in the union, then set *p_must_clear.
+
+ Return whether or not CTOR is a valid static constant initializer, the same
+ as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0". */
+
+bool
categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
- HOST_WIDE_INT *p_nc_elts,
HOST_WIDE_INT *p_elt_count,
bool *p_must_clear)
{
*p_nz_elts = 0;
- *p_nc_elts = 0;
*p_elt_count = 0;
*p_must_clear = false;
- categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count,
- p_must_clear);
+
+ return
+ categorize_ctor_elements_1 (ctor, p_nz_elts, p_elt_count, p_must_clear);
}
/* Count the number of scalars in TYPE. Return -1 on overflow or
if (TREE_CODE (exp) == CONSTRUCTOR)
{
- HOST_WIDE_INT nz_elts, nc_elts, count, elts;
+ HOST_WIDE_INT nz_elts, count, elts;
bool must_clear;
- categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+ categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
if (must_clear)
return 1;
if (TREE_CODE (exp) == CONSTRUCTOR)
{
- HOST_WIDE_INT nz_elts, nc_elts, count;
+ HOST_WIDE_INT nz_elts, count;
bool must_clear;
- categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+ categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
return nz_elts == 0;
}
case ZERO_EXTEND:
case SIGN_EXTEND:
case TRUNCATE:
+ case FLOAT_EXTEND:
+ case FLOAT_TRUNCATE:
convert_move (target, op1, code == ZERO_EXTEND);
return target;
case tcc_type:
/* Should never get a type here. */
gcc_unreachable ();
+
+ case tcc_gimple_stmt:
+ gcc_unreachable ();
}
/* If we have an rtl, find any enclosed object. Then see if we conflict
/* Handle ERROR_MARK before anybody tries to access its type. */
if (TREE_CODE (exp) == ERROR_MARK
- || TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)
+ || (!GIMPLE_TUPLE_P (exp) && TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK))
{
ret = CONST0_RTX (tmode);
return ret ? ret : const0_rtx;
enum expand_modifier modifier, rtx *alt_rtl)
{
rtx op0, op1, temp, decl_rtl;
- tree type = TREE_TYPE (exp);
+ tree type;
int unsignedp;
enum machine_mode mode;
enum tree_code code = TREE_CODE (exp);
type) \
: (expr))
- mode = TYPE_MODE (type);
- unsignedp = TYPE_UNSIGNED (type);
+ if (GIMPLE_STMT_P (exp))
+ {
+ type = void_type_node;
+ mode = VOIDmode;
+ unsignedp = 0;
+ }
+ else
+ {
+ type = TREE_TYPE (exp);
+ mode = TYPE_MODE (type);
+ unsignedp = TYPE_UNSIGNED (type);
+ }
if (lang_hooks.reduce_bit_field_operations
&& TREE_CODE (type) == INTEGER_TYPE
&& GET_MODE_PRECISION (mode) > TYPE_PRECISION (type))
return temp;
case VECTOR_CST:
- if (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_INT
- || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT)
- return const_vector_from_tree (exp);
- else
- return expand_expr (build_constructor_from_list
- (TREE_TYPE (exp),
- TREE_VECTOR_CST_ELTS (exp)),
- ignore ? const0_rtx : target, tmode, modifier);
+ {
+ tree tmp = NULL_TREE;
+ if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+ || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+ return const_vector_from_tree (exp);
+ if (GET_MODE_CLASS (mode) == MODE_INT)
+ {
+ tree type_for_mode = lang_hooks.types.type_for_mode (mode, 1);
+ if (type_for_mode)
+ tmp = fold_unary (VIEW_CONVERT_EXPR, type_for_mode, exp);
+ }
+ if (!tmp)
+ tmp = build_constructor_from_list (type,
+ TREE_VECTOR_CST_ELTS (exp));
+ return expand_expr (tmp, ignore ? const0_rtx : target,
+ tmode, modifier);
+ }
case CONST_DECL:
return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
return REDUCE_BIT_FIELD (op0);
}
- op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode,
+ modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
if (GET_MODE (op0) == mode)
;
subtarget, &op0, &op1, 0);
return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
- case FIX_ROUND_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_CEIL_EXPR:
- gcc_unreachable (); /* Not used for C. */
-
case FIX_TRUNC_EXPR:
op0 = expand_normal (TREE_OPERAND (exp, 0));
if (target == 0 || modifier == EXPAND_STACK_PARM)
target = expand_vec_cond_expr (exp, target);
return target;
- case MODIFY_EXPR:
+ case GIMPLE_MODIFY_STMT:
{
- tree lhs = TREE_OPERAND (exp, 0);
- tree rhs = TREE_OPERAND (exp, 1);
+ tree lhs = GIMPLE_STMT_OPERAND (exp, 0);
+ tree rhs = GIMPLE_STMT_OPERAND (exp, 1);
gcc_assert (ignore);
return temp;
}
+ case VEC_EXTRACT_EVEN_EXPR:
+ case VEC_EXTRACT_ODD_EXPR:
+ {
+ expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+ NULL_RTX, &op0, &op1, 0);
+ this_optab = optab_for_tree_code (code, type);
+ temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+ OPTAB_WIDEN);
+ gcc_assert (temp);
+ return temp;
+ }
+
+ case VEC_INTERLEAVE_HIGH_EXPR:
+ case VEC_INTERLEAVE_LOW_EXPR:
+ {
+ expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+ NULL_RTX, &op0, &op1, 0);
+ this_optab = optab_for_tree_code (code, type);
+ temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+ OPTAB_WIDEN);
+ gcc_assert (temp);
+ return temp;
+ }
+
case VEC_LSHIFT_EXPR:
case VEC_RSHIFT_EXPR:
{
return target;
}
+ case VEC_UNPACK_HI_EXPR:
+ case VEC_UNPACK_LO_EXPR:
+ {
+ op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+ this_optab = optab_for_tree_code (code, type);
+ temp = expand_widen_pattern_expr (exp, op0, NULL_RTX, NULL_RTX,
+ target, unsignedp);
+ gcc_assert (temp);
+ return temp;
+ }
+
+ case VEC_WIDEN_MULT_HI_EXPR:
+ case VEC_WIDEN_MULT_LO_EXPR:
+ {
+ tree oprnd0 = TREE_OPERAND (exp, 0);
+ tree oprnd1 = TREE_OPERAND (exp, 1);
+
+ expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+ target = expand_widen_pattern_expr (exp, op0, op1, NULL_RTX,
+ target, unsignedp);
+ gcc_assert (target);
+ return target;
+ }
+
+ case VEC_PACK_MOD_EXPR:
+ case VEC_PACK_SAT_EXPR:
+ {
+ mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+ goto binop;
+ }
+
default:
return lang_hooks.expand_expr (exp, original_target, tmode,
modifier, alt_rtl);
tree
string_constant (tree arg, tree *ptr_offset)
{
- tree array, offset;
+ tree array, offset, lower_bound;
STRIP_NOPS (arg);
if (TREE_CODE (arg) == ADDR_EXPR)
if (TREE_CODE (array) != STRING_CST
&& TREE_CODE (array) != VAR_DECL)
return 0;
+
+ /* Check if the array has a non-zero lower bound. */
+ lower_bound = array_ref_low_bound (TREE_OPERAND (arg, 0));
+ if (!integer_zerop (lower_bound))
+ {
+ /* If the offset and base aren't both constants, return 0. */
+ if (TREE_CODE (lower_bound) != INTEGER_CST)
+ return 0;
+ if (TREE_CODE (offset) != INTEGER_CST)
+ return 0;
+ /* Adjust offset by the lower bound. */
+ offset = size_diffop (fold_convert (sizetype, offset),
+ fold_convert (sizetype, lower_bound));
+ }
}
else
return 0;
return 0;
icode = setcc_gen_code[(int) code];
+
+ if (icode == CODE_FOR_nothing)
+ {
+ enum machine_mode wmode;
+
+ for (wmode = operand_mode;
+ icode == CODE_FOR_nothing && wmode != VOIDmode;
+ wmode = GET_MODE_WIDER_MODE (wmode))
+ icode = cstore_optab->handlers[(int) wmode].insn_code;
+ }
+
if (icode == CODE_FOR_nothing
|| (only_cheap && insn_data[(int) icode].operand[0].mode != mode))
{
target = gen_reg_rtx (GET_MODE (target));
emit_move_insn (target, invert ? const0_rtx : const1_rtx);
- result = compare_from_rtx (op0, op1, code, unsignedp,
- operand_mode, NULL_RTX);
- if (GET_CODE (result) == CONST_INT)
- return (((result == const0_rtx && ! invert)
- || (result != const0_rtx && invert))
- ? const0_rtx : const1_rtx);
-
- /* The code of RESULT may not match CODE if compare_from_rtx
- decided to swap its operands and reverse the original code.
-
- We know that compare_from_rtx returns either a CONST_INT or
- a new comparison code, so it is safe to just extract the
- code from RESULT. */
- code = GET_CODE (result);
-
label = gen_label_rtx ();
- gcc_assert (bcc_gen_fctn[(int) code]);
-
- emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
+ do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX,
+ NULL_RTX, label);
+
emit_move_insn (target, invert ? const1_rtx : const0_rtx);
emit_label (label);