@@ -56,7 +56,7 @@ trunc_int_for_mode (HOST_WIDE_INT c, machine_mode mode)
int width = GET_MODE_PRECISION (smode);
/* You want to truncate to a _what_? */
- gcc_assert (SCALAR_INT_MODE_P (mode));
+ gcc_assert (SCALAR_INT_MODE_P (mode) || COMPLEX_INT_MODE_P (mode));
/* Canonicalize BImode to 0 and STORE_FLAG_VALUE. */
if (smode == BImode)
@@ -3847,8 +3847,14 @@ emit_move_complex_parts (rtx x, rtx y)
&& REG_P (x) && !reg_overlap_mentioned_p (x, y))
emit_clobber (x);
- write_complex_part (x, read_complex_part (y, REAL_P), REAL_P, true);
- write_complex_part (x, read_complex_part (y, IMAG_P), IMAG_P, false);
+ machine_mode mode = GET_MODE (x);
+ if (optab_handler (mov_optab, mode) != CODE_FOR_nothing)
+ write_complex_part (x, read_complex_part (y, BOTH_P), BOTH_P, false);
+ else
+ {
+ write_complex_part (x, read_complex_part (y, REAL_P), REAL_P, true);
+ write_complex_part (x, read_complex_part (y, IMAG_P), IMAG_P, false);
+ }
return get_last_insn ();
}
@@ -3868,14 +3874,14 @@ emit_move_complex (machine_mode mode, rtx x, rtx y)
/* See if we can coerce the target into moving both values at once, except
for floating point where we favor moving as parts if this is easy. */
- if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ scalar_int_mode imode;
+ if (!int_mode_for_mode (mode).exists (&imode))
+ try_int = false;
+ else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
&& optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing
- && !(REG_P (x)
- && HARD_REGISTER_P (x)
- && REG_NREGS (x) == 1)
- && !(REG_P (y)
- && HARD_REGISTER_P (y)
- && REG_NREGS (y) == 1))
+ && optab_handler (mov_optab, mode) != CODE_FOR_nothing
+ && !(REG_P (x) && HARD_REGISTER_P (x))
+ && !(REG_P (y) && HARD_REGISTER_P (y)))
try_int = false;
/* Not possible if the values are inherently not adjacent. */
else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
@@ -10246,9 +10252,14 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
break;
}
- /* Move the real (op0) and imaginary (op1) parts to their location. */
- write_complex_part (target, op0, REAL_P, true);
- write_complex_part (target, op1, IMAG_P, false);
+ if ((op0 == op1) && (GET_CODE (op0) == CONST_VECTOR))
+ write_complex_part (target, op0, BOTH_P, false);
+ else
+ {
+ /* Move the real (op0) and imaginary (op1) parts to their location. */
+ write_complex_part (target, op0, REAL_P, true);
+ write_complex_part (target, op1, IMAG_P, false);
+ }
return target;
@@ -11001,6 +11012,51 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
return original_target;
}
+ else if (original_target && (GET_CODE (original_target) == REG)
+ &&
+ ((GET_MODE_CLASS (GET_MODE (original_target)) ==
+ MODE_COMPLEX_INT)
+ || (GET_MODE_CLASS (GET_MODE (original_target)) ==
+ MODE_COMPLEX_FLOAT)))
+ {
+ mode = TYPE_MODE (TREE_TYPE (exp));
+
+ /* Move both parts at the same time if possible */
+ if (TREE_COMPLEX_BOTH_PARTS (exp) != NULL)
+ {
+ op0 =
+ expand_expr (TREE_COMPLEX_BOTH_PARTS (exp), original_target,
+ mode, EXPAND_NORMAL);
+ write_complex_part (original_target, op0, BOTH_P, false);
+ }
+ else
+ {
+ mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+
+ rtx rtarg = gen_reg_rtx (mode);
+ rtx itarg = gen_reg_rtx (mode);
+ op0 =
+ expand_expr (TREE_REALPART (exp), rtarg, mode, EXPAND_NORMAL);
+ op1 =
+ expand_expr (TREE_IMAGPART (exp), itarg, mode, EXPAND_NORMAL);
+
+ write_complex_part (original_target, op0, REAL_P, false);
+ write_complex_part (original_target, op1, IMAG_P, false);
+
+ return original_target;
+ }
+ }
+ /* TODO use a finer grain approach than just size of 2 words */
+ else if ((TREE_COMPLEX_BOTH_PARTS (exp) != NULL)
+ && (known_le (GET_MODE_BITSIZE (mode), 2 * BITS_PER_WORD)))
+ {
+ op0 =
+ expand_expr (TREE_COMPLEX_BOTH_PARTS (exp), original_target, mode,
+ EXPAND_NORMAL);
+ rtx tmp = gen_reg_rtx (mode);
+ write_complex_part (tmp, op0, BOTH_P, false);
+ return tmp;
+ }
/* fall through */
@@ -13347,6 +13403,10 @@ const_vector_from_tree (tree exp)
else if (TREE_CODE (elt) == FIXED_CST)
builder.quick_push (CONST_FIXED_FROM_FIXED_VALUE
(TREE_FIXED_CST (elt), inner));
+ else if (TREE_CODE (elt) == COMPLEX_CST)
+ builder.quick_push (expand_expr
+ (TREE_COMPLEX_BOTH_PARTS (elt), NULL_RTX, mode,
+ EXPAND_NORMAL));
else
builder.quick_push (immed_wide_int_const (wi::to_poly_wide (elt),
inner));
@@ -119,6 +119,12 @@ extern const unsigned char mode_class[NUM_MACHINE_MODES];
|| GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT \
|| GET_MODE_CLASS (MODE) == MODE_VECTOR_FLOAT)
+#define COMPLEX_INT_MODE_P(MODE) \
+ (GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT)
+
+#define COMPLEX_FLOAT_MODE_P(MODE) \
+ (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)
+
/* Nonzero if MODE is a complex mode. */
#define COMPLEX_MODE_P(MODE) \
(GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT \
@@ -190,19 +190,34 @@ gen_int_libfunc (optab optable, const char *opname, char suffix,
int maxsize = 2 * BITS_PER_WORD;
int minsize = BITS_PER_WORD;
scalar_int_mode int_mode;
+ complex_mode cplx_int_mode;
+ int bitsize;
+ bool cplx = false;
- if (!is_int_mode (mode, &int_mode))
+ if (is_int_mode (mode, &int_mode))
+ bitsize = GET_MODE_BITSIZE (int_mode);
+ else if (is_complex_int_mode (mode, &cplx_int_mode))
+ {
+ cplx = true;
+ bitsize = GET_MODE_BITSIZE (cplx_int_mode);
+ }
+ else
return;
+
if (maxsize < LONG_LONG_TYPE_SIZE)
maxsize = LONG_LONG_TYPE_SIZE;
if (minsize > INT_TYPE_SIZE
&& (trapv_binoptab_p (optable)
|| trapv_unoptab_p (optable)))
minsize = INT_TYPE_SIZE;
- if (GET_MODE_BITSIZE (int_mode) < minsize
- || GET_MODE_BITSIZE (int_mode) > maxsize)
+
+ if (bitsize < minsize || bitsize > maxsize)
return;
- gen_libfunc (optable, opname, suffix, int_mode);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT)
+ gen_libfunc (optable, opname, suffix, int_mode);
+ else if (cplx)
+ gen_libfunc (optable, opname, suffix, cplx_int_mode);
}
/* Like gen_libfunc, but verify that FP and set decimal prefix if needed. */
@@ -280,9 +295,11 @@ void
gen_intv_fp_libfunc (optab optable, const char *name, char suffix,
machine_mode mode)
{
- if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
+ if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT
+ || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
- if (GET_MODE_CLASS (mode) == MODE_INT)
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
{
int len = strlen (name);
char *v_name = XALLOCAVEC (char, len + 2);
@@ -189,7 +189,8 @@ extern const struct real_format *
: (gcc_unreachable (), 0)])
#define FLOAT_MODE_FORMAT(MODE) \
- (REAL_MODE_FORMAT (as_a <scalar_float_mode> (GET_MODE_INNER (MODE))))
+ (REAL_MODE_FORMAT (as_a <scalar_float_mode> \
+ (GET_MODE_INNER ((COMPLEX_FLOAT_MODE_P (MODE)) ? (GET_MODE_INNER (MODE)) : (MODE)))))
/* The following macro determines whether the floating point format is
composite, i.e. may contain non-consecutive mantissa bits, in which
@@ -1441,6 +1441,7 @@ general_operand (rtx op, machine_mode mode)
if the caller wants something floating. */
if (GET_MODE (op) == VOIDmode && mode != VOIDmode
&& GET_MODE_CLASS (mode) != MODE_INT
+ && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return false;