Patchwork PATCH: Replace target MEMBER_TYPE_FORCES_BLK macro with a target hook

login
register
mail settings
Submitter H.J. Lu
Date Aug. 15, 2012, 11:50 p.m.
Message ID <20120815235059.GA12536@intel.com>
Download mbox | patch
Permalink /patch/177881/
State New
Headers show

Comments

H.J. Lu - Aug. 15, 2012, 11:50 p.m.
Hi,

This patch replaces MEMBER_TYPE_FORCES_BLK with a target hook.  I
also pass the type to the target hook in addition to field, which will
be used by i386 backend for

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20020

This patch doesn't change code generation.  Tested on Linux/x86-64. I
also tested cross compilers to ia64-hpux, powerpc-linux and xtensa-linux
up to cc1.  OK to install?

Thanks.


H.J.
---
2012-08-15  H.J. Lu  <hongjiu.lu@intel.com>

	* stor-layout.c (compute_record_mode): Replace
	MEMBER_TYPE_FORCES_BLK with targetm.member_type_forces_blk.
	(layout_type): Likewise.

	* system.h: Poison MEMBER_TYPE_FORCES_BLK.

	* target.def (member_type_forces_blk): New target hook.

	* targhooks.c (default_member_type_forces_blk): New.
	* targhooks.h (default_member_type_forces_blk): Likewise.

	* doc/tm.texi.in (MEMBER_TYPE_FORCES_BLK): Renamed to ...
	(TARGET_MEMBER_TYPE_FORCES_BLK): This.
	* doc/tm.texi: Regenerated.

	* config/ia64/hpux.h (MEMBER_TYPE_FORCES_BLK): Removed.

	* config/ia64/ia64.c (ia64_member_type_forces_blk): New
	function.
	(TARGET_MEMBER_TYPE_FORCES_BLK): New macro.

	* config/rs6000/rs6000.c (TARGET_MEMBER_TYPE_FORCES_BLK): New
	macro.
	(rs6000_member_type_forces_blk): New function.

	* config/rs6000/rs6000.h (MEMBER_TYPE_FORCES_BLK): Removed.

	* config/xtensa/xtensa.c (xtensa_member_type_forces_blk): New
	function.
	(TARGET_MEMBER_TYPE_FORCES_BLK): New macro.

	* config/xtensa/xtensa.h (MEMBER_TYPE_FORCES_BLK): Removed.
Richard Guenther - Aug. 16, 2012, 10:09 a.m.
On Thu, Aug 16, 2012 at 1:50 AM, H.J. Lu <hongjiu.lu@intel.com> wrote:
> Hi,
>
> This patch replaces MEMBER_TYPE_FORCES_BLK with a target hook.  I
> also pass the type to the target hook in addition to field, which will
> be used by i386 backend for
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20020
>
> This patch doesn't change code generation.  Tested on Linux/x86-64. I
> also tested cross compilers to ia64-hpux, powerpc-linux and xtensa-linux
> up to cc1.  OK to install?

Isn't the type just always DECL_FIELD_CONTEXT (field)?

Btw, with C++ you no longer need ATTRIBUTE_UNUSED, just give the
parameter no name.

Richard.

> Thanks.
>
>
> H.J.
> ---
> 2012-08-15  H.J. Lu  <hongjiu.lu@intel.com>
>
>         * stor-layout.c (compute_record_mode): Replace
>         MEMBER_TYPE_FORCES_BLK with targetm.member_type_forces_blk.
>         (layout_type): Likewise.
>
>         * system.h: Poison MEMBER_TYPE_FORCES_BLK.
>
>         * target.def (member_type_forces_blk): New target hook.
>
>         * targhooks.c (default_member_type_forces_blk): New.
>         * targhooks.h (default_member_type_forces_blk): Likewise.
>
>         * doc/tm.texi.in (MEMBER_TYPE_FORCES_BLK): Renamed to ...
>         (TARGET_MEMBER_TYPE_FORCES_BLK): This.
>         * doc/tm.texi: Regenerated.
>
>         * config/ia64/hpux.h (MEMBER_TYPE_FORCES_BLK): Removed.
>
>         * config/ia64/ia64.c (ia64_member_type_forces_blk): New
>         function.
>         (TARGET_MEMBER_TYPE_FORCES_BLK): New macro.
>
>         * config/rs6000/rs6000.c (TARGET_MEMBER_TYPE_FORCES_BLK): New
>         macro.
>         (rs6000_member_type_forces_blk): New function.
>
>         * config/rs6000/rs6000.h (MEMBER_TYPE_FORCES_BLK): Removed.
>
>         * config/xtensa/xtensa.c (xtensa_member_type_forces_blk): New
>         function.
>         (TARGET_MEMBER_TYPE_FORCES_BLK): New macro.
>
>         * config/xtensa/xtensa.h (MEMBER_TYPE_FORCES_BLK): Removed.
>
> diff --git a/gcc/config/ia64/hpux.h b/gcc/config/ia64/hpux.h
> index ad106b4..d9ae109 100644
> --- a/gcc/config/ia64/hpux.h
> +++ b/gcc/config/ia64/hpux.h
> @@ -115,9 +115,6 @@ do {                                                        \
>  #define TARGET_DEFAULT \
>    (MASK_DWARF2_ASM | MASK_BIG_ENDIAN | MASK_ILP32)
>
> -/* ??? Might not be needed anymore.  */
> -#define MEMBER_TYPE_FORCES_BLK(FIELD, MODE) ((MODE) == TFmode)
> -
>  /* ASM_OUTPUT_EXTERNAL_LIBCALL defaults to just a globalize_label call,
>     but that doesn't put out the @function type information which causes
>     shared library problems.  */
> diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
> index c7fb559..f3585b1 100644
> --- a/gcc/config/ia64/ia64.c
> +++ b/gcc/config/ia64/ia64.c
> @@ -319,6 +319,8 @@ static const char *ia64_invalid_binary_op (int, const_tree, const_tree);
>  static enum machine_mode ia64_c_mode_for_suffix (char);
>  static void ia64_trampoline_init (rtx, tree, rtx);
>  static void ia64_override_options_after_change (void);
> +static bool ia64_member_type_forces_blk (const_tree, const_tree,
> +                                        enum machine_mode);
>
>  static tree ia64_builtin_decl (unsigned, bool);
>
> @@ -570,6 +572,9 @@ static const struct attribute_spec ia64_attribute_table[] =
>  #undef TARGET_GET_RAW_ARG_MODE
>  #define TARGET_GET_RAW_ARG_MODE ia64_get_reg_raw_mode
>
> +#undef TARGET_MEMBER_TYPE_FORCES_BLK
> +#define TARGET_MEMBER_TYPE_FORCES_BLK ia64_member_type_forces_blk
> +
>  #undef TARGET_GIMPLIFY_VA_ARG_EXPR
>  #define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg
>
> @@ -11153,6 +11158,17 @@ ia64_get_reg_raw_mode (int regno)
>    return default_get_reg_raw_mode(regno);
>  }
>
> +/* Implement TARGET_MEMBER_TYPE_FORCES_BLK.  ??? Might not be needed
> +   anymore.  */
> +
> +bool
> +ia64_member_type_forces_blk (const_tree type ATTRIBUTE_UNUSED,
> +                            const_tree field ATTRIBUTE_UNUSED,
> +                            enum machine_mode mode)
> +{
> +  return TARGET_HPUX && mode == TFmode;
> +}
> +
>  /* Always default to .text section until HP-UX linker is fixed.  */
>
>  ATTRIBUTE_UNUSED static section *
> diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
> index 34948fb..5b2d9f0 100644
> --- a/gcc/config/rs6000/rs6000.c
> +++ b/gcc/config/rs6000/rs6000.c
> @@ -1302,6 +1302,9 @@ static const struct attribute_spec rs6000_attribute_table[] =
>  #undef TARGET_INIT_DWARF_REG_SIZES_EXTRA
>  #define TARGET_INIT_DWARF_REG_SIZES_EXTRA rs6000_init_dwarf_reg_sizes_extra
>
> +#undef TARGET_MEMBER_TYPE_FORCES_BLK
> +#define TARGET_MEMBER_TYPE_FORCES_BLK rs6000_member_type_forces_blk
> +
>  /* On rs6000, function arguments are promoted, as are function return
>     values.  */
>  #undef TARGET_PROMOTE_FUNCTION_MODE
> @@ -7287,6 +7290,27 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
>   emit_set:
>    emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
>  }
> +
> +/* Return true if TYPE containing FIELD should be accessed using
> +   `BLKMODE'.
> +
> +   For the SPE, simd types are V2SI, and gcc can be tempted to put the
> +   entire thing in a DI and use subregs to access the internals.
> +   store_bit_field() will force (subreg:DI (reg:V2SI x))'s to the
> +   back-end.  Because a single GPR can hold a V2SI, but not a DI, the
> +   best thing to do is set structs to BLKmode and avoid Severe Tire
> +   Damage.
> +
> +   On e500 v2, DF and DI modes suffer from the same anomaly.  DF can
> +   fit into 1, whereas DI still needs two.  */
> +
> +static bool
> +rs6000_member_type_forces_blk (const_tree type ATTRIBUTE_UNUSED,
> +                              const_tree field, enum machine_mode mode)
> +{
> +  return ((TARGET_SPE && TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
> +         || (TARGET_E500_DOUBLE && mode == DFmode));
> +}
>
>  /* Nonzero if we can use a floating-point register to pass this arg.  */
>  #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)                \
> diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
> index ec62fc6..ab26f7f 100644
> --- a/gcc/config/rs6000/rs6000.h
> +++ b/gcc/config/rs6000/rs6000.h
> @@ -701,22 +701,6 @@ extern unsigned rs6000_pointer_size;
>  /* Every structure's size must be a multiple of this.  */
>  #define STRUCTURE_SIZE_BOUNDARY 8
>
> -/* Return 1 if a structure or array containing FIELD should be
> -   accessed using `BLKMODE'.
> -
> -   For the SPE, simd types are V2SI, and gcc can be tempted to put the
> -   entire thing in a DI and use subregs to access the internals.
> -   store_bit_field() will force (subreg:DI (reg:V2SI x))'s to the
> -   back-end.  Because a single GPR can hold a V2SI, but not a DI, the
> -   best thing to do is set structs to BLKmode and avoid Severe Tire
> -   Damage.
> -
> -   On e500 v2, DF and DI modes suffer from the same anomaly.  DF can
> -   fit into 1, whereas DI still needs two.  */
> -#define MEMBER_TYPE_FORCES_BLK(FIELD, MODE) \
> -  ((TARGET_SPE && TREE_CODE (TREE_TYPE (FIELD)) == VECTOR_TYPE) \
> -   || (TARGET_E500_DOUBLE && (MODE) == DFmode))
> -
>  /* A bit-field declared as `int' forces `int' alignment for the struct.  */
>  #define PCC_BITFIELD_TYPE_MATTERS 1
>
> diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
> index fa38008..1d69881 100644
> --- a/gcc/config/xtensa/xtensa.c
> +++ b/gcc/config/xtensa/xtensa.c
> @@ -175,6 +175,9 @@ static reg_class_t xtensa_secondary_reload (bool, rtx, reg_class_t,
>  static bool constantpool_address_p (const_rtx addr);
>  static bool xtensa_legitimate_constant_p (enum machine_mode, rtx);
>
> +static bool xtensa_member_type_forces_blk (const_tree, const_tree,
> +                                          enum machine_mode mode);
> +
>  static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
>    REG_ALLOC_ORDER;
>
> @@ -210,6 +213,9 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
>  #undef TARGET_ADDRESS_COST
>  #define TARGET_ADDRESS_COST hook_int_rtx_bool_0
>
> +#undef TARGET_MEMBER_TYPE_FORCES_BLK
> +#define TARGET_MEMBER_TYPE_FORCES_BLK xtensa_member_type_forces_blk
> +
>  #undef TARGET_BUILD_BUILTIN_VA_LIST
>  #define TARGET_BUILD_BUILTIN_VA_LIST xtensa_build_builtin_va_list
>
> @@ -2738,6 +2744,20 @@ xtensa_return_addr (int count, rtx frame)
>    return result;
>  }
>
> +/* Disable the use of word-sized or smaller complex modes for structures,
> +   and for function arguments in particular, where they cause problems with
> +   register a7.  The xtensa_copy_incoming_a7 function assumes that there is
> +   a single reference to an argument in a7, but with small complex modes the
> +   real and imaginary components may be extracted separately, leading to two
> +   uses of the register, only one of which would be replaced.  */
> +
> +static bool
> +xtensa_member_type_forces_blk (const_tree type ATTRIBUTE_UNUSED,
> +                              const_tree field ATTRIBUTE_UNUSED,
> +                              enum machine_mode mode)
> +{
> +  return mode == CQImode || mode == CHImode;
> +}
>
>  /* Create the va_list data type.
>
> diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h
> index b1a24c6..50e221a 100644
> --- a/gcc/config/xtensa/xtensa.h
> +++ b/gcc/config/xtensa/xtensa.h
> @@ -165,15 +165,6 @@ extern unsigned xtensa_current_frame_size;
>     bitfields and the structures that contain them.  */
>  #define PCC_BITFIELD_TYPE_MATTERS 1
>
> -/* Disable the use of word-sized or smaller complex modes for structures,
> -   and for function arguments in particular, where they cause problems with
> -   register a7.  The xtensa_copy_incoming_a7 function assumes that there is
> -   a single reference to an argument in a7, but with small complex modes the
> -   real and imaginary components may be extracted separately, leading to two
> -   uses of the register, only one of which would be replaced.  */
> -#define MEMBER_TYPE_FORCES_BLK(FIELD, MODE) \
> -  ((MODE) == CQImode || (MODE) == CHImode)
> -
>  /* Align string constants and constructors to at least a word boundary.
>     The typical use of this macro is to increase alignment for string
>     constants to be word aligned so that 'strcpy' calls that copy
> diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
> index 2a2d500..81371de 100644
> --- a/gcc/doc/tm.texi
> +++ b/gcc/doc/tm.texi
> @@ -1262,9 +1262,9 @@ these accesses should use the bitfield container type.
>  The default is @code{!TARGET_STRICT_ALIGN}.
>  @end deftypefn
>
> -@defmac MEMBER_TYPE_FORCES_BLK (@var{field}, @var{mode})
> -Return 1 if a structure or array containing @var{field} should be accessed using
> -@code{BLKMODE}.
> +@deftypefn {Target Hook} bool TARGET_MEMBER_TYPE_FORCES_BLK (const_tree @var{type}, const_tree @var{field}, enum machine_mode @var{mode})
> +Return true if a structure, union or array @var{type} with @var{mode}
> +containing @var{field} should be accessed using @code{BLKMODE}.
>
>  If @var{field} is the only field in the structure, @var{mode} is its
>  mode, otherwise @var{mode} is VOIDmode.  @var{mode} is provided in the
> @@ -1272,7 +1272,7 @@ case where structures of one field would require the structure's mode to
>  retain the field's mode.
>
>  Normally, this is not needed.
> -@end defmac
> +@end deftypefn
>
>  @defmac ROUND_TYPE_ALIGN (@var{type}, @var{computed}, @var{specified})
>  Define this macro as an expression for the alignment of a type (given
> diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
> index e7d9cec..2888a95 100644
> --- a/gcc/doc/tm.texi.in
> +++ b/gcc/doc/tm.texi.in
> @@ -1240,9 +1240,9 @@ these accesses should use the bitfield container type.
>  The default is @code{!TARGET_STRICT_ALIGN}.
>  @end deftypefn
>
> -@defmac MEMBER_TYPE_FORCES_BLK (@var{field}, @var{mode})
> -Return 1 if a structure or array containing @var{field} should be accessed using
> -@code{BLKMODE}.
> +@hook TARGET_MEMBER_TYPE_FORCES_BLK
> +Return true if a structure, union or array @var{type} with @var{mode}
> +containing @var{field} should be accessed using @code{BLKMODE}.
>
>  If @var{field} is the only field in the structure, @var{mode} is its
>  mode, otherwise @var{mode} is VOIDmode.  @var{mode} is provided in the
> @@ -1250,7 +1250,7 @@ case where structures of one field would require the structure's mode to
>  retain the field's mode.
>
>  Normally, this is not needed.
> -@end defmac
> +@end deftypefn
>
>  @defmac ROUND_TYPE_ALIGN (@var{type}, @var{computed}, @var{specified})
>  Define this macro as an expression for the alignment of a type (given
> diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
> index 53554a9..5679258 100644
> --- a/gcc/stor-layout.c
> +++ b/gcc/stor-layout.c
> @@ -1627,13 +1627,10 @@ compute_record_mode (tree type)
>        if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field)))
>         mode = DECL_MODE (field);
>
> -#ifdef MEMBER_TYPE_FORCES_BLK
> -      /* With some targets, eg. c4x, it is sub-optimal
> -        to access an aligned BLKmode structure as a scalar.  */
> -
> -      if (MEMBER_TYPE_FORCES_BLK (field, mode))
> +      /* With some targets, it is sub-optimal to access an aligned
> +        BLKmode structure as a scalar.  */
> +      if (targetm.member_type_forces_blk (type, field, mode))
>         return;
> -#endif /* MEMBER_TYPE_FORCES_BLK  */
>      }
>
>    /* If we only have one real field; use its mode if that mode's size
> @@ -2270,9 +2267,7 @@ layout_type (tree type)
>         TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element);
>         SET_TYPE_MODE (type, BLKmode);
>         if (TYPE_SIZE (type) != 0
> -#ifdef MEMBER_TYPE_FORCES_BLK
> -           && ! MEMBER_TYPE_FORCES_BLK (type, VOIDmode)
> -#endif
> +           && ! targetm.member_type_forces_blk (type, type, VOIDmode)
>             /* BLKmode elements force BLKmode aggregate;
>                else extract/store fields may lose.  */
>             && (TYPE_MODE (TREE_TYPE (type)) != BLKmode
> diff --git a/gcc/system.h b/gcc/system.h
> index 9e7d503..48c9c89 100644
> --- a/gcc/system.h
> +++ b/gcc/system.h
> @@ -808,7 +808,7 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
>         CAN_DEBUG_WITHOUT_FP UNLIKELY_EXECUTED_TEXT_SECTION_NAME        \
>         HOT_TEXT_SECTION_NAME LEGITIMATE_CONSTANT_P ALWAYS_STRIP_DOTDOT \
>         OUTPUT_ADDR_CONST_EXTRA SMALL_REGISTER_CLASSES ASM_OUTPUT_IDENT \
> -       ASM_BYTE_OP
> +       ASM_BYTE_OP MEMBER_TYPE_FORCES_BLK
>
>  /* Target macros only used for code built for the target, that have
>     moved to libgcc-tm.h or have never been present elsewhere.  */
> diff --git a/gcc/target.def b/gcc/target.def
> index 5ac6d48..1bd5533 100644
> --- a/gcc/target.def
> +++ b/gcc/target.def
> @@ -2332,6 +2332,14 @@ DEFHOOK
>   tree, (tree type, tree expr),
>   hook_tree_tree_tree_null)
>
> +/* True if TYPE with MODE containing FIELD should be accessed using
> +   BLKmode.  */
> +DEFHOOK
> +(member_type_forces_blk,
> + "",
> + bool, (const_tree type, const_tree field, enum machine_mode mode),
> + default_member_type_forces_blk)
> +
>  /* Return the class for a secondary reload, and fill in extra information.  */
>  DEFHOOK
>  (secondary_reload,
> diff --git a/gcc/targhooks.c b/gcc/targhooks.c
> index 52a9912..a28c421 100644
> --- a/gcc/targhooks.c
> +++ b/gcc/targhooks.c
> @@ -1513,4 +1513,14 @@ default_pch_valid_p (const void *data_p, size_t len)
>    return NULL;
>  }
>
> +/* Default version of member_type_forces_blk.  */
> +
> +bool
> +default_member_type_forces_blk (const_tree ARG_UNUSED (type),
> +                               const_tree ARG_UNUSED (field),
> +                               enum machine_mode ARG_UNUSED (mode))
> +{
> +  return false;
> +}
> +
>  #include "gt-targhooks.h"
> diff --git a/gcc/targhooks.h b/gcc/targhooks.h
> index f1cc403..ac49c82 100644
> --- a/gcc/targhooks.h
> +++ b/gcc/targhooks.h
> @@ -189,3 +189,5 @@ extern const char *default_pch_valid_p (const void *, size_t);
>
>  extern void default_asm_output_ident_directive (const char*);
>
> +extern bool default_member_type_forces_blk (const_tree, const_tree,
> +                                           enum machine_mode);

Patch

diff --git a/gcc/config/ia64/hpux.h b/gcc/config/ia64/hpux.h
index ad106b4..d9ae109 100644
--- a/gcc/config/ia64/hpux.h
+++ b/gcc/config/ia64/hpux.h
@@ -115,9 +115,6 @@  do {							\
 #define TARGET_DEFAULT \
   (MASK_DWARF2_ASM | MASK_BIG_ENDIAN | MASK_ILP32)
 
-/* ??? Might not be needed anymore.  */
-#define MEMBER_TYPE_FORCES_BLK(FIELD, MODE) ((MODE) == TFmode)
-
 /* ASM_OUTPUT_EXTERNAL_LIBCALL defaults to just a globalize_label call,
    but that doesn't put out the @function type information which causes
    shared library problems.  */
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index c7fb559..f3585b1 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -319,6 +319,8 @@  static const char *ia64_invalid_binary_op (int, const_tree, const_tree);
 static enum machine_mode ia64_c_mode_for_suffix (char);
 static void ia64_trampoline_init (rtx, tree, rtx);
 static void ia64_override_options_after_change (void);
+static bool ia64_member_type_forces_blk (const_tree, const_tree,
+					 enum machine_mode);
 
 static tree ia64_builtin_decl (unsigned, bool);
 
@@ -570,6 +572,9 @@  static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_GET_RAW_ARG_MODE
 #define TARGET_GET_RAW_ARG_MODE ia64_get_reg_raw_mode
 
+#undef TARGET_MEMBER_TYPE_FORCES_BLK
+#define TARGET_MEMBER_TYPE_FORCES_BLK ia64_member_type_forces_blk
+
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg
 
@@ -11153,6 +11158,17 @@  ia64_get_reg_raw_mode (int regno)
   return default_get_reg_raw_mode(regno);
 }
 
+/* Implement TARGET_MEMBER_TYPE_FORCES_BLK.  ??? Might not be needed
+   anymore.  */
+
+bool
+ia64_member_type_forces_blk (const_tree type ATTRIBUTE_UNUSED,
+			     const_tree field ATTRIBUTE_UNUSED,
+			     enum machine_mode mode)
+{
+  return TARGET_HPUX && mode == TFmode;
+}
+
 /* Always default to .text section until HP-UX linker is fixed.  */
 
 ATTRIBUTE_UNUSED static section *
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 34948fb..5b2d9f0 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -1302,6 +1302,9 @@  static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_INIT_DWARF_REG_SIZES_EXTRA
 #define TARGET_INIT_DWARF_REG_SIZES_EXTRA rs6000_init_dwarf_reg_sizes_extra
 
+#undef TARGET_MEMBER_TYPE_FORCES_BLK
+#define TARGET_MEMBER_TYPE_FORCES_BLK rs6000_member_type_forces_blk
+
 /* On rs6000, function arguments are promoted, as are function return
    values.  */
 #undef TARGET_PROMOTE_FUNCTION_MODE
@@ -7287,6 +7290,27 @@  rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
  emit_set:
   emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
 }
+
+/* Return true if TYPE containing FIELD should be accessed using
+   `BLKMODE'.
+
+   For the SPE, simd types are V2SI, and gcc can be tempted to put the
+   entire thing in a DI and use subregs to access the internals.
+   store_bit_field() will force (subreg:DI (reg:V2SI x))'s to the
+   back-end.  Because a single GPR can hold a V2SI, but not a DI, the
+   best thing to do is set structs to BLKmode and avoid Severe Tire
+   Damage.
+
+   On e500 v2, DF and DI modes suffer from the same anomaly.  DF can
+   fit into 1, whereas DI still needs two.  */
+
+static bool
+rs6000_member_type_forces_blk (const_tree type ATTRIBUTE_UNUSED,
+			       const_tree field, enum machine_mode mode)
+{
+  return ((TARGET_SPE && TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
+	  || (TARGET_E500_DOUBLE && mode == DFmode));
+}
 
 /* Nonzero if we can use a floating-point register to pass this arg.  */
 #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index ec62fc6..ab26f7f 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -701,22 +701,6 @@  extern unsigned rs6000_pointer_size;
 /* Every structure's size must be a multiple of this.  */
 #define STRUCTURE_SIZE_BOUNDARY 8
 
-/* Return 1 if a structure or array containing FIELD should be
-   accessed using `BLKMODE'.
-
-   For the SPE, simd types are V2SI, and gcc can be tempted to put the
-   entire thing in a DI and use subregs to access the internals.
-   store_bit_field() will force (subreg:DI (reg:V2SI x))'s to the
-   back-end.  Because a single GPR can hold a V2SI, but not a DI, the
-   best thing to do is set structs to BLKmode and avoid Severe Tire
-   Damage.
-
-   On e500 v2, DF and DI modes suffer from the same anomaly.  DF can
-   fit into 1, whereas DI still needs two.  */
-#define MEMBER_TYPE_FORCES_BLK(FIELD, MODE) \
-  ((TARGET_SPE && TREE_CODE (TREE_TYPE (FIELD)) == VECTOR_TYPE) \
-   || (TARGET_E500_DOUBLE && (MODE) == DFmode))
-
 /* A bit-field declared as `int' forces `int' alignment for the struct.  */
 #define PCC_BITFIELD_TYPE_MATTERS 1
 
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index fa38008..1d69881 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -175,6 +175,9 @@  static reg_class_t xtensa_secondary_reload (bool, rtx, reg_class_t,
 static bool constantpool_address_p (const_rtx addr);
 static bool xtensa_legitimate_constant_p (enum machine_mode, rtx);
 
+static bool xtensa_member_type_forces_blk (const_tree, const_tree,
+					   enum machine_mode mode);
+
 static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
   REG_ALLOC_ORDER;
 
@@ -210,6 +213,9 @@  static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST hook_int_rtx_bool_0
 
+#undef TARGET_MEMBER_TYPE_FORCES_BLK
+#define TARGET_MEMBER_TYPE_FORCES_BLK xtensa_member_type_forces_blk
+
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST xtensa_build_builtin_va_list
 
@@ -2738,6 +2744,20 @@  xtensa_return_addr (int count, rtx frame)
   return result;
 }
 
+/* Disable the use of word-sized or smaller complex modes for structures,
+   and for function arguments in particular, where they cause problems with
+   register a7.  The xtensa_copy_incoming_a7 function assumes that there is
+   a single reference to an argument in a7, but with small complex modes the
+   real and imaginary components may be extracted separately, leading to two
+   uses of the register, only one of which would be replaced.  */
+
+static bool
+xtensa_member_type_forces_blk (const_tree type ATTRIBUTE_UNUSED,
+			       const_tree field ATTRIBUTE_UNUSED,
+			       enum machine_mode mode)
+{
+  return mode == CQImode || mode == CHImode;
+}
 
 /* Create the va_list data type.
 
diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h
index b1a24c6..50e221a 100644
--- a/gcc/config/xtensa/xtensa.h
+++ b/gcc/config/xtensa/xtensa.h
@@ -165,15 +165,6 @@  extern unsigned xtensa_current_frame_size;
    bitfields and the structures that contain them.  */
 #define PCC_BITFIELD_TYPE_MATTERS 1
 
-/* Disable the use of word-sized or smaller complex modes for structures,
-   and for function arguments in particular, where they cause problems with
-   register a7.  The xtensa_copy_incoming_a7 function assumes that there is
-   a single reference to an argument in a7, but with small complex modes the
-   real and imaginary components may be extracted separately, leading to two
-   uses of the register, only one of which would be replaced.  */
-#define MEMBER_TYPE_FORCES_BLK(FIELD, MODE) \
-  ((MODE) == CQImode || (MODE) == CHImode)
-
 /* Align string constants and constructors to at least a word boundary.
    The typical use of this macro is to increase alignment for string
    constants to be word aligned so that 'strcpy' calls that copy
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 2a2d500..81371de 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1262,9 +1262,9 @@  these accesses should use the bitfield container type.
 The default is @code{!TARGET_STRICT_ALIGN}.
 @end deftypefn
 
-@defmac MEMBER_TYPE_FORCES_BLK (@var{field}, @var{mode})
-Return 1 if a structure or array containing @var{field} should be accessed using
-@code{BLKMODE}.
+@deftypefn {Target Hook} bool TARGET_MEMBER_TYPE_FORCES_BLK (const_tree @var{type}, const_tree @var{field}, enum machine_mode @var{mode})
+Return true if a structure, union or array @var{type} with @var{mode}
+containing @var{field} should be accessed using @code{BLKMODE}.
 
 If @var{field} is the only field in the structure, @var{mode} is its
 mode, otherwise @var{mode} is VOIDmode.  @var{mode} is provided in the
@@ -1272,7 +1272,7 @@  case where structures of one field would require the structure's mode to
 retain the field's mode.
 
 Normally, this is not needed.
-@end defmac
+@end deftypefn
 
 @defmac ROUND_TYPE_ALIGN (@var{type}, @var{computed}, @var{specified})
 Define this macro as an expression for the alignment of a type (given
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index e7d9cec..2888a95 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -1240,9 +1240,9 @@  these accesses should use the bitfield container type.
 The default is @code{!TARGET_STRICT_ALIGN}.
 @end deftypefn
 
-@defmac MEMBER_TYPE_FORCES_BLK (@var{field}, @var{mode})
-Return 1 if a structure or array containing @var{field} should be accessed using
-@code{BLKMODE}.
+@hook TARGET_MEMBER_TYPE_FORCES_BLK
+Return true if a structure, union or array @var{type} with @var{mode}
+containing @var{field} should be accessed using @code{BLKMODE}.
 
 If @var{field} is the only field in the structure, @var{mode} is its
 mode, otherwise @var{mode} is VOIDmode.  @var{mode} is provided in the
@@ -1250,7 +1250,7 @@  case where structures of one field would require the structure's mode to
 retain the field's mode.
 
 Normally, this is not needed.
-@end defmac
+@end deftypefn
 
 @defmac ROUND_TYPE_ALIGN (@var{type}, @var{computed}, @var{specified})
 Define this macro as an expression for the alignment of a type (given
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 53554a9..5679258 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -1627,13 +1627,10 @@  compute_record_mode (tree type)
       if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field)))
 	mode = DECL_MODE (field);
 
-#ifdef MEMBER_TYPE_FORCES_BLK
-      /* With some targets, eg. c4x, it is sub-optimal
-	 to access an aligned BLKmode structure as a scalar.  */
-
-      if (MEMBER_TYPE_FORCES_BLK (field, mode))
+      /* With some targets, it is sub-optimal to access an aligned
+	 BLKmode structure as a scalar.  */
+      if (targetm.member_type_forces_blk (type, field, mode))
 	return;
-#endif /* MEMBER_TYPE_FORCES_BLK  */
     }
 
   /* If we only have one real field; use its mode if that mode's size
@@ -2270,9 +2267,7 @@  layout_type (tree type)
 	TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element);
 	SET_TYPE_MODE (type, BLKmode);
 	if (TYPE_SIZE (type) != 0
-#ifdef MEMBER_TYPE_FORCES_BLK
-	    && ! MEMBER_TYPE_FORCES_BLK (type, VOIDmode)
-#endif
+	    && ! targetm.member_type_forces_blk (type, type, VOIDmode)
 	    /* BLKmode elements force BLKmode aggregate;
 	       else extract/store fields may lose.  */
 	    && (TYPE_MODE (TREE_TYPE (type)) != BLKmode
diff --git a/gcc/system.h b/gcc/system.h
index 9e7d503..48c9c89 100644
--- a/gcc/system.h
+++ b/gcc/system.h
@@ -808,7 +808,7 @@  extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 	CAN_DEBUG_WITHOUT_FP UNLIKELY_EXECUTED_TEXT_SECTION_NAME	\
 	HOT_TEXT_SECTION_NAME LEGITIMATE_CONSTANT_P ALWAYS_STRIP_DOTDOT	\
 	OUTPUT_ADDR_CONST_EXTRA SMALL_REGISTER_CLASSES ASM_OUTPUT_IDENT	\
-	ASM_BYTE_OP
+	ASM_BYTE_OP MEMBER_TYPE_FORCES_BLK
 
 /* Target macros only used for code built for the target, that have
    moved to libgcc-tm.h or have never been present elsewhere.  */
diff --git a/gcc/target.def b/gcc/target.def
index 5ac6d48..1bd5533 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2332,6 +2332,14 @@  DEFHOOK
  tree, (tree type, tree expr),
  hook_tree_tree_tree_null)
 
+/* True if TYPE with MODE containing FIELD should be accessed using
+   BLKmode.  */
+DEFHOOK
+(member_type_forces_blk,
+ "",
+ bool, (const_tree type, const_tree field, enum machine_mode mode),
+ default_member_type_forces_blk)
+
 /* Return the class for a secondary reload, and fill in extra information.  */
 DEFHOOK
 (secondary_reload,
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 52a9912..a28c421 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -1513,4 +1513,14 @@  default_pch_valid_p (const void *data_p, size_t len)
   return NULL;
 }
 
+/* Default version of member_type_forces_blk.  */
+
+bool
+default_member_type_forces_blk (const_tree ARG_UNUSED (type),
+				const_tree ARG_UNUSED (field),
+				enum machine_mode ARG_UNUSED (mode))
+{
+  return false;
+}
+
 #include "gt-targhooks.h"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index f1cc403..ac49c82 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -189,3 +189,5 @@  extern const char *default_pch_valid_p (const void *, size_t);
 
 extern void default_asm_output_ident_directive (const char*);
 
+extern bool default_member_type_forces_blk (const_tree, const_tree,
+					    enum machine_mode);