* [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
@ 2015-11-17 11:01 H.J. Lu
2015-11-17 12:22 ` Richard Biener
0 siblings, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2015-11-17 11:01 UTC (permalink / raw)
To: gcc-patches
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.
gcc/
PR c++/60336
PR middle-end/67239
PR target/68355
* calls.c (store_one_arg): Use 0 for empty record size. Don't
push 0 size argument onto stack.
(must_pass_in_stack_var_size_or_pad): Return false for empty
record.
* function.c (locate_and_pad_parm): Use 0 for empty record size.
* tree-dfa.c (get_ref_base_and_extent): Likewise.
* langhooks-def.h (LANG_HOOKS_EMPTY_RECORD_P): New.
(LANG_HOOKS_DECLS): Add LANG_HOOKS_EMPTY_RECORD_P.
* langhooks.h (lang_hooks_for_decls): Add empty_record_p.
* lto-streamer.h (LTO_major_version): Increase by 1 to 6.
* targhooks.c: Include "langhooks.h".
(std_gimplify_va_arg_expr): Use 0 for empty record size.
* tree-streamer-in.c (unpack_ts_base_value_fields): Stream in
TYPE_LANG_FLAG_0.
* tree-streamer-out.c: Include "langhooks.h".
(pack_ts_base_value_fields): Stream out a bit to indicate if a
record is empty.
* config/i386/i386.c (classify_argument): Return 0 for empty
record.
(construct_container): Return NULL for empty record.
(ix86_function_arg): Likewise.
(ix86_function_arg_advance): Skip empty record.
(ix86_return_in_memory): Return false for empty record.
(ix86_gimplify_va_arg): Use 0 for empty record size.
gcc/cp/
PR c++/60336
PR middle-end/67239
PR target/68355
* class.c (is_empty_class): Changed to return bool and take
const_tree.
(is_really_empty_class): Changed to take const_tree. Check
if TYPE_BINFO is zero.
* cp-tree.h (is_empty_class): Updated.
(is_really_empty_class): Likewise.
* cp-lang.c (LANG_HOOKS_EMPTY_RECORD_P): New.
gcc/lto/
PR c++/60336
PR middle-end/67239
PR target/68355
* lto-lang.c (lto_empty_record_p): New.
(LANG_HOOKS_EMPTY_RECORD_P): Likewise.
gcc/testsuite/
PR c++/60336
PR middle-end/67239
PR target/68355
* g++.dg/abi/empty12.C: New test.
* g++.dg/abi/empty12.h: Likewise.
* g++.dg/abi/empty12a.c: Likewise.
* g++.dg/pr60336-1.C: Likewise.
* g++.dg/pr60336-2.C: Likewise.
* g++.dg/pr68355.C: Likewise.
---
gcc/calls.c | 41 +++++++++++++++++++++++++++----------
gcc/config/i386/i386.c | 18 +++++++++++++++-
gcc/cp/class.c | 17 ++++++++-------
gcc/cp/cp-lang.c | 2 ++
gcc/cp/cp-tree.h | 4 ++--
gcc/function.c | 7 +++++--
gcc/langhooks-def.h | 2 ++
gcc/langhooks.h | 3 +++
gcc/lto-streamer.h | 2 +-
gcc/lto/lto-lang.c | 13 ++++++++++++
gcc/targhooks.c | 6 +++++-
gcc/testsuite/g++.dg/abi/empty12.C | 17 +++++++++++++++
gcc/testsuite/g++.dg/abi/empty12.h | 9 ++++++++
gcc/testsuite/g++.dg/abi/empty12a.c | 6 ++++++
gcc/testsuite/g++.dg/pr60336-1.C | 17 +++++++++++++++
gcc/testsuite/g++.dg/pr60336-2.C | 28 +++++++++++++++++++++++++
gcc/testsuite/g++.dg/pr68355.C | 24 ++++++++++++++++++++++
gcc/tree-dfa.c | 2 ++
gcc/tree-streamer-in.c | 5 +++++
gcc/tree-streamer-out.c | 6 ++++++
20 files changed, 204 insertions(+), 25 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/abi/empty12.C
create mode 100644 gcc/testsuite/g++.dg/abi/empty12.h
create mode 100644 gcc/testsuite/g++.dg/abi/empty12a.c
create mode 100644 gcc/testsuite/g++.dg/pr60336-1.C
create mode 100644 gcc/testsuite/g++.dg/pr60336-2.C
create mode 100644 gcc/testsuite/g++.dg/pr68355.C
diff --git a/gcc/calls.c b/gcc/calls.c
index b56556a..ecc9b7a 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -4835,7 +4835,10 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
Note that in C the default argument promotions
will prevent such mismatches. */
- size = GET_MODE_SIZE (arg->mode);
+ if (lang_hooks.decls.empty_record_p (TREE_TYPE (pval)))
+ size = 0;
+ else
+ size = GET_MODE_SIZE (arg->mode);
/* Compute how much space the push instruction will push.
On many machines, pushing a byte will advance the stack
pointer by a halfword. */
@@ -4865,10 +4868,14 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
/* This isn't already where we want it on the stack, so put it there.
This can either be done with push or copy insns. */
- if (!emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
- parm_align, partial, reg, used - size, argblock,
- ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
- ARGS_SIZE_RTX (arg->locate.alignment_pad), true))
+ if (used
+ && !emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval),
+ NULL_RTX, parm_align, partial, reg,
+ used - size, argblock,
+ ARGS_SIZE_RTX (arg->locate.offset),
+ reg_parm_stack_space,
+ ARGS_SIZE_RTX (arg->locate.alignment_pad),
+ true))
sibcall_failure = 1;
/* Unless this is a partially-in-register argument, the argument is now
@@ -4900,10 +4907,16 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
{
/* PUSH_ROUNDING has no effect on us, because emit_push_insn
for BLKmode is careful to avoid it. */
+ bool empty_record
+ = lang_hooks.decls.empty_record_p (TREE_TYPE (pval));
excess = (arg->locate.size.constant
- - int_size_in_bytes (TREE_TYPE (pval))
+ - (empty_record
+ ? 0
+ : int_size_in_bytes (TREE_TYPE (pval)))
+ partial);
- size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
+ size_rtx = expand_expr ((empty_record
+ ? size_zero_node
+ : size_in_bytes (TREE_TYPE (pval))),
NULL_RTX, TYPE_MODE (sizetype),
EXPAND_NORMAL);
}
@@ -4971,10 +4984,13 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
}
}
- emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
- parm_align, partial, reg, excess, argblock,
- ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
- ARGS_SIZE_RTX (arg->locate.alignment_pad), false);
+ if (!CONST_INT_P (size_rtx) || INTVAL (size_rtx) != 0)
+ emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval),
+ size_rtx, parm_align, partial, reg, excess,
+ argblock, ARGS_SIZE_RTX (arg->locate.offset),
+ reg_parm_stack_space,
+ ARGS_SIZE_RTX (arg->locate.alignment_pad),
+ false);
/* Unless this is a partially-in-register argument, the argument is now
in the stack.
@@ -5052,6 +5068,9 @@ must_pass_in_stack_var_size_or_pad (machine_mode mode, const_tree type)
if (TREE_ADDRESSABLE (type))
return true;
+ if (lang_hooks.decls.empty_record_p (type))
+ return false;
+
/* If the padding and mode of the type is such that a copy into
a register would put it into the wrong part of the register. */
if (mode == BLKmode
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 6173dae..8bd6198 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -7920,6 +7920,9 @@ static int
classify_argument (machine_mode mode, const_tree type,
enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset)
{
+ if (type && lang_hooks.decls.empty_record_p (type))
+ return 0;
+
HOST_WIDE_INT bytes =
(mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
int words = CEIL (bytes + (bit_offset % 64) / 8, UNITS_PER_WORD);
@@ -8371,6 +8374,9 @@ construct_container (machine_mode mode, machine_mode orig_mode,
static bool issued_sse_ret_error;
static bool issued_x87_ret_error;
+ if (type && lang_hooks.decls.empty_record_p (type))
+ return NULL;
+
machine_mode tmpmode;
int bytes =
(mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
@@ -8783,6 +8789,9 @@ ix86_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
HOST_WIDE_INT bytes, words;
int nregs;
+ if (type && lang_hooks.decls.empty_record_p (type))
+ return;
+
if (mode == BLKmode)
bytes = int_size_in_bytes (type);
else
@@ -9099,6 +9108,9 @@ ix86_function_arg (cumulative_args_t cum_v, machine_mode omode,
HOST_WIDE_INT bytes, words;
rtx arg;
+ if (type && lang_hooks.decls.empty_record_p (type))
+ return NULL;
+
/* All pointer bounds arguments are handled separately here. */
if ((type && POINTER_BOUNDS_TYPE_P (type))
|| POINTER_BOUNDS_MODE_P (mode))
@@ -9708,6 +9720,9 @@ ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
if (POINTER_BOUNDS_TYPE_P (type))
return false;
+ if (type && lang_hooks.decls.empty_record_p (type))
+ return false;
+
if (TARGET_64BIT)
{
if (ix86_function_type_abi (fntype) == MS_ABI)
@@ -10266,7 +10281,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 && lang_hooks.decls.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);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 216a301..c380734 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -8068,8 +8068,8 @@ build_self_reference (void)
/* Returns 1 if TYPE contains only padding bytes. */
-int
-is_empty_class (tree type)
+bool
+is_empty_class (const_tree type)
{
if (type == error_mark_node)
return 0;
@@ -8084,7 +8084,7 @@ is_empty_class (tree type)
possible combinations of empty classes and possibly a vptr. */
bool
-is_really_empty_class (tree type)
+is_really_empty_class (const_tree type)
{
if (CLASS_TYPE_P (type))
{
@@ -8098,10 +8098,13 @@ is_really_empty_class (tree type)
if (COMPLETE_TYPE_P (type) && is_empty_class (type))
return true;
- for (binfo = TYPE_BINFO (type), i = 0;
- BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
- if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
- return false;
+ /* TYPE_BINFO may be zeron when is_really_empty_class is called
+ from LANG_HOOKS_EMPTY_RECORD_P. */
+ binfo = TYPE_BINFO (type);
+ if (binfo)
+ for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
+ if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
+ return false;
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL
&& !DECL_ARTIFICIAL (field)
diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
index 048108d..80174cb 100644
--- a/gcc/cp/cp-lang.c
+++ b/gcc/cp/cp-lang.c
@@ -78,6 +78,8 @@ static tree cxx_enum_underlying_base_type (const_tree);
#define LANG_HOOKS_EH_RUNTIME_TYPE build_eh_type_type
#undef LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE
#define LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE cxx_enum_underlying_base_type
+#undef LANG_HOOKS_EMPTY_RECORD_P
+#define LANG_HOOKS_EMPTY_RECORD_P is_really_empty_class
/* Each front end provides its own lang hook initializer. */
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 84437b4..dc79979 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5578,8 +5578,8 @@ extern tree finish_struct (tree, tree);
extern void finish_struct_1 (tree);
extern int resolves_to_fixed_type_p (tree, int *);
extern void init_class_processing (void);
-extern int is_empty_class (tree);
-extern bool is_really_empty_class (tree);
+extern bool is_empty_class (const_tree);
+extern bool is_really_empty_class (const_tree);
extern void pushclass (tree);
extern void popclass (void);
extern void push_nested_class (tree);
diff --git a/gcc/function.c b/gcc/function.c
index afc2c87..b59157d 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4093,8 +4093,11 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs,
part_size_in_regs = (reg_parm_stack_space == 0 ? partial : 0);
- sizetree
- = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
+ if (type)
+ sizetree = (lang_hooks.decls.empty_record_p (type)
+ ? size_zero_node : size_in_bytes (type));
+ else
+ sizetree = size_int (GET_MODE_SIZE (passed_mode));
where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
boundary = targetm.calls.function_arg_boundary (passed_mode, type);
round_boundary = targetm.calls.function_arg_round_boundary (passed_mode,
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 18ac84d..df4cbf8 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -163,6 +163,7 @@ extern tree lhd_make_node (enum tree_code);
#define LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P hook_bool_const_tree_false
#define LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P \
hook_bool_tree_tree_false
+#define LANG_HOOKS_EMPTY_RECORD_P hook_bool_const_tree_false
#define LANG_HOOKS_GET_GENERIC_FUNCTION_DECL hook_tree_const_tree_null
#define LANG_HOOKS_TYPE_PROMOTES_TO lhd_type_promotes_to
#define LANG_HOOKS_REGISTER_BUILTIN_TYPE lhd_register_builtin_type
@@ -228,6 +229,7 @@ extern tree lhd_make_node (enum tree_code);
LANG_HOOKS_FUNCTION_DECL_DELETED_P, \
LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P, \
LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P, \
+ LANG_HOOKS_EMPTY_RECORD_P, \
LANG_HOOKS_GET_GENERIC_FUNCTION_DECL, \
LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \
LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS, \
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index d8d01fa..450bdee 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -177,6 +177,9 @@ struct lang_hooks_for_decls
function parameter pack. */
bool (*function_parm_expanded_from_pack_p) (tree, tree);
+ /* Determine if a type is an empty record. */
+ bool (*empty_record_p) (const_tree type);
+
/* Returns the generic declaration of a generic function instantiations. */
tree (*get_generic_function_decl) (const_tree);
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 5aae9e9..cc4cede 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -128,7 +128,7 @@ along with GCC; see the file COPYING3. If not see
String are represented in the table as pairs, a length in ULEB128
form followed by the data for the string. */
-#define LTO_major_version 5
+#define LTO_major_version 6
#define LTO_minor_version 0
typedef unsigned char lto_decl_flags_t;
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 53dd8f6..dc849a4 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -1306,6 +1306,16 @@ static void lto_init_ts (void)
tree_contains_struct[NAMESPACE_DECL][TS_DECL_MINIMAL] = 1;
}
+/* Return true if TYPE contains no actual data, just various possible
+ combinations of empty records. */
+
+static bool
+lto_empty_record_p (const_tree type)
+{
+ /* Set if a record is empty. */
+ return TYPE_LANG_FLAG_0 (type);
+}
+
#undef LANG_HOOKS_NAME
#define LANG_HOOKS_NAME "GNU GIMPLE"
#undef LANG_HOOKS_OPTION_LANG_MASK
@@ -1363,6 +1373,9 @@ static void lto_init_ts (void)
#undef LANG_HOOKS_INIT_TS
#define LANG_HOOKS_INIT_TS lto_init_ts
+#undef LANG_HOOKS_EMPTY_RECORD_P
+#define LANG_HOOKS_EMPTY_RECORD_P lto_empty_record_p
+
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
/* Language hooks that are not part of lang_hooks. */
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index c34b4e9..5e74dd9 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "opts.h"
#include "gimplify.h"
+#include "langhooks.h"
bool
@@ -1823,9 +1824,12 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
/* Hoist the valist value into a temporary for the moment. */
valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
+ bool empty_record = lang_hooks.decls.empty_record_p (type);
+
/* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
requires greater alignment, we must perform dynamic alignment. */
if (boundary > align
+ && !empty_record
&& !integer_zerop (TYPE_SIZE (type)))
{
t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
@@ -1852,7 +1856,7 @@ 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);
+ type_size = empty_record ? size_zero_node : 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/testsuite/g++.dg/abi/empty12.C b/gcc/testsuite/g++.dg/abi/empty12.C
new file mode 100644
index 0000000..430d57d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty12.C
@@ -0,0 +1,17 @@
+// PR c++/60336
+// { dg-do run }
+// { dg-options "-x c" }
+// { dg-additional-sources "empty12a.c" }
+// { dg-prune-output "command line option" }
+
+#include "empty12.h"
+extern "C" void fun(struct dummy, struct foo);
+
+int main()
+{
+ struct dummy d;
+ struct foo f = { -1, -2, -3, -4, -5 };
+
+ fun(d, f);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty12.h b/gcc/testsuite/g++.dg/abi/empty12.h
new file mode 100644
index 0000000..c61afcd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty12.h
@@ -0,0 +1,9 @@
+struct dummy { };
+struct foo
+{
+ int i1;
+ int i2;
+ int i3;
+ int i4;
+ int i5;
+};
diff --git a/gcc/testsuite/g++.dg/abi/empty12a.c b/gcc/testsuite/g++.dg/abi/empty12a.c
new file mode 100644
index 0000000..34a25ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty12a.c
@@ -0,0 +1,6 @@
+#include "empty12.h"
+void fun(struct dummy d, struct foo f)
+{
+ if (f.i1 != -1)
+ __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/pr60336-1.C b/gcc/testsuite/g++.dg/pr60336-1.C
new file mode 100644
index 0000000..af08638
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr60336-1.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O2 -std=c++11 -fno-pic" }
+// { dg-require-effective-target fpic }
+
+struct dummy { };
+struct true_type { struct dummy i; };
+
+extern true_type y;
+extern void xxx (true_type c);
+
+void
+yyy (void)
+{
+ xxx (y);
+}
+
+// { dg-final { scan-assembler "jmp\[\t \]+\[^\$\]*?_Z3xxx9true_type" { target i?86-*-* x86_64-*-* } } }
diff --git a/gcc/testsuite/g++.dg/pr60336-2.C b/gcc/testsuite/g++.dg/pr60336-2.C
new file mode 100644
index 0000000..7b902e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr60336-2.C
@@ -0,0 +1,28 @@
+// { dg-do run }
+// { dg-options "-O2" }
+
+#include <stdarg.h>
+
+struct dummy { struct{}__attribute__((aligned (4))) a[7]; };
+
+void
+test (struct dummy a, ...)
+{
+ va_list va_arglist;
+ int i;
+
+ va_start (va_arglist, a);
+ i = va_arg (va_arglist, int);
+ if (i != 0x10)
+ __builtin_abort ();
+ va_end (va_arglist);
+}
+
+struct dummy a0;
+
+int
+main ()
+{
+ test (a0, 0x10);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/pr68355.C b/gcc/testsuite/g++.dg/pr68355.C
new file mode 100644
index 0000000..1354fc4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr68355.C
@@ -0,0 +1,24 @@
+// { dg-do compile }
+// { dg-options "-O2 -std=c++11 -fno-pic" }
+// { dg-require-effective-target fpic }
+
+template<typename _Tp, _Tp __v>
+struct integral_constant
+{
+ static constexpr _Tp value = __v;
+ typedef _Tp value_type;
+ typedef integral_constant<_Tp, __v> type;
+ constexpr operator value_type() const { return value; }
+};
+
+typedef integral_constant<bool, true> true_type;
+extern void xxx (true_type c);
+
+void
+yyy (void)
+{
+ true_type y;
+ xxx (y);
+}
+
+// { dg-final { scan-assembler "jmp\[\t \]+\[^\$\]*?_Z3xxx17integral_constantIbLb1EE" { target i?86-*-* x86_64-*-* } } }
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index bb5cd49..6b1e25d 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -394,6 +394,8 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
if (mode == BLKmode)
size_tree = TYPE_SIZE (TREE_TYPE (exp));
+ else if (lang_hooks.decls.empty_record_p (TREE_TYPE (exp)))
+ bitsize = 0;
else
bitsize = int (GET_MODE_PRECISION (mode));
}
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index 65a1ce3..1c32d81 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -154,6 +154,11 @@ unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
}
else
bp_unpack_value (bp, 9);
+ if (TYPE_P (expr))
+ /* Set if a record is empty. */
+ TYPE_LANG_FLAG_0 (expr) = (unsigned) bp_unpack_value (bp, 1);
+ else
+ bp_unpack_value (bp, 1);
}
diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
index d0b7f6d..a1bf962 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "alias.h"
#include "stor-layout.h"
#include "gomp-constants.h"
+#include "langhooks.h"
/* Output the STRING constant to the string
@@ -128,6 +129,11 @@ pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
}
else
bp_pack_value (bp, 0, 9);
+ if (TYPE_P (expr))
+ /* Stream out a bit to indicate if a record is empty. */
+ bp_pack_value (bp, lang_hooks.decls.empty_record_p (expr), 1);
+ else
+ bp_pack_value (bp, 0, 1);
}
--
2.4.3
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-17 11:01 [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class H.J. Lu
@ 2015-11-17 12:22 ` Richard Biener
2015-11-20 18:52 ` H.J. Lu
0 siblings, 1 reply; 14+ messages in thread
From: Richard Biener @ 2015-11-17 12:22 UTC (permalink / raw)
To: H.J. Lu; +Cc: GCC Patches
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).
I don't like that you need to modify targets - those checks should be done
in the caller (which may just use a new wrapper with the logic and then
dispatching to the actual hook).
Why do you need do adjust get_ref_base_and_extent?
Thanks,
Richard.
> gcc/
>
> PR c++/60336
> PR middle-end/67239
> PR target/68355
> * calls.c (store_one_arg): Use 0 for empty record size. Don't
> push 0 size argument onto stack.
> (must_pass_in_stack_var_size_or_pad): Return false for empty
> record.
> * function.c (locate_and_pad_parm): Use 0 for empty record size.
> * tree-dfa.c (get_ref_base_and_extent): Likewise.
> * langhooks-def.h (LANG_HOOKS_EMPTY_RECORD_P): New.
> (LANG_HOOKS_DECLS): Add LANG_HOOKS_EMPTY_RECORD_P.
> * langhooks.h (lang_hooks_for_decls): Add empty_record_p.
> * lto-streamer.h (LTO_major_version): Increase by 1 to 6.
> * targhooks.c: Include "langhooks.h".
> (std_gimplify_va_arg_expr): Use 0 for empty record size.
> * tree-streamer-in.c (unpack_ts_base_value_fields): Stream in
> TYPE_LANG_FLAG_0.
> * tree-streamer-out.c: Include "langhooks.h".
> (pack_ts_base_value_fields): Stream out a bit to indicate if a
> record is empty.
> * config/i386/i386.c (classify_argument): Return 0 for empty
> record.
> (construct_container): Return NULL for empty record.
> (ix86_function_arg): Likewise.
> (ix86_function_arg_advance): Skip empty record.
> (ix86_return_in_memory): Return false for empty record.
> (ix86_gimplify_va_arg): Use 0 for empty record size.
>
> gcc/cp/
>
> PR c++/60336
> PR middle-end/67239
> PR target/68355
> * class.c (is_empty_class): Changed to return bool and take
> const_tree.
> (is_really_empty_class): Changed to take const_tree. Check
> if TYPE_BINFO is zero.
> * cp-tree.h (is_empty_class): Updated.
> (is_really_empty_class): Likewise.
> * cp-lang.c (LANG_HOOKS_EMPTY_RECORD_P): New.
>
> gcc/lto/
>
> PR c++/60336
> PR middle-end/67239
> PR target/68355
> * lto-lang.c (lto_empty_record_p): New.
> (LANG_HOOKS_EMPTY_RECORD_P): Likewise.
>
> gcc/testsuite/
>
> PR c++/60336
> PR middle-end/67239
> PR target/68355
> * g++.dg/abi/empty12.C: New test.
> * g++.dg/abi/empty12.h: Likewise.
> * g++.dg/abi/empty12a.c: Likewise.
> * g++.dg/pr60336-1.C: Likewise.
> * g++.dg/pr60336-2.C: Likewise.
> * g++.dg/pr68355.C: Likewise.
> ---
> gcc/calls.c | 41 +++++++++++++++++++++++++++----------
> gcc/config/i386/i386.c | 18 +++++++++++++++-
> gcc/cp/class.c | 17 ++++++++-------
> gcc/cp/cp-lang.c | 2 ++
> gcc/cp/cp-tree.h | 4 ++--
> gcc/function.c | 7 +++++--
> gcc/langhooks-def.h | 2 ++
> gcc/langhooks.h | 3 +++
> gcc/lto-streamer.h | 2 +-
> gcc/lto/lto-lang.c | 13 ++++++++++++
> gcc/targhooks.c | 6 +++++-
> gcc/testsuite/g++.dg/abi/empty12.C | 17 +++++++++++++++
> gcc/testsuite/g++.dg/abi/empty12.h | 9 ++++++++
> gcc/testsuite/g++.dg/abi/empty12a.c | 6 ++++++
> gcc/testsuite/g++.dg/pr60336-1.C | 17 +++++++++++++++
> gcc/testsuite/g++.dg/pr60336-2.C | 28 +++++++++++++++++++++++++
> gcc/testsuite/g++.dg/pr68355.C | 24 ++++++++++++++++++++++
> gcc/tree-dfa.c | 2 ++
> gcc/tree-streamer-in.c | 5 +++++
> gcc/tree-streamer-out.c | 6 ++++++
> 20 files changed, 204 insertions(+), 25 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/abi/empty12.C
> create mode 100644 gcc/testsuite/g++.dg/abi/empty12.h
> create mode 100644 gcc/testsuite/g++.dg/abi/empty12a.c
> create mode 100644 gcc/testsuite/g++.dg/pr60336-1.C
> create mode 100644 gcc/testsuite/g++.dg/pr60336-2.C
> create mode 100644 gcc/testsuite/g++.dg/pr68355.C
>
> diff --git a/gcc/calls.c b/gcc/calls.c
> index b56556a..ecc9b7a 100644
> --- a/gcc/calls.c
> +++ b/gcc/calls.c
> @@ -4835,7 +4835,10 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
> Note that in C the default argument promotions
> will prevent such mismatches. */
>
> - size = GET_MODE_SIZE (arg->mode);
> + if (lang_hooks.decls.empty_record_p (TREE_TYPE (pval)))
> + size = 0;
> + else
> + size = GET_MODE_SIZE (arg->mode);
> /* Compute how much space the push instruction will push.
> On many machines, pushing a byte will advance the stack
> pointer by a halfword. */
> @@ -4865,10 +4868,14 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
>
> /* This isn't already where we want it on the stack, so put it there.
> This can either be done with push or copy insns. */
> - if (!emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
> - parm_align, partial, reg, used - size, argblock,
> - ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
> - ARGS_SIZE_RTX (arg->locate.alignment_pad), true))
> + if (used
> + && !emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval),
> + NULL_RTX, parm_align, partial, reg,
> + used - size, argblock,
> + ARGS_SIZE_RTX (arg->locate.offset),
> + reg_parm_stack_space,
> + ARGS_SIZE_RTX (arg->locate.alignment_pad),
> + true))
> sibcall_failure = 1;
>
> /* Unless this is a partially-in-register argument, the argument is now
> @@ -4900,10 +4907,16 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
> {
> /* PUSH_ROUNDING has no effect on us, because emit_push_insn
> for BLKmode is careful to avoid it. */
> + bool empty_record
> + = lang_hooks.decls.empty_record_p (TREE_TYPE (pval));
> excess = (arg->locate.size.constant
> - - int_size_in_bytes (TREE_TYPE (pval))
> + - (empty_record
> + ? 0
> + : int_size_in_bytes (TREE_TYPE (pval)))
> + partial);
> - size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
> + size_rtx = expand_expr ((empty_record
> + ? size_zero_node
> + : size_in_bytes (TREE_TYPE (pval))),
> NULL_RTX, TYPE_MODE (sizetype),
> EXPAND_NORMAL);
> }
> @@ -4971,10 +4984,13 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
> }
> }
>
> - emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
> - parm_align, partial, reg, excess, argblock,
> - ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
> - ARGS_SIZE_RTX (arg->locate.alignment_pad), false);
> + if (!CONST_INT_P (size_rtx) || INTVAL (size_rtx) != 0)
> + emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval),
> + size_rtx, parm_align, partial, reg, excess,
> + argblock, ARGS_SIZE_RTX (arg->locate.offset),
> + reg_parm_stack_space,
> + ARGS_SIZE_RTX (arg->locate.alignment_pad),
> + false);
>
> /* Unless this is a partially-in-register argument, the argument is now
> in the stack.
> @@ -5052,6 +5068,9 @@ must_pass_in_stack_var_size_or_pad (machine_mode mode, const_tree type)
> if (TREE_ADDRESSABLE (type))
> return true;
>
> + if (lang_hooks.decls.empty_record_p (type))
> + return false;
> +
> /* If the padding and mode of the type is such that a copy into
> a register would put it into the wrong part of the register. */
> if (mode == BLKmode
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index 6173dae..8bd6198 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -7920,6 +7920,9 @@ static int
> classify_argument (machine_mode mode, const_tree type,
> enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset)
> {
> + if (type && lang_hooks.decls.empty_record_p (type))
> + return 0;
> +
> HOST_WIDE_INT bytes =
> (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
> int words = CEIL (bytes + (bit_offset % 64) / 8, UNITS_PER_WORD);
> @@ -8371,6 +8374,9 @@ construct_container (machine_mode mode, machine_mode orig_mode,
> static bool issued_sse_ret_error;
> static bool issued_x87_ret_error;
>
> + if (type && lang_hooks.decls.empty_record_p (type))
> + return NULL;
> +
> machine_mode tmpmode;
> int bytes =
> (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
> @@ -8783,6 +8789,9 @@ ix86_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
> HOST_WIDE_INT bytes, words;
> int nregs;
>
> + if (type && lang_hooks.decls.empty_record_p (type))
> + return;
> +
> if (mode == BLKmode)
> bytes = int_size_in_bytes (type);
> else
> @@ -9099,6 +9108,9 @@ ix86_function_arg (cumulative_args_t cum_v, machine_mode omode,
> HOST_WIDE_INT bytes, words;
> rtx arg;
>
> + if (type && lang_hooks.decls.empty_record_p (type))
> + return NULL;
> +
> /* All pointer bounds arguments are handled separately here. */
> if ((type && POINTER_BOUNDS_TYPE_P (type))
> || POINTER_BOUNDS_MODE_P (mode))
> @@ -9708,6 +9720,9 @@ ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
> if (POINTER_BOUNDS_TYPE_P (type))
> return false;
>
> + if (type && lang_hooks.decls.empty_record_p (type))
> + return false;
> +
> if (TARGET_64BIT)
> {
> if (ix86_function_type_abi (fntype) == MS_ABI)
> @@ -10266,7 +10281,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 && lang_hooks.decls.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);
> diff --git a/gcc/cp/class.c b/gcc/cp/class.c
> index 216a301..c380734 100644
> --- a/gcc/cp/class.c
> +++ b/gcc/cp/class.c
> @@ -8068,8 +8068,8 @@ build_self_reference (void)
>
> /* Returns 1 if TYPE contains only padding bytes. */
>
> -int
> -is_empty_class (tree type)
> +bool
> +is_empty_class (const_tree type)
> {
> if (type == error_mark_node)
> return 0;
> @@ -8084,7 +8084,7 @@ is_empty_class (tree type)
> possible combinations of empty classes and possibly a vptr. */
>
> bool
> -is_really_empty_class (tree type)
> +is_really_empty_class (const_tree type)
> {
> if (CLASS_TYPE_P (type))
> {
> @@ -8098,10 +8098,13 @@ is_really_empty_class (tree type)
> if (COMPLETE_TYPE_P (type) && is_empty_class (type))
> return true;
>
> - for (binfo = TYPE_BINFO (type), i = 0;
> - BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
> - if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
> - return false;
> + /* TYPE_BINFO may be zeron when is_really_empty_class is called
> + from LANG_HOOKS_EMPTY_RECORD_P. */
> + binfo = TYPE_BINFO (type);
> + if (binfo)
> + for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
> + if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
> + return false;
> for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
> if (TREE_CODE (field) == FIELD_DECL
> && !DECL_ARTIFICIAL (field)
> diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
> index 048108d..80174cb 100644
> --- a/gcc/cp/cp-lang.c
> +++ b/gcc/cp/cp-lang.c
> @@ -78,6 +78,8 @@ static tree cxx_enum_underlying_base_type (const_tree);
> #define LANG_HOOKS_EH_RUNTIME_TYPE build_eh_type_type
> #undef LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE
> #define LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE cxx_enum_underlying_base_type
> +#undef LANG_HOOKS_EMPTY_RECORD_P
> +#define LANG_HOOKS_EMPTY_RECORD_P is_really_empty_class
>
> /* Each front end provides its own lang hook initializer. */
> struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 84437b4..dc79979 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -5578,8 +5578,8 @@ extern tree finish_struct (tree, tree);
> extern void finish_struct_1 (tree);
> extern int resolves_to_fixed_type_p (tree, int *);
> extern void init_class_processing (void);
> -extern int is_empty_class (tree);
> -extern bool is_really_empty_class (tree);
> +extern bool is_empty_class (const_tree);
> +extern bool is_really_empty_class (const_tree);
> extern void pushclass (tree);
> extern void popclass (void);
> extern void push_nested_class (tree);
> diff --git a/gcc/function.c b/gcc/function.c
> index afc2c87..b59157d 100644
> --- a/gcc/function.c
> +++ b/gcc/function.c
> @@ -4093,8 +4093,11 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs,
>
> part_size_in_regs = (reg_parm_stack_space == 0 ? partial : 0);
>
> - sizetree
> - = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
> + if (type)
> + sizetree = (lang_hooks.decls.empty_record_p (type)
> + ? size_zero_node : size_in_bytes (type));
> + else
> + sizetree = size_int (GET_MODE_SIZE (passed_mode));
> where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
> boundary = targetm.calls.function_arg_boundary (passed_mode, type);
> round_boundary = targetm.calls.function_arg_round_boundary (passed_mode,
> diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
> index 18ac84d..df4cbf8 100644
> --- a/gcc/langhooks-def.h
> +++ b/gcc/langhooks-def.h
> @@ -163,6 +163,7 @@ extern tree lhd_make_node (enum tree_code);
> #define LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P hook_bool_const_tree_false
> #define LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P \
> hook_bool_tree_tree_false
> +#define LANG_HOOKS_EMPTY_RECORD_P hook_bool_const_tree_false
> #define LANG_HOOKS_GET_GENERIC_FUNCTION_DECL hook_tree_const_tree_null
> #define LANG_HOOKS_TYPE_PROMOTES_TO lhd_type_promotes_to
> #define LANG_HOOKS_REGISTER_BUILTIN_TYPE lhd_register_builtin_type
> @@ -228,6 +229,7 @@ extern tree lhd_make_node (enum tree_code);
> LANG_HOOKS_FUNCTION_DECL_DELETED_P, \
> LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P, \
> LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P, \
> + LANG_HOOKS_EMPTY_RECORD_P, \
> LANG_HOOKS_GET_GENERIC_FUNCTION_DECL, \
> LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \
> LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS, \
> diff --git a/gcc/langhooks.h b/gcc/langhooks.h
> index d8d01fa..450bdee 100644
> --- a/gcc/langhooks.h
> +++ b/gcc/langhooks.h
> @@ -177,6 +177,9 @@ struct lang_hooks_for_decls
> function parameter pack. */
> bool (*function_parm_expanded_from_pack_p) (tree, tree);
>
> + /* Determine if a type is an empty record. */
> + bool (*empty_record_p) (const_tree type);
> +
> /* Returns the generic declaration of a generic function instantiations. */
> tree (*get_generic_function_decl) (const_tree);
>
> diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
> index 5aae9e9..cc4cede 100644
> --- a/gcc/lto-streamer.h
> +++ b/gcc/lto-streamer.h
> @@ -128,7 +128,7 @@ along with GCC; see the file COPYING3. If not see
> String are represented in the table as pairs, a length in ULEB128
> form followed by the data for the string. */
>
> -#define LTO_major_version 5
> +#define LTO_major_version 6
> #define LTO_minor_version 0
>
> typedef unsigned char lto_decl_flags_t;
> diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
> index 53dd8f6..dc849a4 100644
> --- a/gcc/lto/lto-lang.c
> +++ b/gcc/lto/lto-lang.c
> @@ -1306,6 +1306,16 @@ static void lto_init_ts (void)
> tree_contains_struct[NAMESPACE_DECL][TS_DECL_MINIMAL] = 1;
> }
>
> +/* Return true if TYPE contains no actual data, just various possible
> + combinations of empty records. */
> +
> +static bool
> +lto_empty_record_p (const_tree type)
> +{
> + /* Set if a record is empty. */
> + return TYPE_LANG_FLAG_0 (type);
> +}
> +
> #undef LANG_HOOKS_NAME
> #define LANG_HOOKS_NAME "GNU GIMPLE"
> #undef LANG_HOOKS_OPTION_LANG_MASK
> @@ -1363,6 +1373,9 @@ static void lto_init_ts (void)
> #undef LANG_HOOKS_INIT_TS
> #define LANG_HOOKS_INIT_TS lto_init_ts
>
> +#undef LANG_HOOKS_EMPTY_RECORD_P
> +#define LANG_HOOKS_EMPTY_RECORD_P lto_empty_record_p
> +
> struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
>
> /* Language hooks that are not part of lang_hooks. */
> diff --git a/gcc/targhooks.c b/gcc/targhooks.c
> index c34b4e9..5e74dd9 100644
> --- a/gcc/targhooks.c
> +++ b/gcc/targhooks.c
> @@ -74,6 +74,7 @@ along with GCC; see the file COPYING3. If not see
> #include "intl.h"
> #include "opts.h"
> #include "gimplify.h"
> +#include "langhooks.h"
>
>
> bool
> @@ -1823,9 +1824,12 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
> /* Hoist the valist value into a temporary for the moment. */
> valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
>
> + bool empty_record = lang_hooks.decls.empty_record_p (type);
> +
> /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
> requires greater alignment, we must perform dynamic alignment. */
> if (boundary > align
> + && !empty_record
> && !integer_zerop (TYPE_SIZE (type)))
> {
> t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
> @@ -1852,7 +1856,7 @@ 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);
> + type_size = empty_record ? size_zero_node : 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/testsuite/g++.dg/abi/empty12.C b/gcc/testsuite/g++.dg/abi/empty12.C
> new file mode 100644
> index 0000000..430d57d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/abi/empty12.C
> @@ -0,0 +1,17 @@
> +// PR c++/60336
> +// { dg-do run }
> +// { dg-options "-x c" }
> +// { dg-additional-sources "empty12a.c" }
> +// { dg-prune-output "command line option" }
> +
> +#include "empty12.h"
> +extern "C" void fun(struct dummy, struct foo);
> +
> +int main()
> +{
> + struct dummy d;
> + struct foo f = { -1, -2, -3, -4, -5 };
> +
> + fun(d, f);
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/abi/empty12.h b/gcc/testsuite/g++.dg/abi/empty12.h
> new file mode 100644
> index 0000000..c61afcd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/abi/empty12.h
> @@ -0,0 +1,9 @@
> +struct dummy { };
> +struct foo
> +{
> + int i1;
> + int i2;
> + int i3;
> + int i4;
> + int i5;
> +};
> diff --git a/gcc/testsuite/g++.dg/abi/empty12a.c b/gcc/testsuite/g++.dg/abi/empty12a.c
> new file mode 100644
> index 0000000..34a25ba
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/abi/empty12a.c
> @@ -0,0 +1,6 @@
> +#include "empty12.h"
> +void fun(struct dummy d, struct foo f)
> +{
> + if (f.i1 != -1)
> + __builtin_abort();
> +}
> diff --git a/gcc/testsuite/g++.dg/pr60336-1.C b/gcc/testsuite/g++.dg/pr60336-1.C
> new file mode 100644
> index 0000000..af08638
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr60336-1.C
> @@ -0,0 +1,17 @@
> +// { dg-do compile }
> +// { dg-options "-O2 -std=c++11 -fno-pic" }
> +// { dg-require-effective-target fpic }
> +
> +struct dummy { };
> +struct true_type { struct dummy i; };
> +
> +extern true_type y;
> +extern void xxx (true_type c);
> +
> +void
> +yyy (void)
> +{
> + xxx (y);
> +}
> +
> +// { dg-final { scan-assembler "jmp\[\t \]+\[^\$\]*?_Z3xxx9true_type" { target i?86-*-* x86_64-*-* } } }
> diff --git a/gcc/testsuite/g++.dg/pr60336-2.C b/gcc/testsuite/g++.dg/pr60336-2.C
> new file mode 100644
> index 0000000..7b902e8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr60336-2.C
> @@ -0,0 +1,28 @@
> +// { dg-do run }
> +// { dg-options "-O2" }
> +
> +#include <stdarg.h>
> +
> +struct dummy { struct{}__attribute__((aligned (4))) a[7]; };
> +
> +void
> +test (struct dummy a, ...)
> +{
> + va_list va_arglist;
> + int i;
> +
> + va_start (va_arglist, a);
> + i = va_arg (va_arglist, int);
> + if (i != 0x10)
> + __builtin_abort ();
> + va_end (va_arglist);
> +}
> +
> +struct dummy a0;
> +
> +int
> +main ()
> +{
> + test (a0, 0x10);
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/pr68355.C b/gcc/testsuite/g++.dg/pr68355.C
> new file mode 100644
> index 0000000..1354fc4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr68355.C
> @@ -0,0 +1,24 @@
> +// { dg-do compile }
> +// { dg-options "-O2 -std=c++11 -fno-pic" }
> +// { dg-require-effective-target fpic }
> +
> +template<typename _Tp, _Tp __v>
> +struct integral_constant
> +{
> + static constexpr _Tp value = __v;
> + typedef _Tp value_type;
> + typedef integral_constant<_Tp, __v> type;
> + constexpr operator value_type() const { return value; }
> +};
> +
> +typedef integral_constant<bool, true> true_type;
> +extern void xxx (true_type c);
> +
> +void
> +yyy (void)
> +{
> + true_type y;
> + xxx (y);
> +}
> +
> +// { dg-final { scan-assembler "jmp\[\t \]+\[^\$\]*?_Z3xxx17integral_constantIbLb1EE" { target i?86-*-* x86_64-*-* } } }
> diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
> index bb5cd49..6b1e25d 100644
> --- a/gcc/tree-dfa.c
> +++ b/gcc/tree-dfa.c
> @@ -394,6 +394,8 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
> machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
> if (mode == BLKmode)
> size_tree = TYPE_SIZE (TREE_TYPE (exp));
> + else if (lang_hooks.decls.empty_record_p (TREE_TYPE (exp)))
> + bitsize = 0;
> else
> bitsize = int (GET_MODE_PRECISION (mode));
> }
> diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
> index 65a1ce3..1c32d81 100644
> --- a/gcc/tree-streamer-in.c
> +++ b/gcc/tree-streamer-in.c
> @@ -154,6 +154,11 @@ unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
> }
> else
> bp_unpack_value (bp, 9);
> + if (TYPE_P (expr))
> + /* Set if a record is empty. */
> + TYPE_LANG_FLAG_0 (expr) = (unsigned) bp_unpack_value (bp, 1);
> + else
> + bp_unpack_value (bp, 1);
> }
>
>
> diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
> index d0b7f6d..a1bf962 100644
> --- a/gcc/tree-streamer-out.c
> +++ b/gcc/tree-streamer-out.c
> @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
> #include "alias.h"
> #include "stor-layout.h"
> #include "gomp-constants.h"
> +#include "langhooks.h"
>
>
> /* Output the STRING constant to the string
> @@ -128,6 +129,11 @@ pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
> }
> else
> bp_pack_value (bp, 0, 9);
> + if (TYPE_P (expr))
> + /* Stream out a bit to indicate if a record is empty. */
> + bp_pack_value (bp, lang_hooks.decls.empty_record_p (expr), 1);
> + else
> + bp_pack_value (bp, 0, 1);
> }
>
>
> --
> 2.4.3
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-17 12:22 ` Richard Biener
@ 2015-11-20 18:52 ` H.J. Lu
2015-11-20 22:17 ` Jason Merrill
0 siblings, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2015-11-20 18:52 UTC (permalink / raw)
To: Richard Biener; +Cc: GCC Patches
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" "" }
Should I add a bit to tree_type_common? It may crease the size
of tree_type_common by 4 bytes since there is unused bits in
tree_type_common.
> I don't like that you need to modify targets - those checks should be done
> in the caller (which may just use a new wrapper with the logic and then
> dispatching to the actual hook).
I can do that.
> Why do you need do adjust get_ref_base_and_extent?
get_ref_base_and_extent is changed to set bitsize to 0 for empty records
so that when ref_maybe_used_by_call_p_1 calls get_ref_base_and_extent to
get 0 as the maximum size on empty record. Otherwise, find_tail_calls
won't perform tail call optimization for functions with empty record
parameters, as in
struct dummy { };
struct true_type { struct dummy i; };
extern true_type y;
extern void xxx (true_type c);
void
yyy (void)
{
xxx (y);
}
--
H.J.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-20 18:52 ` H.J. Lu
@ 2015-11-20 22:17 ` Jason Merrill
2015-11-20 22:24 ` Jason Merrill
2015-11-20 23:47 ` H.J. Lu
0 siblings, 2 replies; 14+ messages in thread
From: Jason Merrill @ 2015-11-20 22:17 UTC (permalink / raw)
To: H.J. Lu, Richard Biener; +Cc: GCC Patches
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.
Jason
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-20 22:17 ` Jason Merrill
@ 2015-11-20 22:24 ` Jason Merrill
2015-11-20 23:47 ` H.J. Lu
1 sibling, 0 replies; 14+ messages in thread
From: Jason Merrill @ 2015-11-20 22:24 UTC (permalink / raw)
To: gcc-patches; +Cc: GCC Patches
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.
Jason
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-20 22:17 ` Jason Merrill
2015-11-20 22:24 ` Jason Merrill
@ 2015-11-20 23:47 ` H.J. Lu
2015-11-23 9:59 ` Richard Biener
1 sibling, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2015-11-20 23:47 UTC (permalink / raw)
To: Jason Merrill; +Cc: Richard Biener, GCC Patches
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.
H.J.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-20 23:47 ` H.J. Lu
@ 2015-11-23 9:59 ` Richard Biener
2015-11-23 20:54 ` H.J. Lu
0 siblings, 1 reply; 14+ messages in thread
From: Richard Biener @ 2015-11-23 9:59 UTC (permalink / raw)
To: H.J. Lu; +Cc: Jason Merrill, GCC Patches
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.
Richard.
>
> H.J.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-23 9:59 ` Richard Biener
@ 2015-11-23 20:54 ` H.J. Lu
2015-11-24 3:48 ` Patrick Palka
0 siblings, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2015-11-23 20:54 UTC (permalink / raw)
To: Richard Biener; +Cc: Jason Merrill, GCC Patches
[-- Attachment #1: Type: text/plain, Size: 3058 bytes --]
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?
Thanks.
--
H.J.
[-- Attachment #2: 0001-Add-TYPE_EMPTY_RECORD-for-C-empty-class.patch --]
[-- Type: text/x-patch, Size: 31923 bytes --]
From 1e3e6ed42ed86b74d01bd3a6b869c15dba964c21 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 15 Nov 2015 13:19:05 -0800
Subject: [PATCH] Add TYPE_EMPTY_RECORD for C++ empty class
Empty record should be returned and passed the same way in C and C++.
This patch overloads a bit, side_effects_flag, in tree_base for C++
empty class. Middle-end and x86 backend are updated to ignore empty
records for parameter passing and function value return. Other targets
may need similar changes.
get_ref_base_and_extent is changed to set bitsize to 0 for empty records
so that when ref_maybe_used_by_call_p_1 calls get_ref_base_and_extent to
get 0 as the maximum size on empty record. Otherwise, find_tail_calls
won't perform tail call optimization for functions with empty record
parameters, as shown in g++.dg/pr60336-1.C and g++.dg/pr60336-2.C.
gcc/
PR c++/60336
PR middle-end/67239
PR target/68355
* calls.c (initialize_argument_information): Replace
targetm.calls.function_arg, targetm.calls.function_incoming_arg
and targetm.calls.function_arg_advance with function_arg,
function_incoming_arg and function_arg_advance.
(expand_call): Likewise.
(emit_library_call_value_1): Likewise.
(store_one_arg): Use 0 for empty record size. Don't
push 0 size argument onto stack.
(must_pass_in_stack_var_size_or_pad): Return false for empty
record.
* dse.c (get_call_args): Replace targetm.calls.function_arg
and targetm.calls.function_arg_advance with function_arg and
function_arg_advance.
* expr.c (block_move_libcall_safe_for_call_parm): Likewise.
* function.c (aggregate_value_p): Replace
targetm.calls.return_in_memory with return_in_memory.
(assign_parm_find_entry_rtl): Replace
targetm.calls.function_incoming_arg with function_incoming_arg.
(assign_parms): Replace targetm.calls.function_arg_advance with
function_arg_advance.
(gimplify_parameters): Replace targetm.calls.function_arg_advance
with function_arg_advance.
(locate_and_pad_parm): Use 0 for empty record size.
(function_arg_advance): New wrapper function.
(function_arg): Likewise.
(function_incoming_arg): Likewise.
(return_in_memory): Likewise.
* lto-streamer-out.c (hash_tree): Call hstate.add_flag with
TYPE_EMPTY_RECORD for types.
* print-tree.c (print_node): Also handle TYPE_EMPTY_RECORD.
* ubsan.c (ubsan_type_descriptor): Likewise.
* target.h (function_arg_advance): New prototype.
(function_arg): Likewise.
(function_incoming_arg): Likewise.
(return_in_memory): Likewise.
* targhooks.c (std_gimplify_va_arg_expr): Use 0 for empty record
size.
* tree-dfa.c (get_ref_base_and_extent): Likewise.
* tree-core.h (tree_base): Mention TYPE_EMPTY_RECORD in comments
for side_effects_flag.
* tree-streamer-in.c (unpack_ts_base_value_fields): Stream in
TYPE_EMPTY_RECORD for types.
* tree-streamer-out.c (pack_ts_base_value_fields): Stream out
TYPE_EMPTY_RECORD for types.
* tree.h (TYPE_EMPTY_RECORD): New.
(type_is_empty_record_p): New static inline function.
* var-tracking.c (prepare_call_arguments): Replace
targetm.calls.function_arg and targetm.calls.function_arg_advance
with function_arg and function_arg_advance.
* config/i386/i386.c (ix86_gimplify_va_arg): Use 0 for empty
record size.
gcc/c
PR c++/60336
PR middle-end/67239
PR target/68355
* c-aux-info.c (gen_type): Add TYPE_EMPTY_RECORD check.
gcc/cp/
PR c++/60336
PR middle-end/67239
PR target/68355
* class.c (finish_struct_1): Set TYPE_EMPTY_RECORD with return
value from is_really_empty_class ().
gcc/lto/
PR c++/60336
PR middle-end/67239
PR target/68355
* lto.c (compare_tree_sccs_1): Call compare_values with
TYPE_EMPTY_RECORD for types.
gcc/testsuite/
PR c++/60336
PR middle-end/67239
PR target/68355
* g++.dg/abi/empty12.C: New test.
* g++.dg/abi/empty12.h: Likewise.
* g++.dg/abi/empty12a.c: Likewise.
* g++.dg/pr60336-1.C: Likewise.
* g++.dg/pr60336-2.C: Likewise.
* g++.dg/pr68355.C: Likewise.
---
gcc/c/c-aux-info.c | 2 +
gcc/calls.c | 76 +++++++++++++++++++++---------------
gcc/config/i386/i386.c | 3 +-
gcc/cp/class.c | 2 +
gcc/dse.c | 4 +-
gcc/expr.c | 5 +--
gcc/function.c | 78 ++++++++++++++++++++++++++++++-------
gcc/lto-streamer-out.c | 2 +
gcc/lto/lto.c | 2 +
gcc/print-tree.c | 3 ++
gcc/target.h | 8 ++++
gcc/targhooks.c | 5 ++-
gcc/testsuite/g++.dg/abi/empty12.C | 17 ++++++++
gcc/testsuite/g++.dg/abi/empty12.h | 9 +++++
gcc/testsuite/g++.dg/abi/empty12a.c | 6 +++
gcc/testsuite/g++.dg/pr60336-1.C | 17 ++++++++
gcc/testsuite/g++.dg/pr60336-2.C | 28 +++++++++++++
gcc/testsuite/g++.dg/pr68355.C | 24 ++++++++++++
gcc/tree-core.h | 3 ++
gcc/tree-dfa.c | 2 +
gcc/tree-streamer-in.c | 5 ++-
gcc/tree-streamer-out.c | 5 ++-
gcc/tree.h | 12 ++++++
gcc/ubsan.c | 3 +-
gcc/var-tracking.c | 18 ++++-----
25 files changed, 274 insertions(+), 65 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/abi/empty12.C
create mode 100644 gcc/testsuite/g++.dg/abi/empty12.h
create mode 100644 gcc/testsuite/g++.dg/abi/empty12a.c
create mode 100644 gcc/testsuite/g++.dg/pr60336-1.C
create mode 100644 gcc/testsuite/g++.dg/pr60336-2.C
create mode 100644 gcc/testsuite/g++.dg/pr68355.C
diff --git a/gcc/c/c-aux-info.c b/gcc/c/c-aux-info.c
index 79d9851..93b001b 100644
--- a/gcc/c/c-aux-info.c
+++ b/gcc/c/c-aux-info.c
@@ -433,6 +433,8 @@ gen_type (const char *ret_val, tree t, formals_style style)
ret_val = concat ("volatile ", ret_val, NULL);
if (TYPE_RESTRICT (t))
ret_val = concat ("restrict ", ret_val, NULL);
+ if (TYPE_EMPTY_RECORD (t))
+ ret_val = concat ("empty-record ", ret_val, NULL);
return ret_val;
}
diff --git a/gcc/calls.c b/gcc/calls.c
index b56556a..a81cb3d 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1391,8 +1391,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
args[i].unsignedp = unsignedp;
args[i].mode = mode;
- args[i].reg = targetm.calls.function_arg (args_so_far, mode, type,
- argpos < n_named_args);
+ args[i].reg = function_arg (args_so_far, mode, type,
+ argpos < n_named_args);
if (args[i].reg && CONST_INT_P (args[i].reg))
{
@@ -1405,8 +1405,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
arguments have to go into the incoming registers. */
if (targetm.calls.function_incoming_arg != targetm.calls.function_arg)
args[i].tail_call_reg
- = targetm.calls.function_incoming_arg (args_so_far, mode, type,
- argpos < n_named_args);
+ = function_incoming_arg (args_so_far, mode, type,
+ argpos < n_named_args);
else
args[i].tail_call_reg = args[i].reg;
@@ -1467,8 +1467,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
/* Increment ARGS_SO_FAR, which has info about which arg-registers
have been used, etc. */
- targetm.calls.function_arg_advance (args_so_far, TYPE_MODE (type),
- type, argpos < n_named_args);
+ function_arg_advance (args_so_far, TYPE_MODE (type), type,
+ argpos < n_named_args);
}
}
@@ -3320,14 +3320,11 @@ expand_call (tree exp, rtx target, int ignore)
/* Set up next argument register. For sibling calls on machines
with register windows this should be the incoming register. */
if (pass == 0)
- next_arg_reg = targetm.calls.function_incoming_arg (args_so_far,
- VOIDmode,
- void_type_node,
- true);
+ next_arg_reg = function_incoming_arg (args_so_far, VOIDmode,
+ void_type_node, true);
else
- 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 (pass == 1 && (return_flags & ERF_RETURNS_ARG))
{
@@ -3939,8 +3936,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
argvec[count].mode = Pmode;
argvec[count].partial = 0;
- argvec[count].reg = targetm.calls.function_arg (args_so_far,
- Pmode, NULL_TREE, true);
+ argvec[count].reg = function_arg (args_so_far, Pmode, NULL_TREE,
+ true);
gcc_assert (targetm.calls.arg_partial_bytes (args_so_far, Pmode,
NULL_TREE, 1) == 0);
@@ -3957,7 +3954,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|| reg_parm_stack_space > 0)
args_size.constant += argvec[count].locate.size.constant;
- targetm.calls.function_arg_advance (args_so_far, Pmode, (tree) 0, true);
+ function_arg_advance (args_so_far, Pmode, (tree) 0, true);
count++;
}
@@ -4022,7 +4019,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
mode = promote_function_mode (NULL_TREE, mode, &unsigned_p, NULL_TREE, 0);
argvec[count].mode = mode;
argvec[count].value = convert_modes (mode, GET_MODE (val), val, unsigned_p);
- argvec[count].reg = targetm.calls.function_arg (args_so_far, mode,
+ argvec[count].reg = function_arg (args_so_far, mode,
NULL_TREE, true);
argvec[count].partial
@@ -4052,7 +4049,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
GET_MODE_SIZE (mode) <= UNITS_PER_WORD);
#endif
- targetm.calls.function_arg_advance (args_so_far, mode, (tree) 0, true);
+ function_arg_advance (args_so_far, mode, (tree) 0, true);
}
/* If this machine requires an external definition for library
@@ -4399,8 +4396,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
build_function_type (tfom, NULL_TREE),
original_args_size.constant, args_size.constant,
struct_value_size,
- targetm.calls.function_arg (args_so_far,
- VOIDmode, void_type_node, true),
+ function_arg (args_so_far, VOIDmode, void_type_node, true),
valreg,
old_inhibit_defer_pop + 1, call_fusage, flags, args_so_far);
@@ -4835,7 +4831,10 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
Note that in C the default argument promotions
will prevent such mismatches. */
- size = GET_MODE_SIZE (arg->mode);
+ if (type_is_empty_record_p (TREE_TYPE (pval)))
+ size = 0;
+ else
+ size = GET_MODE_SIZE (arg->mode);
/* Compute how much space the push instruction will push.
On many machines, pushing a byte will advance the stack
pointer by a halfword. */
@@ -4865,10 +4864,14 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
/* This isn't already where we want it on the stack, so put it there.
This can either be done with push or copy insns. */
- if (!emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
- parm_align, partial, reg, used - size, argblock,
- ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
- ARGS_SIZE_RTX (arg->locate.alignment_pad), true))
+ if (used
+ && !emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval),
+ NULL_RTX, parm_align, partial, reg,
+ used - size, argblock,
+ ARGS_SIZE_RTX (arg->locate.offset),
+ reg_parm_stack_space,
+ ARGS_SIZE_RTX (arg->locate.alignment_pad),
+ true))
sibcall_failure = 1;
/* Unless this is a partially-in-register argument, the argument is now
@@ -4900,10 +4903,15 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
{
/* PUSH_ROUNDING has no effect on us, because emit_push_insn
for BLKmode is careful to avoid it. */
+ bool empty_record = type_is_empty_record_p (TREE_TYPE (pval));
excess = (arg->locate.size.constant
- - int_size_in_bytes (TREE_TYPE (pval))
+ - (empty_record
+ ? 0
+ : int_size_in_bytes (TREE_TYPE (pval)))
+ partial);
- size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
+ size_rtx = expand_expr ((empty_record
+ ? size_zero_node
+ : size_in_bytes (TREE_TYPE (pval))),
NULL_RTX, TYPE_MODE (sizetype),
EXPAND_NORMAL);
}
@@ -4971,10 +4979,13 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
}
}
- emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
- parm_align, partial, reg, excess, argblock,
- ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
- ARGS_SIZE_RTX (arg->locate.alignment_pad), false);
+ if (!CONST_INT_P (size_rtx) || INTVAL (size_rtx) != 0)
+ emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval),
+ size_rtx, parm_align, partial, reg, excess,
+ argblock, ARGS_SIZE_RTX (arg->locate.offset),
+ reg_parm_stack_space,
+ ARGS_SIZE_RTX (arg->locate.alignment_pad),
+ false);
/* Unless this is a partially-in-register argument, the argument is now
in the stack.
@@ -5052,6 +5063,9 @@ must_pass_in_stack_var_size_or_pad (machine_mode mode, const_tree type)
if (TREE_ADDRESSABLE (type))
return true;
+ if (type_is_empty_record_p (type))
+ return false;
+
/* If the padding and mode of the type is such that a copy into
a register would put it into the wrong part of the register. */
if (mode == BLKmode
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index cc42544..01d4d80 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -10277,7 +10277,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);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 216a301..d97aae6 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6802,6 +6802,8 @@ finish_struct_1 (tree t)
TYPE_TRANSPARENT_AGGR (t) = 0;
}
}
+
+ TYPE_EMPTY_RECORD (t) = is_really_empty_class (t);
}
/* Insert FIELDS into T for the sorted case if the FIELDS count is
diff --git a/gcc/dse.c b/gcc/dse.c
index 35eef71..594106f 100644
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -2366,7 +2366,7 @@ get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
{
machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
rtx reg, link, tmp;
- reg = targetm.calls.function_arg (args_so_far, mode, NULL_TREE, true);
+ reg = function_arg (args_so_far, mode, NULL_TREE, true);
if (!reg || !REG_P (reg) || GET_MODE (reg) != mode
|| GET_MODE_CLASS (mode) != MODE_INT)
return false;
@@ -2400,7 +2400,7 @@ get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
if (tmp)
args[idx] = tmp;
- targetm.calls.function_arg_advance (args_so_far, mode, NULL_TREE, true);
+ function_arg_advance (args_so_far, mode, NULL_TREE, true);
}
if (arg != void_list_node || idx != nargs)
return false;
diff --git a/gcc/expr.c b/gcc/expr.c
index bd43dc4..384581a 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -1198,13 +1198,12 @@ block_move_libcall_safe_for_call_parm (void)
for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
{
machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
- rtx tmp = targetm.calls.function_arg (args_so_far, mode,
- NULL_TREE, true);
+ rtx tmp = function_arg (args_so_far, mode, NULL_TREE, true);
if (!tmp || !REG_P (tmp))
return false;
if (targetm.calls.arg_partial_bytes (args_so_far, mode, NULL, 1))
return false;
- targetm.calls.function_arg_advance (args_so_far, mode,
+ function_arg_advance (args_so_far, mode,
NULL_TREE, true);
}
}
diff --git a/gcc/function.c b/gcc/function.c
index afc2c87..d8924fe 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -2073,7 +2073,7 @@ aggregate_value_p (const_tree exp, const_tree fntype)
if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type))
return 1;
- if (targetm.calls.return_in_memory (type, fntype))
+ if (return_in_memory (type, fntype))
return 1;
/* Make sure we have suitable call-clobbered regs to return
@@ -2523,10 +2523,10 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
return;
}
- entry_parm = targetm.calls.function_incoming_arg (all->args_so_far,
- data->promoted_mode,
- data->passed_type,
- data->named_arg);
+ entry_parm = function_incoming_arg (all->args_so_far,
+ data->promoted_mode,
+ data->passed_type,
+ data->named_arg);
if (entry_parm == 0)
data->promoted_mode = data->passed_mode;
@@ -2550,9 +2550,9 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
if (targetm.calls.pretend_outgoing_varargs_named (all->args_so_far))
{
rtx tem;
- tem = targetm.calls.function_incoming_arg (all->args_so_far,
- data->promoted_mode,
- data->passed_type, true);
+ tem = function_incoming_arg (all->args_so_far,
+ data->promoted_mode,
+ data->passed_type, true);
in_regs = tem != NULL;
}
}
@@ -3752,8 +3752,8 @@ assign_parms (tree fndecl)
}
/* Update info on where next arg arrives in registers. */
- targetm.calls.function_arg_advance (all.args_so_far, data.promoted_mode,
- data.passed_type, data.named_arg);
+ function_arg_advance (all.args_so_far, data.promoted_mode,
+ data.passed_type, data.named_arg);
if (POINTER_BOUNDS_TYPE_P (data.passed_type))
bound_no++;
@@ -3949,8 +3949,8 @@ gimplify_parameters (void)
continue;
/* Update info on where next arg arrives in registers. */
- targetm.calls.function_arg_advance (all.args_so_far, data.promoted_mode,
- data.passed_type, data.named_arg);
+ function_arg_advance (all.args_so_far, data.promoted_mode,
+ data.passed_type, data.named_arg);
/* ??? Once upon a time variable_size stuffed parameter list
SAVE_EXPRs (amongst others) onto a pending sizes list. This
@@ -4093,8 +4093,11 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs,
part_size_in_regs = (reg_parm_stack_space == 0 ? partial : 0);
- sizetree
- = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
+ if (type)
+ sizetree = (type_is_empty_record_p (type)
+ ? size_zero_node : size_in_bytes (type));
+ else
+ sizetree = size_int (GET_MODE_SIZE (passed_mode));
where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
boundary = targetm.calls.function_arg_boundary (passed_mode, type);
round_boundary = targetm.calls.function_arg_round_boundary (passed_mode,
@@ -6821,5 +6824,52 @@ make_pass_match_asm_constraints (gcc::context *ctxt)
return new pass_match_asm_constraints (ctxt);
}
+/* Wrapper for targetm.calls.function_arg_advance. */
+
+void
+function_arg_advance (cumulative_args_t ca, machine_mode mode,
+ const_tree type, bool named)
+{
+ if (type && type_is_empty_record_p (type))
+ return;
+
+ targetm.calls.function_arg_advance (ca, mode, type, named);
+}
+
+/* Wrapper for targetm.calls.function_arg. */
+
+rtx
+function_arg (cumulative_args_t ca, machine_mode mode, const_tree type,
+ bool named)
+{
+ if (type && type_is_empty_record_p (type))
+ return NULL;
+
+ return targetm.calls.function_arg (ca, mode, type, named);
+}
+
+/* Wrapper for targetm.calls.function_incoming_arg. */
+
+rtx
+function_incoming_arg (cumulative_args_t ca, machine_mode mode,
+ const_tree type, bool named)
+{
+ if (type && type_is_empty_record_p (type))
+ return NULL;
+
+ return targetm.calls.function_incoming_arg (ca, mode, type, named);
+}
+
+/* Wrapper for targetm.calls.return_in_memory. */
+
+bool
+return_in_memory (const_tree type, const_tree fntype)
+{
+ if (type && type_is_empty_record_p (type))
+ return false;
+
+ return targetm.calls.return_in_memory (type, fntype);
+}
+
#include "gt-function.h"
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 0d610f1..898cee9 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -940,6 +940,8 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
hstate.add_flag (TREE_READONLY (t));
hstate.add_flag (TREE_PUBLIC (t));
}
+ else
+ hstate.add_flag (TYPE_EMPTY_RECORD (t));
hstate.add_flag (TREE_ADDRESSABLE (t));
hstate.add_flag (TREE_THIS_VOLATILE (t));
if (DECL_P (t))
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 2661491..df403bf 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -1002,6 +1002,8 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
compare_values (TREE_READONLY);
compare_values (TREE_PUBLIC);
}
+ else
+ compare_values (TYPE_EMPTY_RECORD);
compare_values (TREE_ADDRESSABLE);
compare_values (TREE_THIS_VOLATILE);
if (DECL_P (t1))
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index cb0f1fd..bb489ff 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -587,6 +587,9 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
if (TYPE_RESTRICT (node))
fputs (" restrict", file);
+ if (TYPE_EMPTY_RECORD (node))
+ fputs (" empty-record", file);
+
if (TYPE_LANG_FLAG_0 (node))
fputs (" type_0", file);
if (TYPE_LANG_FLAG_1 (node))
diff --git a/gcc/target.h b/gcc/target.h
index ffc4d6a..eb01a76 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -104,6 +104,14 @@ extern bool target_default_pointer_address_modes_p (void);
behaviour. */
extern unsigned int get_move_ratio (bool);
+extern void function_arg_advance (cumulative_args_t, machine_mode,
+ const_tree, bool);
+extern rtx function_arg (cumulative_args_t, machine_mode, const_tree,
+ bool);
+extern rtx function_incoming_arg (cumulative_args_t, machine_mode,
+ const_tree, bool);
+extern bool return_in_memory (const_tree, const_tree);
+
struct stdarg_info;
struct spec_info_def;
struct hard_reg_set_container;
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 01d3686..de10ec3 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -1829,9 +1829,12 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
/* Hoist the valist value into a temporary for the moment. */
valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
+ bool empty_record = type_is_empty_record_p (type);
+
/* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
requires greater alignment, we must perform dynamic alignment. */
if (boundary > align
+ && !empty_record
&& !integer_zerop (TYPE_SIZE (type)))
{
t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
@@ -1858,7 +1861,7 @@ 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);
+ type_size = empty_record ? size_zero_node : 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/testsuite/g++.dg/abi/empty12.C b/gcc/testsuite/g++.dg/abi/empty12.C
new file mode 100644
index 0000000..430d57d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty12.C
@@ -0,0 +1,17 @@
+// PR c++/60336
+// { dg-do run }
+// { dg-options "-x c" }
+// { dg-additional-sources "empty12a.c" }
+// { dg-prune-output "command line option" }
+
+#include "empty12.h"
+extern "C" void fun(struct dummy, struct foo);
+
+int main()
+{
+ struct dummy d;
+ struct foo f = { -1, -2, -3, -4, -5 };
+
+ fun(d, f);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty12.h b/gcc/testsuite/g++.dg/abi/empty12.h
new file mode 100644
index 0000000..c61afcd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty12.h
@@ -0,0 +1,9 @@
+struct dummy { };
+struct foo
+{
+ int i1;
+ int i2;
+ int i3;
+ int i4;
+ int i5;
+};
diff --git a/gcc/testsuite/g++.dg/abi/empty12a.c b/gcc/testsuite/g++.dg/abi/empty12a.c
new file mode 100644
index 0000000..34a25ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty12a.c
@@ -0,0 +1,6 @@
+#include "empty12.h"
+void fun(struct dummy d, struct foo f)
+{
+ if (f.i1 != -1)
+ __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/pr60336-1.C b/gcc/testsuite/g++.dg/pr60336-1.C
new file mode 100644
index 0000000..af08638
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr60336-1.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O2 -std=c++11 -fno-pic" }
+// { dg-require-effective-target fpic }
+
+struct dummy { };
+struct true_type { struct dummy i; };
+
+extern true_type y;
+extern void xxx (true_type c);
+
+void
+yyy (void)
+{
+ xxx (y);
+}
+
+// { dg-final { scan-assembler "jmp\[\t \]+\[^\$\]*?_Z3xxx9true_type" { target i?86-*-* x86_64-*-* } } }
diff --git a/gcc/testsuite/g++.dg/pr60336-2.C b/gcc/testsuite/g++.dg/pr60336-2.C
new file mode 100644
index 0000000..7b902e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr60336-2.C
@@ -0,0 +1,28 @@
+// { dg-do run }
+// { dg-options "-O2" }
+
+#include <stdarg.h>
+
+struct dummy { struct{}__attribute__((aligned (4))) a[7]; };
+
+void
+test (struct dummy a, ...)
+{
+ va_list va_arglist;
+ int i;
+
+ va_start (va_arglist, a);
+ i = va_arg (va_arglist, int);
+ if (i != 0x10)
+ __builtin_abort ();
+ va_end (va_arglist);
+}
+
+struct dummy a0;
+
+int
+main ()
+{
+ test (a0, 0x10);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/pr68355.C b/gcc/testsuite/g++.dg/pr68355.C
new file mode 100644
index 0000000..1354fc4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr68355.C
@@ -0,0 +1,24 @@
+// { dg-do compile }
+// { dg-options "-O2 -std=c++11 -fno-pic" }
+// { dg-require-effective-target fpic }
+
+template<typename _Tp, _Tp __v>
+struct integral_constant
+{
+ static constexpr _Tp value = __v;
+ typedef _Tp value_type;
+ typedef integral_constant<_Tp, __v> type;
+ constexpr operator value_type() const { return value; }
+};
+
+typedef integral_constant<bool, true> true_type;
+extern void xxx (true_type c);
+
+void
+yyy (void)
+{
+ true_type y;
+ xxx (y);
+}
+
+// { dg-final { scan-assembler "jmp\[\t \]+\[^\$\]*?_Z3xxx17integral_constantIbLb1EE" { target i?86-*-* x86_64-*-* } } }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 9cc64d9..67bffa4 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1086,6 +1086,9 @@ struct GTY(()) tree_base {
FORCED_LABEL in
LABEL_DECL
+ TYPE_EMPTY_RECORD in
+ all types
+
volatile_flag:
TREE_THIS_VOLATILE in
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index bb5cd49..1634ed6 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -394,6 +394,8 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
if (mode == BLKmode)
size_tree = TYPE_SIZE (TREE_TYPE (exp));
+ else if (type_is_empty_record_p (TREE_TYPE (exp)))
+ bitsize = 0;
else
bitsize = int (GET_MODE_PRECISION (mode));
}
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index 65a1ce3..7b67534 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -112,7 +112,10 @@ unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1);
}
else
- bp_unpack_value (bp, 4);
+ {
+ TYPE_EMPTY_RECORD (expr) = (unsigned) bp_unpack_value (bp, 1);
+ bp_unpack_value (bp, 3);
+ }
TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1);
if (DECL_P (expr))
diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
index d0b7f6d..9b14db8 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -83,7 +83,10 @@ pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
bp_pack_value (bp, TREE_PUBLIC (expr), 1);
}
else
- bp_pack_value (bp, 0, 4);
+ {
+ bp_pack_value (bp, TYPE_EMPTY_RECORD (expr), 1);
+ bp_pack_value (bp, 0, 3);
+ }
bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1);
bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1);
if (DECL_P (expr))
diff --git a/gcc/tree.h b/gcc/tree.h
index cb52deb..569f709 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -766,6 +766,10 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
computed gotos. */
#define FORCED_LABEL(NODE) (LABEL_DECL_CHECK (NODE)->base.side_effects_flag)
+/* Nonzero in a type considered an empty record. */
+#define TYPE_EMPTY_RECORD(NODE) \
+ (TYPE_CHECK (NODE)->base.side_effects_flag)
+
/* Nonzero means this expression is volatile in the C sense:
its address should be of type `volatile WHATEVER *'.
In other words, the declared item is volatile qualified.
@@ -5337,6 +5341,14 @@ type_with_alias_set_p (const_tree t)
return false;
}
+/* 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));
+}
+
extern location_t set_block (location_t loc, tree block);
extern void gt_ggc_mx (tree &);
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 6fc6233..6dafc90 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -379,10 +379,11 @@ ubsan_type_descriptor (tree type, enum ubsan_print_style pstyle)
if (pstyle == UBSAN_PRINT_POINTER)
{
- pp_printf (&pretty_name, "'%s%s%s%s%s%s%s",
+ pp_printf (&pretty_name, "'%s%s%s%s%s%s%s%s",
TYPE_VOLATILE (type2) ? "volatile " : "",
TYPE_READONLY (type2) ? "const " : "",
TYPE_RESTRICT (type2) ? "restrict " : "",
+ TYPE_EMPTY_RECORD (type2) ? "empty-record " : "",
TYPE_ATOMIC (type2) ? "_Atomic " : "",
TREE_CODE (type2) == RECORD_TYPE
? "struct "
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 9185bfd..e9fdbe9 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -6140,10 +6140,10 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
rtx reg;
INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
nargs + 1);
- reg = targetm.calls.function_arg (args_so_far, mode,
- struct_addr, true);
- targetm.calls.function_arg_advance (args_so_far, mode,
- struct_addr, true);
+ reg = function_arg (args_so_far, mode, struct_addr,
+ true);
+ function_arg_advance (args_so_far, mode, struct_addr,
+ true);
if (reg == NULL_RTX)
{
for (; link; link = XEXP (link, 1))
@@ -6164,8 +6164,8 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
machine_mode mode;
t = TYPE_ARG_TYPES (type);
mode = TYPE_MODE (TREE_VALUE (t));
- this_arg = targetm.calls.function_arg (args_so_far, mode,
- TREE_VALUE (t), true);
+ this_arg = function_arg (args_so_far, mode,
+ TREE_VALUE (t), true);
if (this_arg && !REG_P (this_arg))
this_arg = NULL_RTX;
else if (this_arg == NULL_RTX)
@@ -6280,8 +6280,7 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
argtype = build_pointer_type (argtype);
mode = TYPE_MODE (argtype);
}
- reg = targetm.calls.function_arg (args_so_far, mode,
- argtype, true);
+ reg = function_arg (args_so_far, mode, argtype, true);
if (TREE_CODE (argtype) == REFERENCE_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (argtype))
&& reg
@@ -6335,8 +6334,7 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
}
}
}
- targetm.calls.function_arg_advance (args_so_far, mode,
- argtype, true);
+ function_arg_advance (args_so_far, mode, argtype, true);
t = TREE_CHAIN (t);
}
}
--
2.4.3
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-23 20:54 ` H.J. Lu
@ 2015-11-24 3:48 ` Patrick Palka
2015-11-24 6:00 ` H.J. Lu
0 siblings, 1 reply; 14+ messages in thread
From: Patrick Palka @ 2015-11-24 3:48 UTC (permalink / raw)
To: H.J. Lu; +Cc: Richard Biener, Jason Merrill, GCC Patches
[-- Attachment #1: Type: text/plain, Size: 3731 bytes --]
On Mon, Nov 23, 2015 at 3: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?
>
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..
[-- Attachment #2: 0001-zero-cost-structs.patch --]
[-- Type: text/x-patch, Size: 3155 bytes --]
From 8eb52639992ad0f6e5482783604f362bcc04d230 Mon Sep 17 00:00:00 2001
From: Patrick Palka <patrick@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
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-24 3:48 ` Patrick Palka
@ 2015-11-24 6:00 ` H.J. Lu
2015-11-24 6:10 ` Andrew Pinski
2015-11-24 16:31 ` Patrick Palka
0 siblings, 2 replies; 14+ messages in thread
From: H.J. Lu @ 2015-11-24 6:00 UTC (permalink / raw)
To: Patrick Palka; +Cc: Richard Biener, Jason Merrill, GCC Patches
On Mon, Nov 23, 2015 at 7:22 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> On Mon, Nov 23, 2015 at 3: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?
>>
>
> 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..
I don't think it works for C++ class. empty_record_or_union_type_p
missed:
for (binfo = TYPE_BINFO (type), i = 0;
BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
return false;
Does it work with variable argument list? Did you run GCC
testsuite for both i686 and x86-64?
--
H.J.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-24 6:00 ` H.J. Lu
@ 2015-11-24 6:10 ` Andrew Pinski
2015-11-24 12:52 ` H.J. Lu
2015-11-24 16:31 ` Patrick Palka
1 sibling, 1 reply; 14+ messages in thread
From: Andrew Pinski @ 2015-11-24 6:10 UTC (permalink / raw)
To: H.J. Lu; +Cc: Patrick Palka, Richard Biener, Jason Merrill, GCC Patches
On Mon, Nov 23, 2015 at 9:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Nov 23, 2015 at 7:22 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
>> On Mon, Nov 23, 2015 at 3: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?
>>>
>>
>> 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..
>
> I don't think it works for C++ class. empty_record_or_union_type_p
> missed:
>
> for (binfo = TYPE_BINFO (type), i = 0;
> BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
> if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
> return false;
This above should not be needed as TYPE_FIELDS should include one
already. Or do you have prove it does not?
Thanks,
Andrew
>
> Does it work with variable argument list? Did you run GCC
> testsuite for both i686 and x86-64?
>
>
> --
> H.J.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-24 6:10 ` Andrew Pinski
@ 2015-11-24 12:52 ` H.J. Lu
0 siblings, 0 replies; 14+ messages in thread
From: H.J. Lu @ 2015-11-24 12:52 UTC (permalink / raw)
To: Andrew Pinski; +Cc: Patrick Palka, Richard Biener, Jason Merrill, GCC Patches
On Mon, Nov 23, 2015 at 10:00 PM, Andrew Pinski <pinskia@gmail.com> wrote:
> On Mon, Nov 23, 2015 at 9:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Mon, Nov 23, 2015 at 7:22 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
>>> On Mon, Nov 23, 2015 at 3: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?
>>>>
>>>
>>> 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..
>>
>> I don't think it works for C++ class. empty_record_or_union_type_p
>> missed:
>>
>> for (binfo = TYPE_BINFO (type), i = 0;
>> BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
>> if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
>> return false;
>
> This above should not be needed as TYPE_FIELDS should include one
> already. Or do you have prove it does not?
You can remove the above from
---
/* Returns true if TYPE contains no actual data, just various
possible combinations of empty classes and possibly a vptr. */
bool
is_really_empty_class (tree type)
{
if (CLASS_TYPE_P (type))
{
tree field;
tree binfo;
tree base_binfo;
int i;
/* CLASSTYPE_EMPTY_P isn't set properly until the class is actually laid
out, but we'd like to be able to check this before then. */
if (COMPLETE_TYPE_P (type) && is_empty_class (type))
return true;
for (binfo = TYPE_BINFO (type), i = 0;
BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
return false;
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL
&& !DECL_ARTIFICIAL (field)
&& !is_really_empty_class (TREE_TYPE (field)))
return false;
return true;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
return is_really_empty_class (TREE_TYPE (type));
return false;
}
---
and see what happens.
--
H.J.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-24 6:00 ` H.J. Lu
2015-11-24 6:10 ` Andrew Pinski
@ 2015-11-24 16:31 ` Patrick Palka
2015-11-24 16:59 ` H.J. Lu
1 sibling, 1 reply; 14+ messages in thread
From: Patrick Palka @ 2015-11-24 16:31 UTC (permalink / raw)
To: H.J. Lu; +Cc: Richard Biener, Jason Merrill, GCC Patches
On Tue, Nov 24, 2015 at 12:53 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Nov 23, 2015 at 7:22 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
>> On Mon, Nov 23, 2015 at 3: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?
>>>
>>
>> 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..
>
> I don't think it works for C++ class. empty_record_or_union_type_p
> missed:
>
> for (binfo = TYPE_BINFO (type), i = 0;
> BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
> if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
> return false;
Yeah, your TYPE_EMPTY_RECORD flag covers more instances of empty
structs than this predicate does.
>
> Does it work with variable argument list? Did you run GCC
> testsuite for both i686 and x86-64?
Hmm, I don't think it works with variable argument lists, at least not
perfectly. And I just finished running the testsuite on x86-64 and
observed a failure in struct-layout-1.exp which makes no sense to me.
Now I remember why I didn't pursue this change any further.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
2015-11-24 16:31 ` Patrick Palka
@ 2015-11-24 16:59 ` H.J. Lu
0 siblings, 0 replies; 14+ messages in thread
From: H.J. Lu @ 2015-11-24 16:59 UTC (permalink / raw)
To: Patrick Palka; +Cc: Richard Biener, Jason Merrill, GCC Patches
On Tue, Nov 24, 2015 at 8:28 AM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> On Tue, Nov 24, 2015 at 12:53 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Mon, Nov 23, 2015 at 7:22 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
>>> On Mon, Nov 23, 2015 at 3: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?
>>>>
>>>
>>> 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..
>>
>> I don't think it works for C++ class. empty_record_or_union_type_p
>> missed:
>>
>> for (binfo = TYPE_BINFO (type), i = 0;
>> BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
>> if (!is_really_empty_class (BINFO_TYPE (base_binfo)))
>> return false;
>
> Yeah, your TYPE_EMPTY_RECORD flag covers more instances of empty
> structs than this predicate does.
>
>>
>> Does it work with variable argument list? Did you run GCC
>> testsuite for both i686 and x86-64?
>
> Hmm, I don't think it works with variable argument lists, at least not
> perfectly. And I just finished running the testsuite on x86-64 and
> observed a failure in struct-layout-1.exp which makes no sense to me.
> Now I remember why I didn't pursue this change any further.
I tried a similar approach and got quite a few C++ failures in
gcc testsuite. There were more failures on i686 than x86-64.
See
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60336
for more details. My current patch passes all tests on i686 and
x86-64.
--
H.J.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2015-11-24 16:35 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-17 11:01 [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class H.J. Lu
2015-11-17 12:22 ` Richard Biener
2015-11-20 18:52 ` H.J. Lu
2015-11-20 22:17 ` Jason Merrill
2015-11-20 22:24 ` Jason Merrill
2015-11-20 23:47 ` H.J. Lu
2015-11-23 9:59 ` Richard Biener
2015-11-23 20:54 ` H.J. Lu
2015-11-24 3:48 ` Patrick Palka
2015-11-24 6:00 ` H.J. Lu
2015-11-24 6:10 ` Andrew Pinski
2015-11-24 12:52 ` H.J. Lu
2015-11-24 16:31 ` Patrick Palka
2015-11-24 16:59 ` H.J. Lu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).