We've got 'gcc/stor-layout.cc:finalize_type_size':

    /* Handle empty records as per the x86-64 psABI.  */
    TYPE_EMPTY_P (type) = targetm.calls.empty_record_p (type);

(Indeed x86_64 is still the only target to define 'TARGET_EMPTY_RECORD_P',
calling 'gcc/tree.cc-default_is_empty_record'.)

And so it happens that for an empty struct used in code offloaded from x86_64
host (but not powerpc64le host, for example), we get to see 'TYPE_EMPTY_P' in
offloading compilation (where the offload targets (currently?) don't use it
themselves, and therefore aren't prepared to handle it).

For nvptx offloading compilation, this causes wrong code generation:
'ptxas [...] error : Call has wrong number of parameters', as nvptx code
generation for function definition doesn't pay attention to this flag (say, in
'gcc/config/nvptx/nvptx.cc:pass_in_memory', or whereever else would be
appropriate to handle that), but the generic code 'gcc/calls.cc:expand_call'
via 'gcc/function.cc:aggregate_value_p' does pay attention to it, and we thus
get mismatching function definition vs. function call.

This issue apparently isn't a problem for GCN offloading, but I don't know if
that's by design or by accident.

Richard Biener:
> It looks like TYPE_EMPTY_P is only used during RTL expansion for ABI
> purposes, so computing it during layout_type is premature as shown here.
>
> I would suggest to simply re-compute it at offload stream-in time.

(For avoidance of doubt, the additions to 'gcc.target/nvptx/abi-struct-arg.c',
'gcc.target/nvptx/abi-struct-ret.c' are not dependent on the offload streaming
code changes, but are just to mirror the changes to
'libgomp.oacc-c-c++-common/abi-struct-1.c'.)

        PR lto/120308
        gcc/
        * lto-streamer-out.cc (hash_tree): Don't handle 'TYPE_EMPTY_P' for
        'lto_stream_offload_p'.
        * tree-streamer-in.cc (unpack_ts_type_common_value_fields):
        Likewise.
        * tree-streamer-out.cc (pack_ts_type_common_value_fields):
        Likewise.
        libgomp/
        * testsuite/libgomp.oacc-c-c++-common/abi-struct-1.c: Add empty
        structure testing.
        gcc/testsuite/
        * gcc.target/nvptx/abi-struct-arg.c: Add empty structure testing.
        * gcc.target/nvptx/abi-struct-ret.c: Likewise.
---
 gcc/lto-streamer-out.cc                       |  3 ++-
 .../gcc.target/nvptx/abi-struct-arg.c         | 10 ++++++++
 .../gcc.target/nvptx/abi-struct-ret.c         | 11 ++++++++
 gcc/tree-streamer-in.cc                       | 12 ++++++++-
 gcc/tree-streamer-out.cc                      |  3 ++-
 .../libgomp.oacc-c-c++-common/abi-struct-1.c  | 25 +++++++++++++++++++
 6 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc
index 86d338461c0..308ab3416b3 100644
--- a/gcc/lto-streamer-out.cc
+++ b/gcc/lto-streamer-out.cc
@@ -1398,7 +1398,8 @@ hash_tree (struct streamer_tree_cache_d *cache, 
hash_map<tree, hashval_t> *map,
       hstate.commit_flag ();
       hstate.add_int (TYPE_PRECISION_RAW (t));
       hstate.add_int (TYPE_ALIGN (t));
-      hstate.add_int (TYPE_EMPTY_P (t));
+      if (!lto_stream_offload_p)
+       hstate.add_int (TYPE_EMPTY_P (t));
     }
 
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
diff --git a/gcc/testsuite/gcc.target/nvptx/abi-struct-arg.c 
b/gcc/testsuite/gcc.target/nvptx/abi-struct-arg.c
index 54ae651dcca..c2cc4de115e 100644
--- a/gcc/testsuite/gcc.target/nvptx/abi-struct-arg.c
+++ b/gcc/testsuite/gcc.target/nvptx/abi-struct-arg.c
@@ -3,12 +3,16 @@
 
 /* Struct arg.  Passed via pointer.  */
 
+typedef struct {} empty;  /* See 'gcc/doc/extend.texi', "Empty Structures".  */
 typedef struct {char a;} one;
 typedef struct {short a;} two;
 typedef struct {int a;} four;
 typedef struct {long long a;} eight;
 typedef struct {int a, b[12];} big;
 
+/* { dg-final { scan-assembler-times ".extern .func dcl_aempty \\(.param.u64 
%\[_a-z0-9\]*\\);" 1 } } */
+void dcl_aempty (empty);
+
 /* { dg-final { scan-assembler-times ".extern .func dcl_aone \\(.param.u64 
%\[_a-z0-9\]*\\);" 1 } } */
 void dcl_aone (one);
 
@@ -28,6 +32,7 @@ void dcl_abig (big);
 
 void test_1 (void)
 {
+  dcl_aempty (({empty t; t;}));
   dcl_aone (M (one, 1));
   dcl_atwo (M (two, 2));
   dcl_afour (M (four, 3));
@@ -35,6 +40,11 @@ void test_1 (void)
   dcl_abig (M (big, 5));
 }
 
+/* { dg-final { scan-assembler-times ".visible .func dfn_aempty \\(.param.u64 
%\[_a-z0-9\]*\\)(?:;|\[\r\n\]+\{)" 2 } } */
+void dfn_aempty (empty empty)
+{
+}
+
 /* { dg-final { scan-assembler-times ".visible .func dfn_aone \\(.param.u64 
%\[_a-z0-9\]*\\)(?:;|\[\r\n\]+\{)" 2 } } */
 void dfn_aone (one one)
 {
diff --git a/gcc/testsuite/gcc.target/nvptx/abi-struct-ret.c 
b/gcc/testsuite/gcc.target/nvptx/abi-struct-ret.c
index d48a82d26ce..13e50212dc3 100644
--- a/gcc/testsuite/gcc.target/nvptx/abi-struct-ret.c
+++ b/gcc/testsuite/gcc.target/nvptx/abi-struct-ret.c
@@ -3,12 +3,16 @@
 
 /* Struct return.  Returned via pointer.  */
 
+typedef struct {} empty;  /* See 'gcc/doc/extend.texi', "Empty Structures".  */
 typedef struct {char a;} one;
 typedef struct {short a;} two;
 typedef struct {int a;} four;
 typedef struct {long long a;} eight;
 typedef struct {int a, b[12];} big;
 
+/* { dg-final { scan-assembler-times ".extern .func dcl_rempty \\(.param.u64 
%\[_a-z0-9\]*\\);" 1 } } */
+empty dcl_rempty (void);
+
 /* { dg-final { scan-assembler-times ".extern .func dcl_rone \\(.param.u64 
%\[_a-z0-9\]*\\);" 1 } } */
 one dcl_rone (void);
 
@@ -26,6 +30,7 @@ big dcl_rbig (void);
 
 void test_1 (void)
 {
+  dcl_rempty ();
   dcl_rone ();
   dcl_rtwo ();
   dcl_rfour ();
@@ -35,6 +40,12 @@ void test_1 (void)
 
 #define M(T, v) ({T t; t.a = v; t;})
 
+/* { dg-final { scan-assembler-times ".visible .func dfn_rempty \\(.param.u64 
%\[_a-z0-9\]*\\)(?:;|\[\r\n\]+\{)" 2 } } */
+empty dfn_rempty (void)
+{
+  return ({empty t; t;});
+}
+
 /* { dg-final { scan-assembler-times ".visible .func dfn_rone \\(.param.u64 
%\[_a-z0-9\]*\\)(?:;|\[\r\n\]+\{)" 2 } } */
 one dfn_rone (void)
 {
diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc
index 215350f6513..e57e6c6514a 100644
--- a/gcc/tree-streamer-in.cc
+++ b/gcc/tree-streamer-in.cc
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "opts.h"
 #include "stor-layout.h"
+#include "hooks.h" /* For 'hook_bool_const_tree_false'.  */
 
 
 /* Read a STRING_CST from the string table in DATA_IN using input
@@ -386,7 +387,16 @@ unpack_ts_type_common_value_fields (struct bitpack_d *bp, 
tree expr)
     TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
   if (AGGREGATE_TYPE_P (expr))
     TYPE_TYPELESS_STORAGE (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TYPE_EMPTY_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  if (!lto_stream_offload_p)
+    TYPE_EMPTY_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  else
+    {
+      /* All offload targets use the default ('false') 'TARGET_EMPTY_RECORD_P'.
+        If that ever changes, we'll have to properly initialize 'TYPE_EMPTY_P'
+        here, see 'stor-layout.cc:finalize_type_size' and PR120308.  */
+      gcc_assert (targetm.calls.empty_record_p == hook_bool_const_tree_false);
+      TYPE_EMPTY_P (expr) = 0;
+    }
   if (FUNC_OR_METHOD_TYPE_P (expr))
     TYPE_NO_NAMED_ARGS_STDARG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
   if (RECORD_OR_UNION_TYPE_P (expr))
diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc
index 34227259b8a..4d008f735ff 100644
--- a/gcc/tree-streamer-out.cc
+++ b/gcc/tree-streamer-out.cc
@@ -372,7 +372,8 @@ pack_ts_type_common_value_fields (struct bitpack_d *bp, 
tree expr)
     bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
   if (AGGREGATE_TYPE_P (expr))
     bp_pack_value (bp, TYPE_TYPELESS_STORAGE (expr), 1);
-  bp_pack_value (bp, TYPE_EMPTY_P (expr), 1);
+  if (!lto_stream_offload_p)
+    bp_pack_value (bp, TYPE_EMPTY_P (expr), 1);
   if (FUNC_OR_METHOD_TYPE_P (expr))
     bp_pack_value (bp, TYPE_NO_NAMED_ARGS_STDARG_P (expr), 1);
   if (RECORD_OR_UNION_TYPE_P (expr))
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/abi-struct-1.c 
b/libgomp/testsuite/libgomp.oacc-c-c++-common/abi-struct-1.c
index 379e9fd3a97..80786555fe2 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/abi-struct-1.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/abi-struct-1.c
@@ -2,6 +2,7 @@
 
 /* See also '../libgomp.c-c++-common/target-abi-struct-1-O0.c'.  */
 
+typedef struct {} empty;  /* See 'gcc/doc/extend.texi', "Empty Structures".  */
 typedef struct {char a;} schar;
 typedef struct {short a;} sshort;
 typedef struct {int a;} sint;
@@ -12,6 +13,14 @@ typedef struct {int a, b[12];} sint_13;
 
 #define M(T) ({T t; t.a = sizeof t; t;})
 
+static __SIZE_TYPE__ empty_a;
+#pragma acc declare create(empty_a)
+#pragma acc routine
+static empty rempty(void)
+{
+  return ({empty t; empty_a = sizeof t; t;});
+}
+
 #pragma acc routine
 static schar rschar(void)
 {
@@ -42,6 +51,21 @@ static sint_13 rsint_13(void)
   return M(sint_13);
 }
 
+#pragma acc routine
+static void aempty(empty empty)
+{
+  (void) empty;
+
+  __SIZE_TYPE__ empty_a_exp;
+#ifndef __cplusplus
+  empty_a_exp = 0;
+#else
+  empty_a_exp = sizeof (char);
+#endif
+  if (empty_a != empty_a_exp)
+    __builtin_abort();
+}
+
 #pragma acc routine
 static void aschar(schar schar)
 {
@@ -85,6 +109,7 @@ int main()
 #pragma acc serial
   /* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target 
openacc_nvidia_accel_selected xfail *-*-* } .-1 } */
   {
+    aempty(rempty());
     aschar(rschar());
     asshort(rsshort());
     asint(rsint());
-- 
2.34.1

Reply via email to