On Tue, Aug 4, 2020 at 12:35 AM Richard Biener <rguent...@suse.de> wrote: > > On Mon, 3 Aug 2020, Qing Zhao wrote: > > > Hi, Uros, > > > > Thanks a lot for your review on X86 parts. > > > > Hi, Richard, > > > > Could you please take a look at the middle-end part to see whether the > > rewritten addressed your previous concern? > > I have a few comments below - I'm not sure I'm qualified to fully > review the rest though. > > > Thanks a lot. > > > > Qing > > > > > > > On Jul 31, 2020, at 12:57 PM, Uros Bizjak <ubiz...@gmail.com> wrote: > > > > > > > > > 22:05, tor., 28. jul. 2020 je oseba Qing Zhao <qing.z...@oracle.com > > > <mailto:qing.z...@oracle.com>> napisala: > > > > > > > > > > > > Richard and Uros, > > > > > > > > Could you please review the change that H.J and I rewrote based on your > > > > comments in the previous round of discussion? > > > > > > > > This patch is a nice security enhancement for GCC that has been > > > > requested by security people for quite some time. > > > > > > > > Thanks a lot for your time. > > > > > > I'll be away from the keyboard for the next week, but the patch needs a > > > middle end approval first. > > > > > > That said, x86 parts looks OK. > > > > > > > > > > > Uros. > > > > Qing > > > > > > > > > On Jul 14, 2020, at 9:45 AM, Qing Zhao via Gcc-patches > > > > > <gcc-patches@gcc.gnu.org <mailto:gcc-patches@gcc.gnu.org>> wrote: > > > > > > > > > > Hi, Gcc team, > > > > > > > > > > This patch is a follow-up on the previous patch and corresponding > > > > > discussion: > > > > > https://gcc.gnu.org/pipermail/gcc-patches/2020-May/545101.html > > > > > <https://gcc.gnu.org/pipermail/gcc-patches/2020-May/545101.html> > > > > > <https://gcc.gnu.org/pipermail/gcc-patches/2020-May/545101.html > > > > > <https://gcc.gnu.org/pipermail/gcc-patches/2020-May/545101.html>> > > > > > > > > > > From the previous round of discussion, the major issues raised were: > > > > > > > > > > A. should be rewritten by using regsets infrastructure. > > > > > B. Put the patch into middle-end instead of x86 backend. > > > > > > > > > > This new patch is rewritten based on the above 2 comments. The major > > > > > changes compared to the previous patch are: > > > > > > > > > > 1. Change the names of the option and attribute from > > > > > -mzero-caller-saved-regs=[skip|used-gpr|all-gpr|used|all] and > > > > > zero_caller_saved_regs("skip|used-gpr|all-gpr||used|all”) > > > > > to: > > > > > -fzero-call-used-regs=[skip|used-gpr|all-gpr|used|all] and > > > > > zero_call_used_regs("skip|used-gpr|all-gpr||used|all”) > > > > > Add the new option and new attribute in general. > > > > > 2. The main code generation part is moved from i386 backend to > > > > > middle-end; > > > > > 3. Add 4 target-hooks; > > > > > 4. Implement these 4 target-hooks on i386 backend. > > > > > 5. On a target that does not implement the target hook, issue error > > > > > for the new option, issue warning for the new attribute. > > > > > > > > > > The patch is as following: > > > > > > > > > > [PATCH] Add -fzero-call-used-regs=[skip|used-gpr|all-gpr|used|all] > > > > > command-line option and > > > > > zero_call_used_regs("skip|used-gpr|all-gpr||used|all") function > > > > > attribue: > > > > > > > > > > 1. -fzero-call-used-regs=skip and zero_call_used_regs("skip") > > > > > > > > > > Don't zero call-used registers upon function return. > > Does a return via EH unwinding also constitute a function return? I > think you may want to have a finally handler or support in the unwinder > for this? Then there's abnormal return via longjmp & friends, I guess > there's nothing that can be done there besides patching glibc?
Abnormal returns, like EH unwinding and longjmp, aren't covered by this patch. Only normal returns are covered. > In general I am missing reasoning as why to use -fzero-call-used-regs= > in the documentation, that is, what is the thread model and what are > the guarantees? Is there any point zeroing registers when spill slots > are left populated with stale register contents? How do I (and why > would I want to?) ensure that there's no information leak from the > implementation of 'foo' to their callers? Do I need to compile all > of 'foo' and functions called from 'foo' with -fzero-call-used-regs= > or is it enough to annotate API boundaries I want to proptect with > zero_call_used_regs("...")? > > Again - what's the intended use (and how does it fulful anything useful > for that case)? > > > > > > 2. -fzero-call-used-regs=used-gpr and zero_call_used_regs("used-gpr") > > > > > > > > > > Zero used call-used general purpose registers upon function return. > > > > > > > > > > 3. -fzero-call-used-regs=all-gpr and zero_call_used_regs("all-gpr") > > > > > > > > > > Zero all call-used general purpose registers upon function return. > > > > > > > > > > 4. -fzero-call-used-regs=used and zero_call_used_regs("used") > > > > > > > > > > Zero used call-used registers upon function return. > > > > > > > > > > 5. -fzero-call-used-regs=all and zero_call_used_regs("all") > > > > > > > > > > Zero all call-used registers upon function return. > > > > > > > > > > The feature is implemented in middle-end. But currently is only valid > > > > > on X86. > > > > > > > > > > Tested on x86-64 and aarch64 with bootstrapping GCC trunk, making > > > > > -fzero-call-used-regs=used-gpr, -fzero-call-used-regs=all-gpr > > > > > -fzero-call-used-regs=used, and -fzero-call-used-regs=all enabled > > > > > by default on x86-64. > > > > > > > > > > Please take a look and let me know any more comment? > > > > > > > > > > thanks. > > > > > > > > > > Qing > > > > > > > > > > > > > > > ==================================== > > > > > > > > > > gcc/ChangeLog: > > > > > > > > > > 2020-07-13 qing zhao <qing.z...@oracle.com > > > > > <mailto:qing.z...@oracle.com> <mailto:qing.z...@oracle.com > > > > > <mailto:qing.z...@oracle.com>>> > > > > > 2020-07-13 H.J. Lu <hjl.to...@gmail.com <mailto:hjl.to...@gmail.com> > > > > > <mailto:hjl.to...@gmail.com <mailto:hjl.to...@gmail.com>>> > > > > > > > > > > * common.opt: Add new option -fzero-call-used-regs. > > > > > * config/i386/i386.c (ix86_zero_call_used_regno_p): New > > > > > function. > > > > > (ix86_zero_call_used_regno_mode): Likewise. > > > > > (ix86_zero_all_vector_registers): Likewise. > > > > > (ix86_expand_prologue): Replace gen_prologue_use with > > > > > gen_pro_epilogue_use. > > > > > (TARGET_ZERO_CALL_USED_REGNO_P): Define. > > > > > (TARGET_ZERO_CALL_USED_REGNO_MODE): Define. > > > > > (TARGET_PRO_EPILOGUE_USE): Define. > > > > > (TARGET_ZERO_ALL_VECTOR_REGISTERS): Define. > > > > > * config/i386/i386.md: Replace UNSPECV_PROLOGUE_USE > > > > > with UNSPECV_PRO_EPILOGUE_USE. > > > > > * coretypes.h (enum zero_call_used_regs): New type. > > > > > * doc/extend.texi: Document the new zero_call_used_regs > > > > > attribute. > > > > > * doc/invoke.texi: Document the new -fzero-call-used-regs > > > > > option. > > > > > * doc/tm.texi: Regenerate. > > > > > * doc/tm.texi.in <http://tm.texi.in/> > > > > > (TARGET_ZERO_CALL_USED_REGNO_P): New hook. > > > > > (TARGET_ZERO_CALL_USED_REGNO_MODE): Likewise. > > > > > (TARGET_PRO_EPILOGUE_USE): Likewise. > > > > > (TARGET_ZERO_ALL_VECTOR_REGISTERS): Likewise. > > > > > * function.c (is_live_reg_at_exit): New function. > > > > > (gen_call_used_regs_seq): Likewise. > > > > > (make_epilogue_seq): Call gen_call_used_regs_seq. > > > > > * function.h (is_live_reg_at_exit): Declare. > > > > > * target.def (zero_call_used_regno_p): New hook. > > > > > (zero_call_used_regno_mode): Likewise. > > > > > (pro_epilogue_use): Likewise. > > > > > (zero_all_vector_registers): Likewise. > > > > > * targhooks.c (default_zero_call_used_regno_p): New function. > > > > > (default_zero_call_used_regno_mode): Likewise. > > > > > * targhooks.h (default_zero_call_used_regno_p): Declare. > > > > > (default_zero_call_used_regno_mode): Declare. > > > > > * toplev.c (process_options): Issue errors when > > > > > -fzero-call-used-regs > > > > > is used on targets that do not support it. > > > > > * tree-core.h (struct tree_decl_with_vis): New field > > > > > zero_call_used_regs_type. > > > > > * tree.h (DECL_ZERO_CALL_USED_REGS): New macro. > > > > > > > > > > gcc/c-family/ChangeLog: > > > > > > > > > > 2020-07-13 qing zhao <qing.z...@oracle.com > > > > > <mailto:qing.z...@oracle.com> <mailto:qing.z...@oracle.com > > > > > <mailto:qing.z...@oracle.com>>> > > > > > 2020-07-13 H.J. Lu <hjl.to...@gmail.com <mailto:hjl.to...@gmail.com> > > > > > <mailto:hjl.to...@gmail.com <mailto:hjl.to...@gmail.com>>> > > > > > > > > > > * c-attribs.c (c_common_attribute_table): Add new attribute > > > > > zero_call_used_regs. > > > > > (handle_zero_call_used_regs_attribute): New function. > > > > > > > > > > gcc/c/ChangeLog: > > > > > > > > > > 2020-07-13 qing zhao <qing.z...@oracle.com > > > > > <mailto:qing.z...@oracle.com> <mailto:qing.z...@oracle.com > > > > > <mailto:qing.z...@oracle.com>>> > > > > > 2020-07-13 H.J. Lu <hjl.to...@gmail.com <mailto:hjl.to...@gmail.com> > > > > > <mailto:hjl.to...@gmail.com <mailto:hjl.to...@gmail.com>>> > > > > > > > > > > * c-decl.c (merge_decls): Merge zero_call_used_regs_type. > > > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > > > 2020-07-13 qing zhao <qing.z...@oracle.com > > > > > <mailto:qing.z...@oracle.com> <mailto:qing.z...@oracle.com > > > > > <mailto:qing.z...@oracle.com>>> > > > > > 2020-07-13 H.J. Lu <hjl.to...@gmail.com <mailto:hjl.to...@gmail.com> > > > > > <mailto:hjl.to...@gmail.com <mailto:hjl.to...@gmail.com>>> > > > > > > > > > > * c-c++-common/zero-scratch-regs-1.c: New test. > > > > > * c-c++-common/zero-scratch-regs-2.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-1.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-10.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-11.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-12.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-13.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-14.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-15.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-16.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-17.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-18.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-19.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-2.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-20.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-21.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-22.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-23.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-3.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-4.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-5.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-6.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-7.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-8.c: Likewise. > > > > > * gcc.target/i386/zero-scratch-regs-9.c: Likewise. > > > > > > > > > > --- > > > > > gcc/c-family/c-attribs.c | 68 ++++++++++ > > > > > gcc/c/c-decl.c | 4 + > > > > > gcc/common.opt | 23 ++++ > > > > > gcc/config/i386/i386.c | 58 ++++++++- > > > > > gcc/config/i386/i386.md | 6 +- > > > > > gcc/coretypes.h | 10 ++ > > > > > gcc/doc/extend.texi | 11 ++ > > > > > gcc/doc/invoke.texi | 13 +- > > > > > gcc/doc/tm.texi | 27 ++++ > > > > > gcc/doc/tm.texi.in <http://tm.texi.in/> > > > > > | 8 ++ > > > > > gcc/function.c | 145 > > > > > +++++++++++++++++++++ > > > > > gcc/function.h | 2 + > > > > > gcc/target.def | 33 +++++ > > > > > gcc/targhooks.c | 17 +++ > > > > > gcc/targhooks.h | 3 + > > > > > gcc/testsuite/c-c++-common/zero-scratch-regs-1.c | 3 + > > > > > gcc/testsuite/c-c++-common/zero-scratch-regs-2.c | 4 + > > > > > .../gcc.target/i386/zero-scratch-regs-1.c | 12 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-10.c | 21 +++ > > > > > .../gcc.target/i386/zero-scratch-regs-11.c | 39 ++++++ > > > > > .../gcc.target/i386/zero-scratch-regs-12.c | 39 ++++++ > > > > > .../gcc.target/i386/zero-scratch-regs-13.c | 21 +++ > > > > > .../gcc.target/i386/zero-scratch-regs-14.c | 19 +++ > > > > > .../gcc.target/i386/zero-scratch-regs-15.c | 14 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-16.c | 14 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-17.c | 13 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-18.c | 13 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-19.c | 12 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-2.c | 19 +++ > > > > > .../gcc.target/i386/zero-scratch-regs-20.c | 23 ++++ > > > > > .../gcc.target/i386/zero-scratch-regs-21.c | 14 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-22.c | 19 +++ > > > > > .../gcc.target/i386/zero-scratch-regs-23.c | 19 +++ > > > > > .../gcc.target/i386/zero-scratch-regs-3.c | 12 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-4.c | 14 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-5.c | 20 +++ > > > > > .../gcc.target/i386/zero-scratch-regs-6.c | 14 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-7.c | 13 ++ > > > > > .../gcc.target/i386/zero-scratch-regs-8.c | 19 +++ > > > > > .../gcc.target/i386/zero-scratch-regs-9.c | 15 +++ > > > > > gcc/toplev.c | 9 ++ > > > > > gcc/tree-core.h | 6 +- > > > > > gcc/tree.h | 5 + > > > > > 43 files changed, 866 insertions(+), 7 deletions(-) > > > > > create mode 100644 gcc/testsuite/c-c++-common/zero-scratch-regs-1.c > > > > > create mode 100644 gcc/testsuite/c-c++-common/zero-scratch-regs-2.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-1.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-10.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-11.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-12.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-13.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-14.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-15.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-16.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-17.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-18.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-19.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-2.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-20.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-21.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-22.c > > > > > create mode 100644 > > > > > gcc/testsuite/gcc.target/i386/zero-scratch-regs-23.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-3.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-4.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-5.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-6.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-7.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-8.c > > > > > create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-9.c > > > > > > > > > > diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c > > > > > index 3721483..cc93d6f 100644 > > > > > --- a/gcc/c-family/c-attribs.c > > > > > +++ b/gcc/c-family/c-attribs.c > > > > > @@ -136,6 +136,8 @@ static tree handle_target_clones_attribute (tree > > > > > *, tree, tree, int, bool *); > > > > > static tree handle_optimize_attribute (tree *, tree, tree, int, bool > > > > > *); > > > > > static tree ignore_attribute (tree *, tree, tree, int, bool *); > > > > > static tree handle_no_split_stack_attribute (tree *, tree, tree, int, > > > > > bool *); > > > > > +static tree handle_zero_call_used_regs_attribute (tree *, tree, > > > > > tree, int, > > > > > + bool *); > > > > > static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); > > > > > static tree handle_warn_unused_attribute (tree *, tree, tree, int, > > > > > bool *); > > > > > static tree handle_returns_nonnull_attribute (tree *, tree, tree, > > > > > int, bool *); > > > > > @@ -434,6 +436,9 @@ const struct attribute_spec > > > > > c_common_attribute_table[] = > > > > > ignore_attribute, NULL }, > > > > > { "no_split_stack", 0, 0, true, false, false, false, > > > > > handle_no_split_stack_attribute, NULL }, > > > > > + { "zero_call_used_regs", 1, 1, true, false, false, false, > > > > > + handle_zero_call_used_regs_attribute, > > > > > NULL }, > > > > > + > > > > > /* For internal use (marking of builtins and runtime functions) only. > > > > > The name contains space to prevent its usage in source code. */ > > > > > { "fn spec", 1, 1, false, true, true, false, > > > > > @@ -4506,6 +4511,69 @@ handle_no_split_stack_attribute (tree *node, > > > > > tree name, > > > > > return NULL_TREE; > > > > > } > > > > > > > > > > +/* Handle a "zero_call_used_regs" attribute; arguments as in > > > > > + struct attribute_spec.handler. */ > > > > > + > > > > > +static tree > > > > > +handle_zero_call_used_regs_attribute (tree *node, tree name, tree > > > > > args, > > > > > + int ARG_UNUSED (flags), > > > > > + bool *no_add_attris) > > > > > +{ > > > > > + tree decl = *node; > > > > > + tree id = TREE_VALUE (args); > > > > > + enum zero_call_used_regs zero_call_used_regs_type = > > > > > zero_call_used_regs_unset; > > > > > + > > > > > + if (TREE_CODE (decl) != FUNCTION_DECL) > > > > > + { > > > > > + error_at (DECL_SOURCE_LOCATION (decl), > > > > > + "%qE attribute applies only to functions", name); > > > > > + *no_add_attris = true; > > > > > + return NULL_TREE; > > > > > + } > > > > > + else if (DECL_INITIAL (decl)) > > > > > + { > > > > > + error_at (DECL_SOURCE_LOCATION (decl), > > > > > + "cannot set %qE attribute after definition", name); > > Why's that? > > > > > > + *no_add_attris = true; > > > > > + return NULL_TREE; > > > > > + } > > > > > + > > > > > + if (TREE_CODE (id) != STRING_CST) > > > > > + { > > > > > + error ("attribute %qE arguments not a string", name); > > > > > + *no_add_attris = true; > > > > > + return NULL_TREE; > > > > > + } > > > > > + > > > > > + if (!targetm.calls.pro_epilogue_use) > > > > > + { > > > > > + warning (OPT_Wattributes, "%qE attribute directive ignored", > > > > > name); > > > > > + return NULL_TREE; > > > > > + } > > > > > + > > > > > + if (strcmp (TREE_STRING_POINTER (id), "skip") == 0) > > > > > + zero_call_used_regs_type = zero_call_used_regs_skip; > > > > > + else if (strcmp (TREE_STRING_POINTER (id), "used-gpr") == 0) > > > > > + zero_call_used_regs_type = zero_call_used_regs_used_gpr; > > > > > + else if (strcmp (TREE_STRING_POINTER (id), "all-gpr") == 0) > > > > > + zero_call_used_regs_type = zero_call_used_regs_all_gpr; > > > > > + else if (strcmp (TREE_STRING_POINTER (id), "used") == 0) > > > > > + zero_call_used_regs_type = zero_call_used_regs_used; > > > > > + else if (strcmp (TREE_STRING_POINTER (id), "all") == 0) > > > > > + zero_call_used_regs_type = zero_call_used_regs_all; > > > > > + else > > > > > + { > > > > > + error ("attribute %qE argument must be one of %qs, %qs, %qs, > > > > > %qs, or %qs", > > > > > + name, "skip", "used-gpr", "all-gpr", "used", "all"); > > > > > + *no_add_attris = true; > > > > > + return NULL_TREE; > > > > > + } > > > > > + > > > > > + DECL_ZERO_CALL_USED_REGS (decl) = zero_call_used_regs_type; > > > > > + > > > > > + return NULL_TREE; > > > > > +} > > > > > + > > > > > /* Handle a "returns_nonnull" attribute; arguments as in > > > > > struct attribute_spec.handler. */ > > > > > > > > > > diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c > > > > > index 81bd2ee..ded1880 100644 > > > > > --- a/gcc/c/c-decl.c > > > > > +++ b/gcc/c/c-decl.c > > > > > @@ -2681,6 +2681,10 @@ merge_decls (tree newdecl, tree olddecl, tree > > > > > newtype, tree oldtype) > > > > > DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl); > > > > > } > > > > > > > > > > + /* Merge the zero_call_used_regs_type information. */ > > > > > + if (TREE_CODE (newdecl) == FUNCTION_DECL) > > > > > + DECL_ZERO_CALL_USED_REGS (newdecl) = DECL_ZERO_CALL_USED_REGS > > > > > (olddecl); > > > > > + > > If you need this (see below) then likely cp/* needs similar adjustment > so do other places in the middle-end (function cloning, etc) > > > > > > /* Merge the storage class information. */ > > > > > merge_weak (newdecl, olddecl); > > > > > > > > > > diff --git a/gcc/common.opt b/gcc/common.opt > > > > > index df8af36..19900f9 100644 > > > > > --- a/gcc/common.opt > > > > > +++ b/gcc/common.opt > > > > > @@ -3083,6 +3083,29 @@ fzero-initialized-in-bss > > > > > Common Report Var(flag_zero_initialized_in_bss) Init(1) > > > > > Put zero initialized data in the bss section. > > > > > > > > > > +fzero-call-used-regs= > > > > > +Common Report RejectNegative Joined Enum(zero_call_used_regs) > > > > > Var(flag_zero_call_used_regs) Init(zero_call_used_regs_skip) > > > > > +Clear call-used registers upon function return. > > > > > + > > > > > +Enum > > > > > +Name(zero_call_used_regs) Type(enum zero_call_used_regs) > > > > > +Known choices of clearing call-used registers upon function return > > > > > (for use with the -fzero-call-used-regs= option): > > > > > + > > > > > +EnumValue > > > > > +Enum(zero_call_used_regs) String(skip) > > > > > Value(zero_call_used_regs_skip) > > > > > + > > > > > +EnumValue > > > > > +Enum(zero_call_used_regs) String(used-gpr) > > > > > Value(zero_call_used_regs_used_gpr) > > > > > + > > > > > +EnumValue > > > > > +Enum(zero_call_used_regs) String(all-gpr) > > > > > Value(zero_call_used_regs_all_gpr) > > > > > + > > > > > +EnumValue > > > > > +Enum(zero_call_used_regs) String(used) > > > > > Value(zero_call_used_regs_used) > > > > > + > > > > > +EnumValue > > > > > +Enum(zero_call_used_regs) String(all) Value(zero_call_used_regs_all) > > > > > + > > > > > g > > > > > Common Driver RejectNegative JoinedOrMissing > > > > > Generate debug information in default format. > > > > > diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c > > > > > index 5c373c0..fd1aa9c 100644 > > > > > --- a/gcc/config/i386/i386.c > > > > > +++ b/gcc/config/i386/i386.c > > > > > @@ -3551,6 +3551,48 @@ ix86_function_value_regno_p (const unsigned > > > > > int regno) > > > > > return false; > > > > > } > > > > > > > > > > +/* TARGET_ZERO_CALL_USED_REGNO_P. */ > > > > > + > > > > > +static bool > > > > > +ix86_zero_call_used_regno_p (const unsigned int regno, > > > > > + bool gpr_only) > > > > > +{ > > > > > + return GENERAL_REGNO_P (regno) || (!gpr_only && SSE_REGNO_P > > > > > (regno)); > > > > > +} > > > > > + > > > > > +/* TARGET_ZERO_CALL_USED_REGNO_MODE. */ > > > > > + > > > > > +static machine_mode > > > > > +ix86_zero_call_used_regno_mode (const unsigned int regno, > > > > > machine_mode) > > > > > +{ > > > > > + /* NB: We only need to zero the lower 32 bits for integer registers > > > > > + and the lower 128 bits for vector registers since destination > > > > > are > > > > > + zero-extended to the full register width. */ > > > > > + return GENERAL_REGNO_P (regno) ? SImode : V4SFmode; > > > > > +} > > > > > + > > > > > +/* TARGET_ZERO_ALL_VECTOR_REGISTERS. */ > > > > > + > > > > > +static rtx > > > > > +ix86_zero_all_vector_registers (bool used_only) > > > > > +{ > > > > > + if (!TARGET_AVX) > > > > > + return NULL; > > > > > + > > > > > + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; > > > > > regno++) > > > > > + if ((IN_RANGE (regno, FIRST_SSE_REG, LAST_SSE_REG) > > > > > + || (TARGET_64BIT > > > > > + && (REX_SSE_REGNO_P (regno) > > > > > + || (TARGET_AVX512F && EXT_REX_SSE_REGNO_P (regno))))) > > > > > + && (!this_target_hard_regs->x_call_used_regs[regno] > > > > > + || fixed_regs[regno] > > > > > + || is_live_reg_at_exit (regno) > > > > > + || (used_only && !df_regs_ever_live_p (regno)))) > > > > > + return NULL; > > > > > + > > > > > + return gen_avx_vzeroall (); > > > > > +} > > > > > + > > > > > /* Define how to find the value returned by a function. > > > > > VALTYPE is the data type of the value (as a tree). > > > > > If the precise function being called is known, FUNC is its > > > > > FUNCTION_DECL; > > > > > @@ -8513,7 +8555,7 @@ ix86_expand_prologue (void) > > > > > insn = emit_insn (gen_set_got (pic)); > > > > > RTX_FRAME_RELATED_P (insn) = 1; > > > > > add_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL_RTX); > > > > > - emit_insn (gen_prologue_use (pic)); > > > > > + emit_insn (gen_pro_epilogue_use (pic)); > > > > > /* Deleting already emmitted SET_GOT if exist and allocated to > > > > > REAL_PIC_OFFSET_TABLE_REGNUM. */ > > > > > ix86_elim_entry_set_got (pic); > > > > > @@ -8542,7 +8584,7 @@ ix86_expand_prologue (void) > > > > > Further, prevent alloca modifications to the stack pointer from > > > > > being > > > > > combined with prologue modifications. */ > > > > > if (TARGET_SEH) > > > > > - emit_insn (gen_prologue_use (stack_pointer_rtx)); > > > > > + emit_insn (gen_pro_epilogue_use (stack_pointer_rtx)); > > > > > } > > > > > > > > > > /* Emit code to restore REG using a POP insn. */ > > > > > @@ -23319,6 +23361,18 @@ ix86_run_selftests (void) > > > > > #undef TARGET_FUNCTION_VALUE_REGNO_P > > > > > #define TARGET_FUNCTION_VALUE_REGNO_P ix86_function_value_regno_p > > > > > > > > > > +#undef TARGET_ZERO_CALL_USED_REGNO_P > > > > > +#define TARGET_ZERO_CALL_USED_REGNO_P ix86_zero_call_used_regno_p > > > > > + > > > > > +#undef TARGET_ZERO_CALL_USED_REGNO_MODE > > > > > +#define TARGET_ZERO_CALL_USED_REGNO_MODE > > > > > ix86_zero_call_used_regno_mode > > > > > + > > > > > +#undef TARGET_PRO_EPILOGUE_USE > > > > > +#define TARGET_PRO_EPILOGUE_USE gen_pro_epilogue_use > > > > > + > > > > > +#undef TARGET_ZERO_ALL_VECTOR_REGISTERS > > > > > +#define TARGET_ZERO_ALL_VECTOR_REGISTERS > > > > > ix86_zero_all_vector_registers > > > > > + > > > > > #undef TARGET_PROMOTE_FUNCTION_MODE > > > > > #define TARGET_PROMOTE_FUNCTION_MODE ix86_promote_function_mode > > > > > > > > > > diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md > > > > > index d0ecd9e..e7df59f 100644 > > > > > --- a/gcc/config/i386/i386.md > > > > > +++ b/gcc/config/i386/i386.md > > > > > @@ -194,7 +194,7 @@ > > > > > UNSPECV_STACK_PROBE > > > > > UNSPECV_PROBE_STACK_RANGE > > > > > UNSPECV_ALIGN > > > > > - UNSPECV_PROLOGUE_USE > > > > > + UNSPECV_PRO_EPILOGUE_USE > > > > > UNSPECV_SPLIT_STACK_RETURN > > > > > UNSPECV_CLD > > > > > UNSPECV_NOPS > > > > > @@ -13525,8 +13525,8 @@ > > > > > > > > > > ;; As USE insns aren't meaningful after reload, this is used instead > > > > > ;; to prevent deleting instructions setting registers for PIC code > > > > > -(define_insn "prologue_use" > > > > > - [(unspec_volatile [(match_operand 0)] UNSPECV_PROLOGUE_USE)] > > > > > +(define_insn "pro_epilogue_use" > > > > > + [(unspec_volatile [(match_operand 0)] UNSPECV_PRO_EPILOGUE_USE)] > > > > > "" > > > > > "" > > > > > [(set_attr "length" "0")]) > > > > > diff --git a/gcc/coretypes.h b/gcc/coretypes.h > > > > > index 6b6cfcd..e56d6ec 100644 > > > > > --- a/gcc/coretypes.h > > > > > +++ b/gcc/coretypes.h > > > > > @@ -418,6 +418,16 @@ enum symbol_visibility > > > > > VISIBILITY_INTERNAL > > > > > }; > > > > > > > > > > +/* Zero call-used registers type. */ > > > > > +enum zero_call_used_regs { > > > > > + zero_call_used_regs_unset = 0, > > > > > + zero_call_used_regs_skip, > > > > > + zero_call_used_regs_used_gpr, > > > > > + zero_call_used_regs_all_gpr, > > > > > + zero_call_used_regs_used, > > > > > + zero_call_used_regs_all > > > > > +}; > > > > > + > > > > > /* enums used by the targetm.excess_precision hook. */ > > > > > > > > > > enum flt_eval_method > > > > > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > > > > > index c800b74..b32c55f 100644 > > > > > --- a/gcc/doc/extend.texi > > > > > +++ b/gcc/doc/extend.texi > > > > > @@ -3984,6 +3984,17 @@ performing a link with relocatable output > > > > > (i.e.@: @code{ld -r}) on them. > > > > > A declaration to which @code{weakref} is attached and that is > > > > > associated > > > > > with a named @code{target} must be @code{static}. > > > > > > > > > > +@item zero_call_used_regs ("@var{choice}") > > > > > +@cindex @code{zero_call_used_regs} function attribute > > > > > +The @code{zero_call_used_regs} attribute causes the compiler to zero > > > > > +call-used registers at function return according to @var{choice}. > > > > > +@samp{skip} doesn't zero call-used registers. @samp{used-gpr} zeros > > > > > +call-used general purpose registers which are used in funciton. > > > > > +@samp{all-gpr} zeros all call-used general purpose registers. > > > > > +@samp{used} zeros call-used registers which are used in function. > > > > > +@samp{all} zeros all call-used registers. The default for the > > > > > +attribute is controlled by @option{-fzero-call-used-regs}. > > > > > + > > > > > @end table > > > > > > > > > > @c This is the end of the target-independent attribute table > > > > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > > > > > index 09bcc5b..da02686 100644 > > > > > --- a/gcc/doc/invoke.texi > > > > > +++ b/gcc/doc/invoke.texi > > > > > @@ -542,7 +542,7 @@ Objective-C and Objective-C++ Dialects}. > > > > > -funit-at-a-time -funroll-all-loops -funroll-loops @gol > > > > > -funsafe-math-optimizations -funswitch-loops @gol > > > > > -fipa-ra -fvariable-expansion-in-unroller -fvect-cost-model -fvpt > > > > > @gol > > > > > --fweb -fwhole-program -fwpa -fuse-linker-plugin @gol > > > > > +-fweb -fwhole-program -fwpa -fuse-linker-plugin > > > > > -fzero-call-used-regs @gol > > > > > --param @var{name}=@var{value} > > > > > -O -O0 -O1 -O2 -O3 -Os -Ofast -Og} > > > > > > > > > > @@ -12273,6 +12273,17 @@ int foo (void) > > > > > > > > > > Not all targets support this option. > > > > > > > > > > +@item -fzero-call-used-regs=@var{choice} > > > > > +@opindex fzero-call-used-regs > > > > > +Zero call-used registers at function return according to > > > > > +@var{choice}. @samp{skip}, which is the default, doesn't zero > > > > > +call-used registers. @samp{used-gpr} zeros call-used general purpose > > > > > +registers which are used in function. @samp{all-gpr} zeros all > > > > > +call-used registers. @samp{used} zeros call-used registers which > > > > > +are used in function. @samp{all} zeros all call-used registers. You > > > > > +can control this behavior for a specific function by using the > > > > > function > > > > > +attribute @code{zero_call_used_regs}. @xref{Function Attributes}. > > > > > + > > > > > @item --param @var{name}=@var{value} > > > > > @opindex param > > > > > In some places, GCC uses various constants to control the amount of > > > > > diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi > > > > > index 6e7d9dc..43dddd3 100644 > > > > > --- a/gcc/doc/tm.texi > > > > > +++ b/gcc/doc/tm.texi > > > > > @@ -4571,6 +4571,22 @@ should recognize only the caller's register > > > > > numbers. > > > > > If this hook is not defined, then FUNCTION_VALUE_REGNO_P will be used. > > > > > @end deftypefn > > > > > > > > > > +@deftypefn {Target Hook} bool TARGET_ZERO_CALL_USED_REGNO_P (const > > > > > unsigned int @var{regno}, bool @var{general_reg_only_p}) > > > > > +A target hook that returns @code{true} if @var{regno} is the number > > > > > of a > > > > > +call used register. If @var{general_reg_only_p} is @code{true}, > > > > > +@var{regno} must be the number of a hard general register. > > > > > + > > > > > +If this hook is not defined, then default_zero_call_used_regno_p > > > > > will be used. > > > > > +@end deftypefn > > > > > + > > > > > +@deftypefn {Target Hook} machine_mode > > > > > TARGET_ZERO_CALL_USED_REGNO_MODE (const unsigned int @var{regno}, > > > > > machine_mode @var{mode}) > > > > > +A target hook that returns a mode of suitable to zero the register > > > > > for the > > > > > +call used register @var{regno} in @var{mode}. > > > > > + > > > > > +If this hook is not defined, then default_zero_call_used_regno_mode > > > > > will be > > > > > +used. > > > > > +@end deftypefn > > > > > + > > > > > @defmac APPLY_RESULT_SIZE > > > > > Define this macro if @samp{untyped_call} and @samp{untyped_return} > > > > > need more space than is implied by @code{FUNCTION_VALUE_REGNO_P} for > > > > > @@ -12043,6 +12059,17 @@ argument list due to stack realignment. > > > > > Return @code{NULL} if no DRAP > > > > > is needed. > > > > > @end deftypefn > > > > > > > > > > +@deftypefn {Target Hook} rtx TARGET_PRO_EPILOGUE_USE (rtx @var{reg}) > > > > > +This hook should return a UNSPEC_VOLATILE rtx to mark a register in > > > > > use to > > > > > +prevent deleting register setting instructions in proprologue and > > > > > epilogue. > > > > > +@end deftypefn > > > > > + > > > > > +@deftypefn {Target Hook} rtx TARGET_ZERO_ALL_VECTOR_REGISTERS (bool > > > > > @var{used_only}) > > > > > +This hook should return an rtx to zero all vector registers at > > > > > function > > > > > +exit. If @var{used_only} is @code{true}, only used vector registers > > > > > should > > > > > +be zeroed. Return @code{NULL} if possible > > > > > +@end deftypefn > > > > > + > > > > > @deftypefn {Target Hook} bool TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS > > > > > (void) > > > > > When optimization is disabled, this hook indicates whether or not > > > > > arguments should be allocated to stack slots. Normally, GCC allocates > > > > > diff --git a/gcc/doc/tm.texi.in <http://tm.texi.in/> > > > > > b/gcc/doc/tm.texi.in <http://tm.texi.in/> > > > > > index 3be984b..bee917a 100644 > > > > > --- a/gcc/doc/tm.texi.in <http://tm.texi.in/> > > > > > +++ b/gcc/doc/tm.texi.in <http://tm.texi.in/> > > > > > @@ -3430,6 +3430,10 @@ for a new target instead. > > > > > > > > > > @hook TARGET_FUNCTION_VALUE_REGNO_P > > > > > > > > > > +@hook TARGET_ZERO_CALL_USED_REGNO_P > > > > > + > > > > > +@hook TARGET_ZERO_CALL_USED_REGNO_MODE > > > > > + > > > > > @defmac APPLY_RESULT_SIZE > > > > > Define this macro if @samp{untyped_call} and @samp{untyped_return} > > > > > need more space than is implied by @code{FUNCTION_VALUE_REGNO_P} for > > > > > @@ -8109,6 +8113,10 @@ and the associated definitions of those > > > > > functions. > > > > > > > > > > @hook TARGET_GET_DRAP_RTX > > > > > > > > > > +@hook TARGET_PRO_EPILOGUE_USE > > > > > + > > > > > +@hook TARGET_ZERO_ALL_VECTOR_REGISTERS > > > > > + > > > > > @hook TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS > > > > > > > > > > @hook TARGET_CONST_ANCHOR > > > > > diff --git a/gcc/function.c b/gcc/function.c > > > > > index 9eee9b5..9908530 100644 > > > > > --- a/gcc/function.c > > > > > +++ b/gcc/function.c > > > > > @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see > > > > > #include "emit-rtl.h" > > > > > #include "recog.h" > > > > > #include "rtl-error.h" > > > > > +#include "hard-reg-set.h" > > > > > #include "alias.h" > > > > > #include "fold-const.h" > > > > > #include "stor-layout.h" > > > > > @@ -5808,6 +5809,147 @@ make_prologue_seq (void) > > > > > return seq; > > > > > } > > > > > > > > > > +/* Check whether the hard register REGNO is live at the exit block > > > > > + * of the current routine. */ > > > > > +bool > > > > > +is_live_reg_at_exit (unsigned int regno) > > > > > +{ > > > > > + edge e; > > > > > + edge_iterator ei; > > > > > + > > > > > + FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) > > > > > + { > > > > > + bitmap live_out = df_get_live_out (e->src); > > > > > + if (REGNO_REG_SET_P (live_out, regno)) > > > > > + return true; > > > > > + } > > > > > + > > > > > + return false; > > > > > +} > > > > > + > > > > > +/* Emit a sequence of insns to zero the call-used-registers for the > > > > > current > > > > > + * function. */ > > No '*' on the continuation line > > > > > > + > > > > > +static void > > > > > +gen_call_used_regs_seq (void) > > > > > +{ > > > > > + if (!targetm.calls.pro_epilogue_use) > > > > > + return; > > > > > + > > > > > + bool gpr_only = true; > > > > > + bool used_only = true; > > > > > + enum zero_call_used_regs zero_call_used_regs_type = > > > > > zero_call_used_regs_unset; > > > > > + > > > > > + if (flag_zero_call_used_regs) > > > > > + if (DECL_ZERO_CALL_USED_REGS (current_function_decl) > > > > > + == zero_call_used_regs_unset) > > > > > + zero_call_used_regs_type = flag_zero_call_used_regs; > > > > > + else > > > > > + zero_call_used_regs_type > > > > > + = DECL_ZERO_CALL_USED_REGS (current_function_decl); > > > > > + else > > > > > + zero_call_used_regs_type = DECL_ZERO_CALL_USED_REGS > > > > > (current_function_decl); > > > > > + > > > > > + /* No need to zero call-used-regs when no user request is present. > > > > > */ > > > > > + if (zero_call_used_regs_type <= zero_call_used_regs_skip) > > > > > + return; > > > > > + > > > > > + /* No need to zero call-used-regs in main (). */ > > > > > + if (MAIN_NAME_P (DECL_NAME (current_function_decl))) > > > > > + return; > > > > > + > > > > > + /* No need to zero call-used-regs if __builtin_eh_return is called > > > > > + since it isn't a normal function return. */ > > > > > + if (crtl->calls_eh_return) > > > > > + return; > > > > > + > > > > > + /* If gpr_only is true, only zero call-used-registers that are > > > > > + general-purpose registers; if used_only is true, only zero > > > > > + call-used-registers that are used in the current function. */ > > > > > + switch (zero_call_used_regs_type) > > > > > + { > > > > > + case zero_call_used_regs_all_gpr: > > > > > + used_only = false; > > > > > + break; > > > > > + case zero_call_used_regs_used: > > > > > + gpr_only = false; > > > > > + break; > > > > > + case zero_call_used_regs_all: > > > > > + gpr_only = false; > > > > > + used_only = false; > > > > > + break; > > > > > + default: > > > > > + break; > > > > > + } > > > > > + > > > > > + /* An optimization to use a single hard insn to zero all vector > > > > > registers on > > > > > + the target that provides such insn. */ > > > > > + if (!gpr_only > > > > > + && targetm.calls.zero_all_vector_registers) > > > > > + { > > > > > + rtx zero_all_vec_insn > > > > > + = targetm.calls.zero_all_vector_registers (used_only); > > > > > + if (zero_all_vec_insn) > > > > > + { > > > > > + emit_insn (zero_all_vec_insn); > > > > > + gpr_only = true; > > > > > + } > > > > > + } > > > > > + > > > > > + /* For each of the hard registers, check to see whether we should > > > > > zero it if: > > > > > + 1. it is a call-used-registers; > > > > > + and 2. it is not a fixed-registers; > > > > > + and 3. it is not live at the end of the routine; > > > > > + and 4. it is general purpose register if gpr_only is true; > > > > > + and 5. it is used in the routine if used_only is true; > > > > > + */ > > > > > + > > > > > + /* This array holds the zero rtx with the correponding machine > > > > > mode. */ > > > > > + rtx zero_rtx[(int)MAX_MACHINE_MODE]; > > > > > + for (int i = 0; i < (int) MAX_MACHINE_MODE; i++) > > > > > + zero_rtx[i] = NULL_RTX; > > > > > + > > > > > + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; > > > > > regno++) > > > > > + { > > > > > + if (!this_target_hard_regs->x_call_used_regs[regno]) > > Use if (!call_used_regs[regno]) > > > > > > + continue; > > > > > + if (fixed_regs[regno]) > > > > > + continue; > > > > > + if (is_live_reg_at_exit (regno)) > > > > > + continue; > > How can a call-used reg be live at exit? > > > > > > + if (!targetm.calls.zero_call_used_regno_p (regno, gpr_only)) > > > > > + continue; > > Why does the target need some extra say here? > > > > > > + if (used_only && !df_regs_ever_live_p (regno)) > > So I suppose this does not include uses by callees of this function? > > > > > > + continue; > > > > > + > > > > > + /* Now we can emit insn to zero this register. */ > > > > > + rtx reg, tmp; > > > > > + > > > > > + machine_mode mode > > > > > + = targetm.calls.zero_call_used_regno_mode (regno, > > > > > + reg_raw_mode[regno]); > > In what case does the target ever need to adjust this (we're dealing > with hard-regs only?)? > > > > > > + if (mode == VOIDmode) > > > > > + continue; > > > > > + if (!have_regs_of_mode[mode]) > > > > > + continue; > > When does this happen? > > > > > > + > > > > > + reg = gen_rtx_REG (mode, regno); > > > > > + if (zero_rtx[(int)mode] == NULL_RTX) > > > > > + { > > > > > + zero_rtx[(int)mode] = reg; > > > > > + tmp = gen_rtx_SET (reg, const0_rtx); > > > > > + emit_insn (tmp); > > > > > + } > > > > > + else > > > > > + emit_move_insn (reg, zero_rtx[(int)mode]); > > Not sure but I think the canonical zero to use is CONST0_RTX (mode) > but I may be wrong. I'd rather have the target be able to specify > some special instruction for zeroing here. Some may have > multi-reg set instructions for example. That said, can't we > defer the actual zeroing to the target in full and only compute > a hard-reg-set of to-be zerored registers here and pass that > to a target hook? > > > > > > + > > > > > + emit_insn (targetm.calls.pro_epilogue_use (reg)); > > > > > + } > > > > > + > > > > > + return; > > > > > +} > > > > > + > > > > > + > > > > > /* Return a sequence to be used as the epilogue for the current > > > > > function, > > > > > or NULL. */ > > > > > > > > > > @@ -5819,6 +5961,9 @@ make_epilogue_seq (void) > > > > > > > > > > start_sequence (); > > > > > emit_note (NOTE_INSN_EPILOGUE_BEG); > > > > > + > > > > > + gen_call_used_regs_seq (); > > > > > + > > The caller eventually performs shrink-wrapping - are you sure that > doesn't mess up things? > > > > > > rtx_insn *seq = targetm.gen_epilogue (); > > > > > if (seq) > > > > > emit_jump_insn (seq); > > > > > diff --git a/gcc/function.h b/gcc/function.h > > > > > index d55cbdd..fc36c3e 100644 > > > > > --- a/gcc/function.h > > > > > +++ b/gcc/function.h > > > > > @@ -705,4 +705,6 @@ extern const char *current_function_name (void); > > > > > > > > > > extern void used_types_insert (tree); > > > > > > > > > > +extern bool is_live_reg_at_exit (unsigned int); > > > > > + > > > > > #endif /* GCC_FUNCTION_H */ > > > > > diff --git a/gcc/target.def b/gcc/target.def > > > > > index 07059a8..8aab63e 100644 > > > > > --- a/gcc/target.def > > > > > +++ b/gcc/target.def > > > > > @@ -5022,6 +5022,26 @@ If this hook is not defined, then > > > > > FUNCTION_VALUE_REGNO_P will be used.", > > > > > default_function_value_regno_p) > > > > > > > > > > DEFHOOK > > > > > +(zero_call_used_regno_p, > > > > > + "A target hook that returns @code{true} if @var{regno} is the > > > > > number of a\n\ > > > > > +call used register. If @var{general_reg_only_p} is @code{true},\n\ > > > > > +@var{regno} must be the number of a hard general register.\n\ > > > > > +\n\ > > > > > +If this hook is not defined, then default_zero_call_used_regno_p > > > > > will be used.", > > > > > + bool, (const unsigned int regno, bool general_reg_only_p), > > > > > + default_zero_call_used_regno_p) > > > > > + > > > > > +DEFHOOK > > > > > +(zero_call_used_regno_mode, > > > > > + "A target hook that returns a mode of suitable to zero the register > > > > > for the\n\ > > > > > +call used register @var{regno} in @var{mode}.\n\ > > > > > +\n\ > > > > > +If this hook is not defined, then default_zero_call_used_regno_mode > > > > > will be\n\ > > > > > +used.", > > > > > + machine_mode, (const unsigned int regno, machine_mode mode), > > > > > + default_zero_call_used_regno_mode) > > > > > + > > > > > +DEFHOOK > > > > > (fntype_abi, > > > > > "Return the ABI used by a function with type @var{type}; see the\n\ > > > > > definition of @code{predefined_function_abi} for details of the ABI\n\ > > > > > @@ -5068,6 +5088,19 @@ argument list due to stack realignment. > > > > > Return @code{NULL} if no DRAP\n\ > > > > > is needed.", > > > > > rtx, (void), NULL) > > > > > > > > > > +DEFHOOK > > > > > +(pro_epilogue_use, > > > > > + "This hook should return a UNSPEC_VOLATILE rtx to mark a register > > > > > in use to\n\ > > > > > +prevent deleting register setting instructions in proprologue and > > > > > epilogue.", > > > > > + rtx, (rtx reg), NULL) > > > > > + > > > > > +DEFHOOK > > > > > +(zero_all_vector_registers, > > > > > + "This hook should return an rtx to zero all vector registers at > > > > > function\n\ > > > > > +exit. If @var{used_only} is @code{true}, only used vector registers > > > > > should\n\ > > > > > +be zeroed. Return @code{NULL} if possible", > > > > > + rtx, (bool used_only), NULL) > > > > > + > > > > > /* Return true if all function parameters should be spilled to the > > > > > stack. */ > > > > > DEFHOOK > > > > > diff --git a/gcc/targhooks.c b/gcc/targhooks.c > > > > > index 0113c7b..ed02173 100644 > > > > > --- a/gcc/targhooks.c > > > > > +++ b/gcc/targhooks.c > > > > > @@ -987,6 +987,23 @@ default_function_value_regno_p (const unsigned > > > > > int regno ATTRIBUTE_UNUSED) > > > > > #endif > > > > > } > > > > > > > > > > +/* The default hook for TARGET_ZERO_CALL_USED_REGNO_P. */ > > > > > + > > > > > +bool > > > > > +default_zero_call_used_regno_p (const unsigned int, > > > > > + bool) > > > > > +{ > > > > > + return false; > > > > > +} > > > > > + > > > > > +/* The default hook for TARGET_ZERO_CALL_USED_REGNO_MODE. */ > > > > > + > > > > > +machine_mode > > > > > +default_zero_call_used_regno_mode (const unsigned int, machine_mode > > > > > mode) > > > > > +{ > > > > > + return mode; > > > > > +} > > > > > + > > > > > rtx > > > > > default_internal_arg_pointer (void) > > > > > { > > > > > diff --git a/gcc/targhooks.h b/gcc/targhooks.h > > > > > index b572a36..370df19 100644 > > > > > --- a/gcc/targhooks.h > > > > > +++ b/gcc/targhooks.h > > > > > @@ -162,6 +162,9 @@ extern bool hook_bool_const_rtx_commutative_p > > > > > (const_rtx, int); > > > > > extern rtx default_function_value (const_tree, const_tree, bool); > > > > > extern rtx default_libcall_value (machine_mode, const_rtx); > > > > > extern bool default_function_value_regno_p (const unsigned int); > > > > > +extern bool default_zero_call_used_regno_p (const unsigned int, > > > > > bool); > > > > > +extern machine_mode default_zero_call_used_regno_mode (const > > > > > unsigned int, > > > > > + machine_mode); > > > > > extern rtx default_internal_arg_pointer (void); > > > > > extern rtx default_static_chain (const_tree, bool); > > > > > extern void default_trampoline_init (rtx, tree, rtx); > > > > > diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-1.c > > > > > b/gcc/testsuite/c-c++-common/zero-scratch-regs-1.c > > > > > new file mode 100644 > > > > > index 0000000..3c2ac72 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-1.c > > > > > @@ -0,0 +1,3 @@ > > > > > +/* { dg-do compile } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=used" } */ > > > > > +/* { dg-error "'-fzero-call-used-regs=' is not supported for this > > > > > target" "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */ > > > > > diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-2.c > > > > > b/gcc/testsuite/c-c++-common/zero-scratch-regs-2.c > > > > > new file mode 100644 > > > > > index 0000000..acf48c4 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-2.c > > > > > @@ -0,0 +1,4 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2" } */ > > > > > + > > > > > +extern int foo (int) __attribute__ > > > > > ((zero_call_used_regs("all-gpr"))); /* { dg-warning " attribute > > > > > directive ignored" "" {target { ! "i?86-*-* x86_64-*-*" } } 0 } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-1.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-1.c > > > > > new file mode 100644 > > > > > index 0000000..9f61dc4 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-1.c > > > > > @@ -0,0 +1,12 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=used" } */ > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-10.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-10.c > > > > > new file mode 100644 > > > > > index 0000000..09048e5 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-10.c > > > > > @@ -0,0 +1,21 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ > > > > > + > > > > > +extern int foo (int) __attribute__ > > > > > ((zero_call_used_regs("all-gpr"))); > > > > > + > > > > > +int > > > > > +foo (int x) > > > > > +{ > > > > > + return x; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%edx, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-11.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-11.c > > > > > new file mode 100644 > > > > > index 0000000..4862688 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-11.c > > > > > @@ -0,0 +1,39 @@ > > > > > +/* { dg-do run { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=used-gpr" } */ > > > > > + > > > > > +struct S { int i; }; > > > > > +__attribute__((const, noinline, noclone)) > > > > > +struct S foo (int x) > > > > > +{ > > > > > + struct S s; > > > > > + s.i = x; > > > > > + return s; > > > > > +} > > > > > + > > > > > +int a[2048], b[2048], c[2048], d[2048]; > > > > > +struct S e[2048]; > > > > > + > > > > > +__attribute__((noinline, noclone)) void > > > > > +bar (void) > > > > > +{ > > > > > + int i; > > > > > + for (i = 0; i < 1024; i++) > > > > > + { > > > > > + e[i] = foo (i); > > > > > + a[i+2] = a[i] + a[i+1]; > > > > > + b[10] = b[10] + i; > > > > > + c[i] = c[2047 - i]; > > > > > + d[i] = d[i + 1]; > > > > > + } > > > > > +} > > > > > + > > > > > +int > > > > > +main () > > > > > +{ > > > > > + int i; > > > > > + bar (); > > > > > + for (i = 0; i < 1024; i++) > > > > > + if (e[i].i != i) > > > > > + __builtin_abort (); > > > > > + return 0; > > > > > +} > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-12.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-12.c > > > > > new file mode 100644 > > > > > index 0000000..500251b > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-12.c > > > > > @@ -0,0 +1,39 @@ > > > > > +/* { dg-do run { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all-gpr" } */ > > > > > + > > > > > +struct S { int i; }; > > > > > +__attribute__((const, noinline, noclone)) > > > > > +struct S foo (int x) > > > > > +{ > > > > > + struct S s; > > > > > + s.i = x; > > > > > + return s; > > > > > +} > > > > > + > > > > > +int a[2048], b[2048], c[2048], d[2048]; > > > > > +struct S e[2048]; > > > > > + > > > > > +__attribute__((noinline, noclone)) void > > > > > +bar (void) > > > > > +{ > > > > > + int i; > > > > > + for (i = 0; i < 1024; i++) > > > > > + { > > > > > + e[i] = foo (i); > > > > > + a[i+2] = a[i] + a[i+1]; > > > > > + b[10] = b[10] + i; > > > > > + c[i] = c[2047 - i]; > > > > > + d[i] = d[i + 1]; > > > > > + } > > > > > +} > > > > > + > > > > > +int > > > > > +main () > > > > > +{ > > > > > + int i; > > > > > + bar (); > > > > > + for (i = 0; i < 1024; i++) > > > > > + if (e[i].i != i) > > > > > + __builtin_abort (); > > > > > + return 0; > > > > > +} > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-13.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-13.c > > > > > new file mode 100644 > > > > > index 0000000..8b058e3 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-13.c > > > > > @@ -0,0 +1,21 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7" } */ > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm0, %xmm0" } } */ > > > > > +/* { dg-final { scan-assembler-times "movaps\[ \t\]*%xmm0, > > > > > %xmm\[0-9\]+" 7 { target { ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler-times "movaps\[ \t\]*%xmm0, > > > > > %xmm\[0-9\]+" 15 { target { ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-14.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-14.c > > > > > new file mode 100644 > > > > > index 0000000..d4eaaf7 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-14.c > > > > > @@ -0,0 +1,19 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7 -mavx" > > > > > } */ > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-times "vzeroall" 1 } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-15.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-15.c > > > > > new file mode 100644 > > > > > index 0000000..dd3bb90 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-15.c > > > > > @@ -0,0 +1,14 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ > > > > > + > > > > > +extern void foo (void) __attribute__ ((zero_call_used_regs("used"))); > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-16.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-16.c > > > > > new file mode 100644 > > > > > index 0000000..e2274f6 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-16.c > > > > > @@ -0,0 +1,14 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all" } */ > > > > > + > > > > > +extern void foo (void) __attribute__ ((zero_call_used_regs("skip"))); > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-17.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-17.c > > > > > new file mode 100644 > > > > > index 0000000..7f5d153 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-17.c > > > > > @@ -0,0 +1,13 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=used" } */ > > > > > + > > > > > +int > > > > > +foo (int x) > > > > > +{ > > > > > + return x; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" { target ia32 } } > > > > > } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%edi, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-18.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-18.c > > > > > new file mode 100644 > > > > > index 0000000..fe13d2b > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-18.c > > > > > @@ -0,0 +1,13 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=used -march=corei7" } */ > > > > > + > > > > > +float > > > > > +foo (float z, float y, float x) > > > > > +{ > > > > > + return x + y; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm1, %xmm1" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movaps\[ \t\]*%xmm1, %xmm2" { target > > > > > { ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-19.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-19.c > > > > > new file mode 100644 > > > > > index 0000000..205a532 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-19.c > > > > > @@ -0,0 +1,12 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=used -march=corei7" } */ > > > > > + > > > > > +float > > > > > +foo (float z, float y, float x) > > > > > +{ > > > > > + return x; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm2, %xmm2" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-2.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-2.c > > > > > new file mode 100644 > > > > > index 0000000..e046684 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-2.c > > > > > @@ -0,0 +1,19 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all-gpr" } */ > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-20.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-20.c > > > > > new file mode 100644 > > > > > index 0000000..4be8ff6 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-20.c > > > > > @@ -0,0 +1,23 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7" } */ > > > > > + > > > > > +float > > > > > +foo (float z, float y, float x) > > > > > +{ > > > > > + return x + y; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm0, %xmm0" { target { > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm1, %xmm1" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler-times "movaps\[ \t\]*%xmm0, > > > > > %xmm\[0-9\]+" 7 { target { ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler-times "movaps\[ \t\]*%xmm1, > > > > > %xmm\[0-9\]+" 14 { target { ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-21.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-21.c > > > > > new file mode 100644 > > > > > index 0000000..0eb34e0 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-21.c > > > > > @@ -0,0 +1,14 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=skip -march=corei7" } */ > > > > > + > > > > > +__attribute__ ((zero_call_used_regs("used"))) > > > > > +float > > > > > +foo (float z, float y, float x) > > > > > +{ > > > > > + return x + y; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm1, %xmm1" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movaps\[ \t\]*%xmm1, %xmm2" { target > > > > > { ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-22.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-22.c > > > > > new file mode 100644 > > > > > index 0000000..cbb63a4 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-22.c > > > > > @@ -0,0 +1,19 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7 -mavx" > > > > > } */ > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-23.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-23.c > > > > > new file mode 100644 > > > > > index 0000000..7573197 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-23.c > > > > > @@ -0,0 +1,19 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7 > > > > > -mavx512f" } */ > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-3.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-3.c > > > > > new file mode 100644 > > > > > index 0000000..de71223 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-3.c > > > > > @@ -0,0 +1,12 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-4.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-4.c > > > > > new file mode 100644 > > > > > index 0000000..ccfa441 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-4.c > > > > > @@ -0,0 +1,14 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ > > > > > + > > > > > +extern void foo (void) __attribute__ > > > > > ((zero_call_used_regs("used-gpr"))); > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-5.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-5.c > > > > > new file mode 100644 > > > > > index 0000000..6b46ca3 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-5.c > > > > > @@ -0,0 +1,20 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ > > > > > + > > > > > +__attribute__ ((zero_call_used_regs("all-gpr"))) > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-6.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-6.c > > > > > new file mode 100644 > > > > > index 0000000..0680f38 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-6.c > > > > > @@ -0,0 +1,14 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all-gpr" } */ > > > > > + > > > > > +extern void foo (void) __attribute__ ((zero_call_used_regs("skip"))); > > > > > + > > > > > +void > > > > > +foo (void) > > > > > +{ > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ > > > > > +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-7.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-7.c > > > > > new file mode 100644 > > > > > index 0000000..534defa > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-7.c > > > > > @@ -0,0 +1,13 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=used-gpr" } */ > > > > > + > > > > > +int > > > > > +foo (int x) > > > > > +{ > > > > > + return x; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" { target ia32 } } > > > > > } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%edi, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-8.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-8.c > > > > > new file mode 100644 > > > > > index 0000000..477bb19 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-8.c > > > > > @@ -0,0 +1,19 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=all-gpr" } */ > > > > > + > > > > > +int > > > > > +foo (int x) > > > > > +{ > > > > > + return x; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%edx, %edx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %ecx" } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %esi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r8d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r9d" { target { ! > > > > > ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r10d" { target { > > > > > ! ia32 } } } } */ > > > > > +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r11d" { target { > > > > > ! ia32 } } } } */ > > > > > diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-9.c > > > > > b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-9.c > > > > > new file mode 100644 > > > > > index 0000000..a305a60 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-9.c > > > > > @@ -0,0 +1,15 @@ > > > > > +/* { dg-do compile { target *-*-linux* } } */ > > > > > +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ > > > > > + > > > > > +extern int foo (int) __attribute__ > > > > > ((zero_call_used_regs("used-gpr"))); > > > > > + > > > > > +int > > > > > +foo (int x) > > > > > +{ > > > > > + return x; > > > > > +} > > > > > + > > > > > +/* { dg-final { scan-assembler-not "vzeroall" } } */ > > > > > +/* { dg-final { scan-assembler-not "%xmm" } } */ > > > > > +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" { target ia32 } } > > > > > } */ > > > > > +/* { dg-final { scan-assembler "xorl\[ \t\]*%edi, %edi" { target { ! > > > > > ia32 } } } } */ > > > > > diff --git a/gcc/toplev.c b/gcc/toplev.c > > > > > index 95eea63..01a1f24 100644 > > > > > --- a/gcc/toplev.c > > > > > +++ b/gcc/toplev.c > > > > > @@ -1464,6 +1464,15 @@ process_options (void) > > > > > } > > > > > } > > > > > > > > > > + if (flag_zero_call_used_regs != zero_call_used_regs_skip > > > > > + && !targetm.calls.pro_epilogue_use) > > > > > + { > > > > > + error_at (UNKNOWN_LOCATION, > > > > > + "%<-fzero-call-used-regs=%> is not supported for this " > > > > > + "target"); > > > > > + flag_zero_call_used_regs = zero_call_used_regs_skip; > > > > > + } > > > > > + > > > > > /* One region RA really helps to decrease the code size. */ > > > > > if (flag_ira_region == IRA_REGION_AUTODETECT) > > > > > flag_ira_region > > > > > diff --git a/gcc/tree-core.h b/gcc/tree-core.h > > > > > index 8c5a2e3..71badbd 100644 > > > > > --- a/gcc/tree-core.h > > > > > +++ b/gcc/tree-core.h > > > > > @@ -1825,7 +1825,11 @@ struct GTY(()) tree_decl_with_vis { > > > > > unsigned final : 1; > > > > > /* Belong to FUNCTION_DECL exclusively. */ > > > > > unsigned regdecl_flag : 1; > > > > > - /* 14 unused bits. */ > > > > > + > > > > > + /* How to clear call-used registers upon function return. */ > > > > > + ENUM_BITFIELD(zero_call_used_regs) zero_call_used_regs_type : 3; > > > > > + > > > > > + /* 11 unused bits. */ > > So instead of wasting "precious" bits please use lookup_attribute > in the single place you query this value (which is once per function). > There's no need to complicate matters by trying to maintain the above. > > > > > > }; > > > > > > > > > > struct GTY(()) tree_var_decl { > > > > > diff --git a/gcc/tree.h b/gcc/tree.h > > > > > index cf546ed..d378a88 100644 > > > > > --- a/gcc/tree.h > > > > > +++ b/gcc/tree.h > > > > > @@ -2925,6 +2925,11 @@ extern void decl_value_expr_insert (tree, > > > > > tree); > > > > > #define DECL_VISIBILITY(NODE) \ > > > > > (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.visibility) > > > > > > > > > > +/* Value of the function decl's type of zeroing the call used > > > > > + registers upon return from function. */ > > > > > +#define DECL_ZERO_CALL_USED_REGS(NODE) \ > > > > > + (DECL_WITH_VIS_CHECK > > > > > (NODE)->decl_with_vis.zero_call_used_regs_type) > > > > > + > > > > > /* Nonzero means that the decl (or an enclosing scope) had its > > > > > visibility specified rather than being inferred. */ > > > > > #define DECL_VISIBILITY_SPECIFIED(NODE) \ > > > > > -- > > > > > 1.9.1 > > > > > > > > > > > > > -- > Richard Biener <rguent...@suse.de> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, > Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg) -- H.J.