diff mbox series

[committed] d: Fix wrong code-gen when returning structs by value.

Message ID 20230628185357.2326251-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Fix wrong code-gen when returning structs by value. | expand

Commit Message

Iain Buclaw June 28, 2023, 6:53 p.m. UTC
Hi,

Since r13-1104, structs in the D have had compute_record_mode called too
early on them, causing them to return differently depending on the order
that types are generated in, and whether there are forward references.

This patch moves the call to compute_record_mode into its own function,
and calls it after all fields have been given a size.

Bootstrapped on i686-apple-darwin17 - previously it failed at stage2 -
as well as bootstrapped and regression tested on x86_64-linux-gnu/-m32.
Committed to mainline, and backported to releases/gcc-13.

Regards,
Iain.

---
	PR d/106977
	PR target/110406

gcc/d/ChangeLog:

	* types.cc (finish_aggregate_mode): New function.
	(finish_incomplete_fields): Call finish_aggregate_mode.
	(finish_aggregate_type): Replace call to compute_record_mode with
	finish_aggregate_mode.

gcc/testsuite/ChangeLog:

	* gdc.dg/torture/pr110406.d: New test.
---
 gcc/d/types.cc                          | 39 ++++++++++++++++++++++---
 gcc/testsuite/gdc.dg/torture/pr110406.d | 25 ++++++++++++++++
 2 files changed, 60 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gdc.dg/torture/pr110406.d
diff mbox series

Patch

diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index bdf07f83d4b..ef2d80e5bd4 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -573,6 +573,35 @@  layout_aggregate_type (AggregateDeclaration *decl, tree type,
     }
 }
 
+/* Given a record type TYPE compute the finalized record mode if all fields have
+   had their types resolved and sizes determined.  */
+
+void
+finish_aggregate_mode (tree type)
+{
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    {
+      /* Fields of type `typeof(*null)' have no size, so let them force the
+	 record type mode to be computed as BLKmode.  */
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (field)) == noreturn_type_node)
+	break;
+
+      if (DECL_SIZE (field) == NULL_TREE)
+	return;
+    }
+
+  compute_record_mode (type);
+
+  /* Propagate computed mode to all variants of this aggregate type.  */
+  for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+    {
+      if (t == type)
+	continue;
+
+      SET_TYPE_MODE (t, TYPE_MODE (type));
+    }
+}
+
 /* If the aggregate type TYPE completes the type of any previous field
    declarations, lay them out now.  */
 
@@ -596,6 +625,9 @@  finish_incomplete_fields (tree type)
 	}
 
       relayout_decl (field);
+
+      /* Relayout of field may change the mode of its RECORD_TYPE.  */
+      finish_aggregate_mode (DECL_FIELD_CONTEXT (field));
     }
 
   /* No more forward references to process.  */
@@ -615,9 +647,6 @@  finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type)
   SET_TYPE_ALIGN (type, alignsize * BITS_PER_UNIT);
   TYPE_PACKED (type) = (alignsize == 1);
 
-  /* Set the back-end type mode.  */
-  compute_record_mode (type);
-
   /* Layout all fields now the type is complete.  */
   for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     {
@@ -662,6 +691,9 @@  finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type)
 	}
     }
 
+  /* Set the back-end type mode after all fields have had their size set.  */
+  finish_aggregate_mode (type);
+
   /* Fix up all forward-referenced variants of this aggregate type.  */
   for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
     {
@@ -673,7 +705,6 @@  finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type)
       TYPE_SIZE (t) = TYPE_SIZE (type);
       TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (type);
       TYPE_PACKED (type) = TYPE_PACKED (type);
-      SET_TYPE_MODE (t, TYPE_MODE (type));
       SET_TYPE_ALIGN (t, TYPE_ALIGN (type));
       TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type);
     }
diff --git a/gcc/testsuite/gdc.dg/torture/pr110406.d b/gcc/testsuite/gdc.dg/torture/pr110406.d
new file mode 100644
index 00000000000..c380e4bdec8
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/torture/pr110406.d
@@ -0,0 +1,25 @@ 
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110406
+// { dg-do compile { target i?86-*-* x86_64-*-* } }
+// { dg-options "-fdump-tree-optimized" }
+struct cpuid_abcd_t
+{
+    uint eax;
+    uint ebx;
+    uint ecx;
+    uint edx;
+};
+
+cpuid_abcd_t cpuid_insn(const uint in_eax)
+{
+    cpuid_abcd_t ret = void;
+    asm { "cpuid"
+        : "=a" (ret.eax),
+          "=b" (ret.ebx),
+          "=c" (ret.ecx),
+          "=d" (ret.edx)
+        : "a"  (in_eax)
+        :;
+    }
+    return ret;
+}
+// { dg-final { scan-tree-dump-not "MEM <vector\\(4\\) uint>" "optimized" } }