On Mon, Nov 23, 2015 at 3:53 PM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Mon, Nov 23, 2015 at 1:57 AM, Richard Biener > <richard.guent...@gmail.com> wrote: >> On Sat, Nov 21, 2015 at 12:46 AM, H.J. Lu <hjl.to...@gmail.com> wrote: >>> On Fri, Nov 20, 2015 at 2:17 PM, Jason Merrill <ja...@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.guent...@gmail.com> wrote: >>>>>> >>>>>> On Tue, Nov 17, 2015 at 12:01 PM, H.J. Lu <hjl.to...@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? >
Hi, Coincidentally a few months ago I was experimenting with making empty-struct function arguments zero-cost (and thus making them behave the same way as in GNU C). My approach (patch attached) was to assign empty-struct arguments to a virtual register (instead of on the stack or to a hard register) during RTL call expansion. These virtual-register assignments would then be trivially DCE'd later. This approach seemed to work surprisingly well with minimal code changes. I wonder what your thoughts are on this approach..
From 8eb52639992ad0f6e5482783604f362bcc04d230 Mon Sep 17 00:00:00 2001 From: Patrick Palka <patr...@parcs.ath.cx> Date: Mon, 23 Nov 2015 21:02:09 -0500 Subject: [PATCH] zero-cost structs --- gcc/calls.c | 15 +++++++++++++++ gcc/tree-tailcall.c | 7 ++++++- gcc/tree.c | 17 +++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/gcc/calls.c b/gcc/calls.c index b56556a..4ca668c 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1394,6 +1394,21 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, args[i].reg = targetm.calls.function_arg (args_so_far, mode, type, argpos < n_named_args); + bool empty_record_or_union_type_p (const_tree); + + if (type != NULL_TREE +#if 0 + /* ??? This condition was necessary to fix a C regression whose + details I have forgot about. In GNU C the mode of an empty struct is BLKmode + (and TYPE_SIZE 0) so this condition makes it so that we don't mess + with the codegen of empty structs in C. In C++ the mode of the empty struct + is QImode and TYPE_SIZE_UNIT 1. Maybe it's not necessary anymore? */ + && mode != BLKmode +#endif + && args[i].reg == NULL_RTX + && empty_record_or_union_type_p (type)) + args[i].reg = gen_reg_rtx (mode); + if (args[i].reg && CONST_INT_P (args[i].reg)) { args[i].special_slot = args[i].reg; diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index bbd1b29..fa8f66a 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -497,6 +497,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret) tail_recursion = true; } + bool empty_record_or_union_type_p (const_tree); + /* Make sure the tail invocation of this function does not refer to local variables. */ FOR_EACH_LOCAL_DECL (cfun, idx, var) @@ -504,7 +506,10 @@ find_tail_calls (basic_block bb, struct tailcall **ret) if (TREE_CODE (var) != PARM_DECL && auto_var_in_fn_p (var, cfun->decl) && (ref_maybe_used_by_stmt_p (call, var) - || call_may_clobber_ref_p (call, var))) + || call_may_clobber_ref_p (call, var)) + /* This change does the same thing as your aliasing change, to allow + tail calling of functions taking by argument empty structs. */ + && !empty_record_or_union_type_p (TREE_TYPE (var))) return; } diff --git a/gcc/tree.c b/gcc/tree.c index 779fe93..f710d15 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -9069,6 +9069,23 @@ auto_var_in_fn_p (const_tree var, const_tree fn) || TREE_CODE (var) == RESULT_DECL)); } +/* Return true if if type TYPE is an empty record or union type. */ + +/* This predicate is inferior to your TYPE_EMPTY_RECORD-flag approach. */ + +bool +empty_record_or_union_type_p (const_tree type) +{ + if (!RECORD_OR_UNION_TYPE_P (type)) + return false; + + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + return false; + + return true; +} + /* Subprogram of following function. Called by walk_tree. Return *TP if it is an automatic variable or parameter of the -- 2.6.3.424.g74c917e.dirty