Summary: 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 | 11 ++++++----- gcc/target.def | 10 ++++++++++ gcc/targhooks.cc | 27 +++++++++++++++++++++++++++ gcc/targhooks.h | 2 ++ 8 files changed, 63 insertions(+), 23 deletions(-) diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index c4f935b5746..470497a3ade 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4620,6 +4620,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 b8970761c8d..27a0b321fe0 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -3392,6 +3392,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 973c16a14d3..ce935951781 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 32ff379ffc3..429a20f9cd7 100644 --- a/gcc/optabs.cc +++ b/gcc/optabs.cc @@ -1001,16 +1001,17 @@ 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 f99df939776..d63dacbbb8f 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -3313,6 +3313,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 df852eb18e3..f6e7bc6c141 100644 --- a/gcc/targhooks.cc +++ b/gcc/targhooks.cc @@ -1533,6 +1533,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 dcacc725e27..cf37eea24b5 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