From 8eb52639992ad0f6e5482783604f362bcc04d230 Mon Sep 17 00:00:00 2001 From: Patrick Palka 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