diff mbox

PING^1: [PATCH] Add TYPE_EMPTY_RECORD for C++ empty class

Message ID CAMe9rOpi29c7gSyf6t7TUDiZ9hQgNssFqD=aY1zMtDY=Sg0UMw@mail.gmail.com
State New
Headers show

Commit Message

H.J. Lu Dec. 9, 2015, 9:14 p.m. UTC
On Wed, Dec 9, 2015 at 10:53 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Dec 9, 2015 at 6:05 AM, Richard Biener
> <richard.guenther@gmail.com> wrote:
>> On Tue, Dec 8, 2015 at 5:22 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Mon, Nov 23, 2015 at 12:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>> On Mon, Nov 23, 2015 at 1:57 AM, Richard Biener
>>>> <richard.guenther@gmail.com> wrote:
>>>>> On Sat, Nov 21, 2015 at 12:46 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>>>> On Fri, Nov 20, 2015 at 2:17 PM, Jason Merrill <jason@redhat.com> wrote:
>>>>>>> On 11/20/2015 01:52 PM, H.J. Lu wrote:
>>>>>>>>
>>>>>>>> On Tue, Nov 17, 2015 at 4:22 AM, Richard Biener
>>>>>>>> <richard.guenther@gmail.com> wrote:
>>>>>>>>>
>>>>>>>>> On Tue, Nov 17, 2015 at 12:01 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>>>>>>>>
>>>>>>>>>> Empty record should be returned and passed the same way in C and C++.
>>>>>>>>>> This patch adds LANG_HOOKS_EMPTY_RECORD_P for C++ empty class, which
>>>>>>>>>> defaults to return false.  For C++, LANG_HOOKS_EMPTY_RECORD_P is defined
>>>>>>>>>> to is_really_empty_class, which returns true for C++ empty classes.  For
>>>>>>>>>> LTO, we stream out a bit to indicate if a record is empty and we store
>>>>>>>>>> it in TYPE_LANG_FLAG_0 when streaming in.  get_ref_base_and_extent is
>>>>>>>>>> changed to set bitsize to 0 for empty records.  Middle-end and x86
>>>>>>>>>> backend are updated to ignore empty records for parameter passing and
>>>>>>>>>> function value return.  Other targets may need similar changes.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Please avoid a new langhook for this and instead claim a bit in
>>>>>>>>> tree_type_common
>>>>>>>>> like for example restrict_flag (double-check it is unused for
>>>>>>>>> non-pointers).
>>>>>>>>
>>>>>>>>
>>>>>>>> There is no bit in tree_type_common I can overload.  restrict_flag is
>>>>>>>> checked for non-pointers to issue an error when it is used on
>>>>>>>> non-pointers:
>>>>>>>>
>>>>>>>>
>>>>>>>> /export/gnu/import/git/sources/gcc/gcc/testsuite/g++.dg/template/qualttp20.C:19:38:
>>>>>>>> error: ‘__restrict__’ qualifiers cannot be applied to ‘AS::L’
>>>>>>>>     typedef typename T::L __restrict__ r;// { dg-error "'__restrict__'
>>>>>>>> qualifiers cannot" "" }
>>>>>>>
>>>>>>>
>>>>>>> The C++ front end only needs to check TYPE_RESTRICT for this purpose on
>>>>>>> front-end-specific type codes like TEMPLATE_TYPE_PARM; cp_type_quals could
>>>>>>> handle that specifically if you change TYPE_RESTRICT to only apply to
>>>>>>> pointers.
>>>>>>>
>>>>>>
>>>>>> restrict_flag is also checked in this case:
>>>>>>
>>>>>> [hjl@gnu-6 gcc]$ cat x.i
>>>>>> struct dummy { };
>>>>>>
>>>>>> struct dummy
>>>>>> foo (struct dummy __restrict__ i)
>>>>>> {
>>>>>>   return i;
>>>>>> }
>>>>>> [hjl@gnu-6 gcc]$ gcc -S x.i -Wall
>>>>>> x.i:4:13: error: invalid use of ‘restrict’
>>>>>>  foo (struct dummy __restrict__ i)
>>>>>>              ^
>>>>>> x.i:4:13: error: invalid use of ‘restrict’
>>>>>> [hjl@gnu-6 gcc]$
>>>>>>
>>>>>> restrict_flag can't also be used to indicate `i' is an empty record.
>>>>>
>>>>> I'm sure this error can be done during parsing w/o relying on TYPE_RESTRICT.
>>>>>
>>>>> But well, use any other free bit (but do not enlarge
>>>>> tree_type_common).  Eventually
>>>>> you can free up a bit by putting sth into type_lang_specific currently
>>>>> using bits
>>>>> in tree_type_common.
>>>>
>>>> There are no bits in tree_type_common I can move.  Instead,
>>>> this patch overloads side_effects_flag in tree_base.  Tested on
>>>> Linux/x86-64.  OK for trunk?
>>
>> I'm fine with using side_effects_flag for this.
>>
>> I miss an explanation of where this detail of the ABI is documented and wonder
>> if the term "empty record" is also used in that document and how it is
>> documented.
>>
>> Thus
>>
>> +/* Nonzero in a type considered an empty record.  */
>> +#define TYPE_EMPTY_RECORD(NODE) \
>> +  (TYPE_CHECK (NODE)->base.side_effects_flag)
>>
>> should refer to the ABI where is defined what an "empty record" is and how
>> it is handled by the backend(s).
>
> Empty C++ class is a corner case which isn't covered in psABI nor C++ ABI.
> There is no mention of "empty record" in GCC documentation.  But there are
> plenty of "empty class" in gcc/cp.  This change affects all targets.  C++ ABI
> should specify how it should be passed.
>
>> +/* Return true if type T is an empty record.  */
>> +
>> +static inline bool
>> +type_is_empty_record_p (const_tree t)
>> +{
>> +  return TYPE_EMPTY_RECORD (TYPE_MAIN_VARIANT (t));
>>
>> the type checker should probably check the bit is consistent across
>> variants so it can be tested on any of them.
>
> TYPE_EMPTY_RECORD is only relevant for parameter passing.  For
>
> struct foo;
> typedef foo bar;
>
> TYPE_EMPTY_RECORD has no impact.  Since call only uses
> the main variant type, checking TYPE_MAIN_VARIANT is sufficient.
>
>> You fail to adjust other targets gimplification hooks which suggests
>> this is a detail of the x86 psABI and not the C++ ABI?  If so I miss
>> a -Wpsabi warning for this change.
>
> My change is generic.  The only x86 specific change is
>
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index d30fbff..308d9a4e 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -10292,7 +10292,8 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq
>  *pre_p,
>    indirect_p = pass_by_reference (NULL, TYPE_MODE (type), type, false);
>    if (indirect_p)
>      type = build_pointer_type (type);
> -  size = int_size_in_bytes (type);
> +  bool empty_record = type && type_is_empty_record_p (type);
> +  size = empty_record ? 0 : int_size_in_bytes (type);
>    rsize = CEIL (size, UNITS_PER_WORD);
>
>    nat_mode = type_natural_mode (type, NULL, false);
>
> which is for 64-bit variadic functions.  I added a testcase,
> g++.dg/pr60336-2.C, for it.  There are also other variadic tests
> in g++.dg/compat.  If a target doesn't use std_gimplify_va_arg_expr,
> it needs similar change.  I see that TARGET_GIMPLIFY_VA_ARG_EXPR
> is also defined in
>
> aarch64/aarch64.c
> alpha/alpha.c
> arm/arm.c
> epiphany/epiphany.c
> ia64/ia64.c
> mep/mep.c
> mips/mips.c
> msp430/msp430.c
> pa/pa.c
> rs6000/rs6000.c
> s390/s390.c
> sh/sh.c
> sparc/sparc.c
> spu/spu.c
> stormy16/stormy16.c
> tilegx/tilegx.c
> tilepro/tilepro.c
> visium/visium.c
> xtensa/xtensa.c
>
> I will prepare a separate patch for those targets to try.
>

Here is a patch for other backends to properly pass C++ empty class.
One can check out hjl/pr60336/master branch from

https://github.com/hjl-tools/gcc

to get both generic and target-dependent patches.
diff mbox

Patch

From 7332cc2ab12c46639fa029ba2af023c654db7a93 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 9 Dec 2015 12:48:07 -0800
Subject: [PATCH] Properly pass C++ empty class

Use 0 for empty record size in TARGET_GIMPLIFY_VA_ARG_EXPR.

	PR c++/60336
	PR middle-end/67239
	PR target/68355
	* config/aarch64/aarch64.c (aarch64_gimplify_va_arg_expr): Use 0
	for empty record size.
	* config/mep/mep.c (mep_gimplify_va_arg_expr): Likewise.
	* config/mips/mips.c (mips_std_gimplify_va_arg_expr): Likewise.
	(mips_gimplify_va_arg_expr): Likewise.
	* config/msp430/msp430.c (msp430_gimplify_va_arg_expr): Likewise.
	* config/pa/pa.c (hppa_gimplify_va_arg_expr): Likewise.
	* config/rs6000/rs6000.c (rs6000_gimplify_va_arg): Likewise.
	* config/s390/s390.c (s390_gimplify_va_arg): Likewise.
	* config/sh/sh.c (sh_gimplify_va_arg_expr): Likewise.
	* config/sparc/sparc.c (sparc_gimplify_va_arg): Likewise.
	* config/spu/spu.c (spu_gimplify_va_arg_expr): Likewise.
	* config/stormy16/stormy16.c (xstormy16_gimplify_va_arg_expr):
	Likewise.
	* config/visium/visium.c (visium_gimplify_va_arg): Likewise.
	* config/xtensa/xtensa.c (xtensa_gimplify_va_arg_expr): Likewise.
	* config/alpha/alpha.c (alpha_setup_incoming_varargs): Replace
	targetm.calls.function_arg_advance with function_arg_advance.
	(alpha_gimplify_va_arg_1): Use 0 for empty record size.
	* config/microblaze/microblaze.c (microblaze_expand_prologue):
	Replace targetm.calls.function_arg with function_arg.  Replace
	targetm.calls.function_arg_advance with function_arg_advance.
	* config/tilegx/tilegx.c (tilegx_setup_incoming_varargs): Replace
	targetm.calls.function_arg_advance with function_arg_advance.
	(tilegx_gimplify_va_arg_expr): Use 0 for empty record size.
	* config/tilepro/tilepro.c (tilepro_setup_incoming_varargs):
	Replace targetm.calls.function_arg_advance with
	function_arg_advance.
	(tilepro_gimplify_va_arg_expr): Use 0 for empty record size.
---
 gcc/config/aarch64/aarch64.c       |  3 ++-
 gcc/config/alpha/alpha.c           |  6 +++---
 gcc/config/mep/mep.c               |  3 ++-
 gcc/config/microblaze/microblaze.c | 11 +++++------
 gcc/config/mips/mips.c             |  6 ++++--
 gcc/config/msp430/msp430.c         |  3 ++-
 gcc/config/pa/pa.c                 |  3 ++-
 gcc/config/rs6000/rs6000.c         |  3 ++-
 gcc/config/s390/s390.c             |  3 ++-
 gcc/config/sh/sh.c                 |  3 ++-
 gcc/config/sparc/sparc.c           |  3 ++-
 gcc/config/spu/spu.c               |  3 ++-
 gcc/config/stormy16/stormy16.c     |  6 ++++--
 gcc/config/tilegx/tilegx.c         |  7 ++++---
 gcc/config/tilepro/tilepro.c       |  7 ++++---
 gcc/config/visium/visium.c         |  3 ++-
 gcc/config/xtensa/xtensa.c         |  3 ++-
 17 files changed, 46 insertions(+), 30 deletions(-)

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 1e1b864..cfb9f66 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -9618,7 +9618,8 @@  aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
 
   stack = build3 (COMPONENT_REF, TREE_TYPE (f_stack), unshare_expr (valist),
 		  f_stack, NULL_TREE);
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
   align = aarch64_function_arg_alignment (mode, type) / BITS_PER_UNIT;
 
   dw_align = false;
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 4cfae82..d5d2f66 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -6117,8 +6117,7 @@  alpha_setup_incoming_varargs (cumulative_args_t pcum, machine_mode mode,
   CUMULATIVE_ARGS cum = *get_cumulative_args (pcum);
 
   /* Skip the current argument.  */
-  targetm.calls.function_arg_advance (pack_cumulative_args (&cum), mode, type,
-				      true);
+  function_arg_advance (pack_cumulative_args (&cum), mode, type, true);
 
 #if TARGET_ABI_OPEN_VMS
   /* For VMS, we allocate space for all 6 arg registers plus a count.
@@ -6304,7 +6303,8 @@  alpha_gimplify_va_arg_1 (tree type, tree base, tree offset,
   gimple_seq_add_seq (pre_p, internal_post);
 
   /* Update the offset field.  */
-  type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
+  bool empty_record = type && type_is_empty_record_p (type);
+  type_size = empty_record ? 0 : TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
   if (type_size == NULL || TREE_OVERFLOW (type_size))
     t = size_zero_node;
   else
diff --git a/gcc/config/mep/mep.c b/gcc/config/mep/mep.c
index 5ab56bd..65aec24 100644
--- a/gcc/config/mep/mep.c
+++ b/gcc/config/mep/mep.c
@@ -3525,7 +3525,8 @@  mep_gimplify_va_arg_expr (tree valist, tree type,
 
   ivc2_vec = TARGET_IVC2 && VECTOR_TYPE_P (type);
 
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
   by_reference = (size > (ivc2_vec ? 8 : 4)) || (size <= 0);
 
   if (by_reference)
diff --git a/gcc/config/microblaze/microblaze.c b/gcc/config/microblaze/microblaze.c
index aebbc3b..7a7c397 100644
--- a/gcc/config/microblaze/microblaze.c
+++ b/gcc/config/microblaze/microblaze.c
@@ -2795,8 +2795,8 @@  microblaze_expand_prologue (void)
 	  passed_mode = Pmode;
 	}
 
-      entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
-					       passed_type, true);
+      entry_parm = function_arg (args_so_far, passed_mode, passed_type,
+				 true);
 
       if (entry_parm)
 	{
@@ -2816,8 +2816,7 @@  microblaze_expand_prologue (void)
 	  break;
 	}
 
-      targetm.calls.function_arg_advance (args_so_far, passed_mode,
-					  passed_type, true);
+      function_arg_advance (args_so_far, passed_mode, passed_type, true);
 
       next_arg = TREE_CHAIN (cur_arg);
       if (next_arg == 0)
@@ -2831,8 +2830,8 @@  microblaze_expand_prologue (void)
 
   /* Split parallel insn into a sequence of insns.  */
 
-  next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
-					     void_type_node, true);
+  next_arg_reg = function_arg (args_so_far, VOIDmode, void_type_node,
+			       true);
   if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
     {
       rtvec adjust = XVEC (next_arg_reg, 0);
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 6145944..61c6d0c 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -6308,7 +6308,8 @@  mips_std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
     }
 
   /* Compute the rounded size of the type.  */
-  type_size = size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  type_size = empty_record ? 0 : size_in_bytes (type);
   rounded_size = round_up (type_size, align);
 
   /* Reduce rounded_size so it's sharable with the postqueue.  */
@@ -6397,7 +6398,8 @@  mips_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
 
       ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
 		     NULL_TREE);
-      size = int_size_in_bytes (type);
+      bool empty_record = type && type_is_empty_record_p (type);
+      size = empty_record ? 0 : int_size_in_bytes (type);
 
       if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
 	  && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c
index 88301c8..1726f5b 100644
--- a/gcc/config/msp430/msp430.c
+++ b/gcc/config/msp430/msp430.c
@@ -1451,7 +1451,8 @@  msp430_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
     }
 
   /* Compute the rounded size of the type.  */
-  type_size = size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  type_size = empty_record ? 0 : size_in_bytes (type);
   rounded_size = round_up (type_size, align);
 
   /* Reduce rounded_size so it's sharable with the postqueue.  */
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index b8caab5..ef956cf 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -6305,7 +6305,8 @@  hppa_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
 	  type = ptr;
 	  ptr = build_pointer_type (type);
 	}
-      size = int_size_in_bytes (type);
+      bool empty_record = type && type_is_empty_record_p (type);
+      size = empty_record ? 0 : int_size_in_bytes (type);
       valist_type = TREE_TYPE (valist);
 
       /* Args grow down.  Not handled by generic routines.  */
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 6b22f93..ef829ed 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -11983,7 +11983,8 @@  rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), unshare_expr (valist),
 		f_sav, NULL_TREE);
 
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
   rsize = (size + 3) / 4;
   align = 1;
 
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index f8928b9..6f6639f 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -11569,7 +11569,8 @@  s390_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   valist = unshare_expr (valist);
   ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
 
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
 
   s390_check_type_for_vector_abi (type, true, false);
 
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 919ea1c..f1f66f9 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -8765,7 +8765,8 @@  sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
   if (pass_by_ref)
     type = build_pointer_type (type);
 
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
   rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
   pptr_type_node = build_pointer_type (ptr_type_node);
 
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 55ddacf..559bc69 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -7425,7 +7425,8 @@  sparc_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   else
     {
       indirect = false;
-      size = int_size_in_bytes (type);
+      bool empty_record = type && type_is_empty_record_p (type);
+      size = empty_record ? 0 : int_size_in_bytes (type);
       rsize = ROUND_UP (size, UNITS_PER_WORD);
       align = 0;
 
diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
index 31502fb..1b24b12 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -4028,7 +4028,8 @@  spu_gimplify_va_arg_expr (tree valist, tree type, gimple_seq * pre_p,
 					   false);
   if (pass_by_reference_p)
     type = build_pointer_type (type);
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
   rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
 
   /* build conditional expression to calculate addr. The expression
diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c
index f626853..bff3e27 100644
--- a/gcc/config/stormy16/stormy16.c
+++ b/gcc/config/stormy16/stormy16.c
@@ -1337,8 +1337,10 @@  xstormy16_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
   count = build3 (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count,
 		  NULL_TREE);
 
+  bool empty_record = type && type_is_empty_record_p (type);
   must_stack = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type);
-  size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
+  size_tree = round_up (empty_record ? integer_zero_node : size_in_bytes (type),
+			UNITS_PER_WORD);
   gimplify_expr (&size_tree, pre_p, NULL, is_gimple_val, fb_rvalue);
 
   size_of_reg_args = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
@@ -1374,7 +1376,7 @@  xstormy16_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
   /* Arguments larger than a word might need to skip over some
      registers, since arguments are either passed entirely in
      registers or entirely on the stack.  */
-  size = PUSH_ROUNDING (int_size_in_bytes (type));
+  size = PUSH_ROUNDING (empty_record ? 0 : int_size_in_bytes (type));
   if (size > 2 || size < 0 || must_stack)
     {
       tree r, u;
diff --git a/gcc/config/tilegx/tilegx.c b/gcc/config/tilegx/tilegx.c
index d221062..cdacd36 100644
--- a/gcc/config/tilegx/tilegx.c
+++ b/gcc/config/tilegx/tilegx.c
@@ -396,8 +396,8 @@  tilegx_setup_incoming_varargs (cumulative_args_t cum,
   /* The caller has advanced CUM up to, but not beyond, the last named
      argument.  Advance a local copy of CUM past the last "real" named
      argument, to find out how many registers are left over.  */
-  targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum),
-				      mode, type, true);
+  function_arg_advance (pack_cumulative_args (&local_cum), mode, type,
+			true);
   first_reg = local_cum;
 
   if (local_cum < TILEGX_NUM_ARG_REGS)
@@ -473,7 +473,8 @@  tilegx_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
   if (pass_by_reference_p)
     type = build_pointer_type (type);
 
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
   rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
 
   /* If the alignment of the type is greater than the default for a
diff --git a/gcc/config/tilepro/tilepro.c b/gcc/config/tilepro/tilepro.c
index 248b24e..1549c32 100644
--- a/gcc/config/tilepro/tilepro.c
+++ b/gcc/config/tilepro/tilepro.c
@@ -348,8 +348,8 @@  tilepro_setup_incoming_varargs (cumulative_args_t cum,
   /* The caller has advanced CUM up to, but not beyond, the last named
      argument.  Advance a local copy of CUM past the last "real" named
      argument, to find out how many registers are left over.  */
-  targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum),
-				      mode, type, true);
+  function_arg_advance (pack_cumulative_args (&local_cum), mode, type,
+			true);
   first_reg = local_cum;
 
   if (local_cum < TILEPRO_NUM_ARG_REGS)
@@ -421,7 +421,8 @@  tilepro_gimplify_va_arg_expr (tree valist, tree type, gimple_seq * pre_p,
   if (pass_by_reference_p)
     type = build_pointer_type (type);
 
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
   rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
 
   /* If the alignment of the type is greater than the default for a
diff --git a/gcc/config/visium/visium.c b/gcc/config/visium/visium.c
index 0bf275c..4f252d0 100644
--- a/gcc/config/visium/visium.c
+++ b/gcc/config/visium/visium.c
@@ -1529,7 +1529,8 @@  visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
       return build_va_arg_indirect_ref (t);
     }
 
-  size = int_size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  size = empty_record ? 0 : int_size_in_bytes (type);
   rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
   f_ovfl = TYPE_FIELDS (va_list_type_node);
   f_gbase = TREE_CHAIN (f_ovfl);
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index 0f58655..43911a1 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -3161,7 +3161,8 @@  xtensa_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
   ndx = build3 (COMPONENT_REF, TREE_TYPE (f_ndx), unshare_expr (valist),
 		f_ndx, NULL_TREE);
 
-  type_size = size_in_bytes (type);
+  bool empty_record = type && type_is_empty_record_p (type);
+  type_size = empty_record ? 0 : size_in_bytes (type);
   va_size = round_up (type_size, UNITS_PER_WORD);
   gimplify_expr (&va_size, pre_p, NULL, is_gimple_val, fb_rvalue);
 
-- 
2.5.0