Support registers of complex types in rtl. Also adapt the functions
called during the expand pass to support native complex operations.

gcc/ChangeLog:

        * explow.cc (trunc_int_for_mode): Allow complex int modes
        * expr.cc (emit_move_complex_parts): Move both parts at the
        same time if it is supported by the backend
        (emit_move_complex): Do not move via integer if not int mode
        corresponds. For complex floats, relax the constraint on the
        number of registers for targets with pairs of registers, and
        use native moves if it is supported by the backend.
        (expand_expr_real_2): Move both parts at the same time if it
        is supported by the backend
        (expand_expr_real_1): Update the expand of complex constants
        (const_vector_from_tree): Add the expand of both parts of a
        complex constant
        * real.h: update FLOAT_MODE_FORMAT
        * machmode.h: Add COMPLEX_INT_MODE_P and COMPLEX_FLOAT_MODE_P
        predicates
        * optabs-libfuncs.cc (gen_int_libfunc): Add support for
        complex modes
        (gen_intv_fp_libfunc): Likewise
        * recog.cc (general_operand): Likewise
---
 gcc/explow.cc          |  2 +-
 gcc/expr.cc            | 84 ++++++++++++++++++++++++++++++++++++------
 gcc/machmode.h         |  6 +++
 gcc/optabs-libfuncs.cc | 29 ++++++++++++---
 gcc/real.h             |  3 +-
 gcc/recog.cc           |  1 +
 6 files changed, 105 insertions(+), 20 deletions(-)

diff --git a/gcc/explow.cc b/gcc/explow.cc
index 6424c0802f0..48572a40eab 100644
--- a/gcc/explow.cc
+++ b/gcc/explow.cc
@@ -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)
diff --git a/gcc/expr.cc b/gcc/expr.cc
index e1a0892b4d9..e94de8a05b5 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -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));
diff --git a/gcc/machmode.h b/gcc/machmode.h
index a22df60dc20..b1937eafdc3 100644
--- a/gcc/machmode.h
+++ b/gcc/machmode.h
@@ -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   \
diff --git a/gcc/optabs-libfuncs.cc b/gcc/optabs-libfuncs.cc
index f1abe6916d3..fe390a592eb 100644
--- a/gcc/optabs-libfuncs.cc
+++ b/gcc/optabs-libfuncs.cc
@@ -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);
diff --git a/gcc/real.h b/gcc/real.h
index 9ed6c372b14..53585418e68 100644
--- a/gcc/real.h
+++ b/gcc/real.h
@@ -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
diff --git a/gcc/recog.cc b/gcc/recog.cc
index 37432087812..687fe2b1b8a 100644
--- a/gcc/recog.cc
+++ b/gcc/recog.cc
@@ -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;
 
-- 
2.17.1





Reply via email to