Add a new target hook for complex element creation during
the expand pass, called gen_rtx_complex. The default implementation
calls gen_rtx_CONCAT like before. Then calls to gen_rtx_CONCAT for
complex handling are replaced by calls to targetm.gen_rtx_complex.

gcc/ChangeLog:

        * target.def: Add gen_rtx_complex target hook
        * targhooks.cc (default_gen_rtx_complex): New: Default
        implementation for gen_rtx_complex
        * targhooks.h: Add default_gen_rtx_complex
        * doc/tm.texi: Document TARGET_GEN_RTX_COMPLEX
        * doc/tm.texi.in: Add TARGET_GEN_RTX_COMPLEX
        * emit-rtl.cc (gen_reg_rtx): Replace call to
        gen_rtx_CONCAT by call to gen_rtx_complex
        (init_emit_once): Likewise
        * expmed.cc (flip_storage_order): Likewise
        * optabs.cc (expand_doubleword_mod): Likewise
---
 gcc/doc/tm.texi    |  6 ++++++
 gcc/doc/tm.texi.in |  2 ++
 gcc/emit-rtl.cc    | 26 +++++++++-----------------
 gcc/expmed.cc      |  2 +-
 gcc/optabs.cc      | 12 +++++++-----
 gcc/target.def     | 10 ++++++++++
 gcc/targhooks.cc   | 27 +++++++++++++++++++++++++++
 gcc/targhooks.h    |  2 ++
 8 files changed, 64 insertions(+), 23 deletions(-)

diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 87997b76338..b73147aea9f 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -4605,6 +4605,12 @@ to return a nonzero value when it is required, the 
compiler will run out
 of spill registers and print a fatal error message.
 @end deftypefn
 
+@deftypefn {Target Hook} rtx TARGET_GEN_RTX_COMPLEX (machine_mode @var{mode}, 
rtx @var{real_part}, rtx @var{imag_part})
+This hook should return an rtx representing a complex of mode 
@var{machine_mode} built from @var{real_part} and @var{imag_part}.
+  If both arguments are @code{NULL}, create them as registers.
+ The default is @code{gen_rtx_CONCAT}.
+@end deftypefn
+
 @deftypefn {Target Hook} rtx TARGET_READ_COMPLEX_PART (rtx @var{cplx}, 
complex_part_t @var{part})
 This hook should return the rtx representing the specified @var{part} of the 
complex given by @var{cplx}.
   @var{part} can be the real part, the imaginary part, or both of them.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index efbf972e6a7..dd39e450903 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -3390,6 +3390,8 @@ stack.
 
 @hook TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P
 
+@hook TARGET_GEN_RTX_COMPLEX
+
 @hook TARGET_READ_COMPLEX_PART
 
 @hook TARGET_WRITE_COMPLEX_PART
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
index f6276a2d0b6..22012bfea13 100644
--- a/gcc/emit-rtl.cc
+++ b/gcc/emit-rtl.cc
@@ -1190,19 +1190,7 @@ gen_reg_rtx (machine_mode mode)
   if (generating_concat_p
       && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
          || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT))
-    {
-      /* For complex modes, don't make a single pseudo.
-        Instead, make a CONCAT of two pseudos.
-        This allows noncontiguous allocation of the real and imaginary parts,
-        which makes much better code.  Besides, allocating DCmode
-        pseudos overstrains reload on some machines like the 386.  */
-      rtx realpart, imagpart;
-      machine_mode partmode = GET_MODE_INNER (mode);
-
-      realpart = gen_reg_rtx (partmode);
-      imagpart = gen_reg_rtx (partmode);
-      return gen_rtx_CONCAT (mode, realpart, imagpart);
-    }
+    return targetm.gen_rtx_complex (mode, NULL, NULL);
 
   /* Do not call gen_reg_rtx with uninitialized crtl.  */
   gcc_assert (crtl->emit.regno_pointer_align_length);
@@ -6274,14 +6262,18 @@ init_emit_once (void)
 
   FOR_EACH_MODE_IN_CLASS (mode, MODE_COMPLEX_INT)
     {
-      rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)];
-      const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner);
+      machine_mode imode = GET_MODE_INNER (mode);
+      rtx inner = const_tiny_rtx[0][(int) imode];
+      const_tiny_rtx[0][(int) mode] =
+       targetm.gen_rtx_complex (mode, inner, inner);
     }
 
   FOR_EACH_MODE_IN_CLASS (mode, MODE_COMPLEX_FLOAT)
     {
-      rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)];
-      const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner);
+      machine_mode imode = GET_MODE_INNER (mode);
+      rtx inner = const_tiny_rtx[0][(int) imode];
+      const_tiny_rtx[0][(int) mode] =
+       targetm.gen_rtx_complex (mode, inner, inner);
     }
 
   FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_BOOL)
diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index 2f787cc28f9..8a18161827b 100644
--- a/gcc/expmed.cc
+++ b/gcc/expmed.cc
@@ -400,7 +400,7 @@ flip_storage_order (machine_mode mode, rtx x)
       real = flip_storage_order (GET_MODE_INNER (mode), real);
       imag = flip_storage_order (GET_MODE_INNER (mode), imag);
 
-      return gen_rtx_CONCAT (mode, real, imag);
+      return targetm.gen_rtx_complex (mode, real, imag);
     }
 
   if (UNLIKELY (reverse_storage_order_supported < 0))
diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index 4e9f58f8060..18900e8113e 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -1001,16 +1001,18 @@ expand_doubleword_mod (machine_mode mode, rtx op0, rtx 
op1, bool unsignedp)
          machine_mode cmode = TYPE_MODE (ctype);
          rtx op00 = operand_subword_force (op0, 0, mode);
          rtx op01 = operand_subword_force (op0, 1, mode);
-         rtx cres = gen_rtx_CONCAT (cmode, gen_reg_rtx (word_mode),
-                                    gen_reg_rtx (word_mode));
+         rtx cres = targetm.gen_rtx_complex (cmode, gen_reg_rtx (word_mode),
+                                             gen_reg_rtx (word_mode));
          tree lhs = make_tree (ctype, cres);
          tree arg0 = make_tree (wtype, op00);
          tree arg1 = make_tree (wtype, op01);
          expand_addsub_overflow (UNKNOWN_LOCATION, PLUS_EXPR, lhs, arg0,
                                  arg1, true, true, true, false, NULL);
-         sum = expand_simple_binop (word_mode, PLUS, XEXP (cres, 0),
-                                    XEXP (cres, 1), NULL_RTX, 1,
-                                    OPTAB_DIRECT);
+         sum =
+           expand_simple_binop (word_mode, PLUS,
+                                read_complex_part (cres, REAL_P),
+                                read_complex_part (cres, IMAG_P), NULL_RTX,
+                                1, OPTAB_DIRECT);
          if (sum == NULL_RTX)
            return NULL_RTX;
        }
diff --git a/gcc/target.def b/gcc/target.def
index 9798c0f58e4..ee1dfdc7565 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -3306,6 +3306,16 @@ a pointer to int.",
  bool, (ao_ref *ref),
  default_ref_may_alias_errno)
 
+/* Return the rtx representation of a complex with a specified mode.  */
+DEFHOOK
+(gen_rtx_complex,
+ "This hook should return an rtx representing a complex of mode 
@var{machine_mode} built from @var{real_part} and @var{imag_part}.\n\
+  If both arguments are @code{NULL}, create them as registers.\n\
+ The default is @code{gen_rtx_CONCAT}.",
+ rtx,
+ (machine_mode mode, rtx real_part, rtx imag_part),
+ default_gen_rtx_complex)
+
 /* Returns the value corresponding to the specified part of a complex.  */
 DEFHOOK
 (read_complex_part,
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index d33fcbd9a13..4ea40c643a8 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -1532,6 +1532,33 @@ default_preferred_simd_mode (scalar_mode)
   return word_mode;
 }
 
+/* By default, call gen_rtx_CONCAT.  */
+
+rtx
+default_gen_rtx_complex (machine_mode mode, rtx real_part, rtx imag_part)
+{
+  /* For complex modes, don't make a single pseudo.
+     Instead, make a CONCAT of two pseudos.
+     This allows noncontiguous allocation of the real and imaginary parts,
+     which makes much better code.  Besides, allocating DCmode
+     pseudos overstrains reload on some machines like the 386.  */
+  machine_mode imode = GET_MODE_INNER (mode);
+
+  if (real_part == NULL)
+    real_part = gen_reg_rtx (imode);
+  else
+    gcc_assert ((GET_MODE (real_part) == imode)
+               || (GET_MODE (real_part) == E_VOIDmode));
+
+  if (imag_part == NULL)
+    imag_part = gen_reg_rtx (imode);
+  else
+    gcc_assert ((GET_MODE (imag_part) == imode)
+               || (GET_MODE (imag_part) == E_VOIDmode));
+
+  return gen_rtx_CONCAT (mode, real_part, imag_part);
+}
+
 /* By default, extract one of the components of the complex value CPLX.  
Extract the
    real part if part is REAL_P, and the imaginary part if it is IMAG_P. If 
part is
    BOTH_P, return cplx directly*/
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 805abd96938..811cd6165de 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -124,6 +124,8 @@ extern opt_machine_mode default_get_mask_mode 
(machine_mode);
 extern bool default_empty_mask_is_expensive (unsigned);
 extern vector_costs *default_vectorize_create_costs (vec_info *, bool);
 
+extern rtx default_gen_rtx_complex (machine_mode mode, rtx real_part,
+                                   rtx imag_part);
 extern rtx default_read_complex_part (rtx cplx, complex_part_t part);
 extern void default_write_complex_part (rtx cplx, rtx val,
                                        complex_part_t part,
-- 
2.17.1





Reply via email to