[Bug tree-optimization/99728] code pessimization when using wrapper classes around SIMD types

rguenth at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Wed Jul 14 11:37:40 GMT 2021


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99728

--- Comment #18 from Richard Biener <rguenth at gcc dot gnu.org> ---
OTOH we call is_really_empty_class which for not trivially empty classes ends
up
walking all non-FIELD_DECL fields as well:

      for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
        if (TREE_CODE (field) == FIELD_DECL
            && !DECL_ARTIFICIAL (field)
            /* An unnamed bit-field is not a data member.  */
            && !DECL_UNNAMED_BIT_FIELD (field)
            && !is_really_empty_class (TREE_TYPE (field), ignore_vptr))
          return false;

So the following performs single-member copying optimization (also avoiding
the as-base special-casing when the copy involves a single member).  The
copy_single_member function is based on is_really_empty_class which could
be refactored to also compute this as alternate output.  In principle the
single member to copy could be inside an aggregate member/base so as-is
this doesn't always avoid an aggregate copy if the single member in 'type'
is an aggregate.  It fixes the testcase fully.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index e4df72ec1a3..31eea7c935b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -8881,6 +8881,41 @@ immediate_invocation_p (tree fn, int nargs)
          && (nargs > 1 || !source_location_current_p (fn)));
 }

+/* Return the FIELD_DECL of the single member of TYPE that needs to be copied
+   by copy assignment if any or NULL_TREE if there are none or multiple.  */
+
+static tree
+copy_single_member (tree type)
+{
+  if (!CLASS_TYPE_P (type))
+    return NULL_TREE;
+
+  tree binfo;
+  tree base_binfo;
+  int i;
+  for (binfo = TYPE_BINFO (type), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
+    if (!is_really_empty_class (BINFO_TYPE (base_binfo), true))
+      return NULL_TREE;
+
+  tree single_field = NULL_TREE;
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    {
+      if (TREE_CODE (field) != FIELD_DECL)
+       continue;
+      if (!(!DECL_ARTIFICIAL (field)
+           /* An unnamed bit-field is not a data member.  */
+           && !DECL_UNNAMED_BIT_FIELD (field)
+           && !is_really_empty_class (TREE_TYPE (field), true)))
+       continue;
+      if (single_field)
+       return NULL_TREE;
+      single_field = field;
+    }
+
+  return single_field;
+}
+
 /* Subroutine of the various build_*_call functions.  Overload resolution
    has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
    ARGS is a TREE_LIST of the unconverted arguments to the call.  FLAGS is a
@@ -9501,6 +9536,16 @@ build_over_call (struct z_candidate *cand, int flags,
tsubst_flags_t complain)
          val = build2 (COMPOUND_EXPR, type, arg, to);
          suppress_warning (val, OPT_Wunused);
        }
+      else if (tree field = copy_single_member (type))
+       {
+         arg = cp_build_fold_indirect_ref (arg);
+         tree t = build2 (MODIFY_EXPR, TREE_TYPE (field),
+                          build3 (COMPONENT_REF, TREE_TYPE (field),
+                                  to, field, NULL_TREE),
+                          build3 (COMPONENT_REF, TREE_TYPE (field),
+                                  arg, field, NULL_TREE));
+         val = build2 (COMPOUND_EXPR, type, t, to);
+         suppress_warning (val, OPT_Wunused);
+       }
       else if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base)))
        {
          if (is_std_init_list (type)


More information about the Gcc-bugs mailing list