diff mbox series

introduce -fcallgraph-info option

Message ID or1rv0run4.fsf@lxoliva.fsfla.org
State New
Headers show
Series introduce -fcallgraph-info option | expand

Commit Message

Alexandre Oliva Oct. 26, 2019, 4:35 a.m. UTC
This was first submitted many years ago
https://gcc.gnu.org/ml/gcc-patches/2010-10/msg02468.html

The command line option -fcallgraph-info is added and makes the
compiler generate another output file (xxx.ci) for each compilation
unit, which is a valid VCG file (you can launch your favorite VCG
viewer on it unmodified) and contains the "final" callgraph of the
unit.  "final" is a bit of a misnomer as this is actually the
callgraph at RTL expansion time, but since most high-level
optimizations are done at the Tree level and RTL doesn't usually
fiddle with calls, it's final in almost all cases.  Moreover, the
nodes can be decorated with additional info: -fcallgraph-info=su adds
stack usage info and -fcallgraph-info=da dynamic allocation info.

Compared with the earlier version, this patch does not modify cgraph,
and instead adds the required information next to the stage usage
function data structure, so we only hold one of those at at time.  I've
switched to vecs from linked lists, for more compact edges and dynamic
allocation annotations, and arranged for them to be released as soon as
we've printed out the information.  I have NOT changed the file format,
because existing tools such as gnatstack consume the current format.

Regstrapped on x86_64-linux-gnu.  Ok to install?


for  gcc/ChangeLog
From  Eric Botcazou  <ebotcazou@adacore.com>, Alexandre Oliva  <oliva@adacore.com>

	* common.opt (-fcallgraph-info[=]): New option.
	* doc/invoke.texi (Debugging options): Document it.
	* opts.c (common_handle_option): Handle it.
	* builtins.c (expand_builtin_alloca): Record allocation if
	-fcallgraph-info=da.
	* calls.c (expand_call): If -fcallgraph-info, record the call.
	(emit_library_call_value_1): Likewise.
	* flag-types.h (enum callgraph_info_type): New type.
	* explow.c: Include stringpool.h.
	(set_stack_check_libfunc): Set SET_SYMBOL_REF_DECL on the symbol.
	* function.c (allocate_stack_usage_info): New.
	(allocate_struct_function): Call it for -fcallgraph-info.
	(prepare_function_start): Call it otherwise.
	(rest_of_handle_thread_prologue_and_epilogue): Release callees
	and dallocs after output_stack_usage.
	(record_final_call, record_dynamic_alloc): New.
	* function.h (struct callee, struct dalloc): New.
	(struct stack_usage): Add callees and dallocs.
	(record_final_call, record_dynamic_alloc): Declare.
	* gimplify.c (gimplify_decl_expr): Record dynamically-allocated
	object if -fcallgraph-info=da.
	* optabs-libfuncs.c (build_libfunc_function): Keep SYMBOL_REF_DECL.
	* print-tree.h (print_decl_identifier): Declare.
	(PRINT_DECL_ORIGIN, PRINT_DECL_NAME, PRINT_DECL_UNIQUE_NAME): New.
	* print-tree.c: Include print-tree.h.
	(print_decl_identifier): New function.
	* toplev.c: Include print-tree.h.
	(callgraph_info_file): New global variable.
	(callgraph_info_indirect_emitted): Likewise.
	(output_stack_usage): Rename to...
	(output_stack_usage_1): ... this.  Make it static, add cf
	parameter.  If -fcallgraph-info=su, print stack usage to cf.
	If -fstack-usage, use print_decl_identifier for
	pretty-printing.
	(INDIRECT_CALL_NAME): New.
	(dump_final_indirect_call_node_vcg): New.
	(dump_final_callee_vcg, dump_final_node_vcg): New.
	(output_stack_usage): New.
	(lang_dependent_init): Open and start file if
	-fcallgraph-info.
	(finalize): If callgraph_info_file is not null, finish it,
	close it, and reset callgraph info state.

for  gcc/ada/ChangeLog

	* gcc-interface/misc.c (callgraph_info_file): Delete.
---
 gcc/ada/gcc-interface/misc.c |    3 -
 gcc/builtins.c               |    4 +
 gcc/calls.c                  |    6 +
 gcc/common.opt               |    8 ++
 gcc/doc/invoke.texi          |   17 ++++
 gcc/explow.c                 |    5 +
 gcc/flag-types.h             |   16 ++++
 gcc/function.c               |   63 ++++++++++++++--
 gcc/function.h               |   25 ++++++
 gcc/gimplify.c               |    4 +
 gcc/optabs-libfuncs.c        |    4 -
 gcc/opts.c                   |   26 ++++++
 gcc/output.h                 |    2 
 gcc/print-tree.c             |   76 +++++++++++++++++++
 gcc/print-tree.h             |    4 +
 gcc/toplev.c                 |  169 ++++++++++++++++++++++++++++++++++--------
 16 files changed, 381 insertions(+), 51 deletions(-)

Comments

Richard Biener Oct. 26, 2019, 7:52 a.m. UTC | #1
On October 26, 2019 6:35:43 AM GMT+02:00, Alexandre Oliva <oliva@adacore.com> wrote:
>This was first submitted many years ago
>https://gcc.gnu.org/ml/gcc-patches/2010-10/msg02468.html
>
>The command line option -fcallgraph-info is added and makes the
>compiler generate another output file (xxx.ci) for each compilation
>unit, which is a valid VCG file (you can launch your favorite VCG
>viewer on it unmodified) and contains the "final" callgraph of the
>unit.  "final" is a bit of a misnomer as this is actually the
>callgraph at RTL expansion time, but since most high-level
>optimizations are done at the Tree level and RTL doesn't usually
>fiddle with calls, it's final in almost all cases.  Moreover, the
>nodes can be decorated with additional info: -fcallgraph-info=su adds
>stack usage info and -fcallgraph-info=da dynamic allocation info.
>
>Compared with the earlier version, this patch does not modify cgraph,
>and instead adds the required information next to the stage usage
>function data structure, so we only hold one of those at at time.  I've
>switched to vecs from linked lists, for more compact edges and dynamic
>allocation annotations, and arranged for them to be released as soon as
>we've printed out the information.  I have NOT changed the file format,
>because existing tools such as gnatstack consume the current format.
>
>Regstrapped on x86_64-linux-gnu.  Ok to install?

How does it relate to the LTO-dump utility we have now which can in theory provide a more complete view? Maybe some infrastructure can be shared here (the actual dumping of the cgraph?) 

Thanks, 
Richard. 

>
>for  gcc/ChangeLog
>From  Eric Botcazou  <ebotcazou@adacore.com>, Alexandre Oliva 
><oliva@adacore.com>
>
>	* common.opt (-fcallgraph-info[=]): New option.
>	* doc/invoke.texi (Debugging options): Document it.
>	* opts.c (common_handle_option): Handle it.
>	* builtins.c (expand_builtin_alloca): Record allocation if
>	-fcallgraph-info=da.
>	* calls.c (expand_call): If -fcallgraph-info, record the call.
>	(emit_library_call_value_1): Likewise.
>	* flag-types.h (enum callgraph_info_type): New type.
>	* explow.c: Include stringpool.h.
>	(set_stack_check_libfunc): Set SET_SYMBOL_REF_DECL on the symbol.
>	* function.c (allocate_stack_usage_info): New.
>	(allocate_struct_function): Call it for -fcallgraph-info.
>	(prepare_function_start): Call it otherwise.
>	(rest_of_handle_thread_prologue_and_epilogue): Release callees
>	and dallocs after output_stack_usage.
>	(record_final_call, record_dynamic_alloc): New.
>	* function.h (struct callee, struct dalloc): New.
>	(struct stack_usage): Add callees and dallocs.
>	(record_final_call, record_dynamic_alloc): Declare.
>	* gimplify.c (gimplify_decl_expr): Record dynamically-allocated
>	object if -fcallgraph-info=da.
>	* optabs-libfuncs.c (build_libfunc_function): Keep SYMBOL_REF_DECL.
>	* print-tree.h (print_decl_identifier): Declare.
>	(PRINT_DECL_ORIGIN, PRINT_DECL_NAME, PRINT_DECL_UNIQUE_NAME): New.
>	* print-tree.c: Include print-tree.h.
>	(print_decl_identifier): New function.
>	* toplev.c: Include print-tree.h.
>	(callgraph_info_file): New global variable.
>	(callgraph_info_indirect_emitted): Likewise.
>	(output_stack_usage): Rename to...
>	(output_stack_usage_1): ... this.  Make it static, add cf
>	parameter.  If -fcallgraph-info=su, print stack usage to cf.
>	If -fstack-usage, use print_decl_identifier for
>	pretty-printing.
>	(INDIRECT_CALL_NAME): New.
>	(dump_final_indirect_call_node_vcg): New.
>	(dump_final_callee_vcg, dump_final_node_vcg): New.
>	(output_stack_usage): New.
>	(lang_dependent_init): Open and start file if
>	-fcallgraph-info.
>	(finalize): If callgraph_info_file is not null, finish it,
>	close it, and reset callgraph info state.
>
>for  gcc/ada/ChangeLog
>
>	* gcc-interface/misc.c (callgraph_info_file): Delete.
>---
> gcc/ada/gcc-interface/misc.c |    3 -
> gcc/builtins.c               |    4 +
> gcc/calls.c                  |    6 +
> gcc/common.opt               |    8 ++
> gcc/doc/invoke.texi          |   17 ++++
> gcc/explow.c                 |    5 +
> gcc/flag-types.h             |   16 ++++
> gcc/function.c               |   63 ++++++++++++++--
> gcc/function.h               |   25 ++++++
> gcc/gimplify.c               |    4 +
> gcc/optabs-libfuncs.c        |    4 -
> gcc/opts.c                   |   26 ++++++
> gcc/output.h                 |    2 
> gcc/print-tree.c             |   76 +++++++++++++++++++
> gcc/print-tree.h             |    4 +
>gcc/toplev.c                 |  169
>++++++++++++++++++++++++++++++++++--------
> 16 files changed, 381 insertions(+), 51 deletions(-)
>
>diff --git a/gcc/ada/gcc-interface/misc.c
>b/gcc/ada/gcc-interface/misc.c
>index 4abd4d5708a54..d68b37384ff7f 100644
>--- a/gcc/ada/gcc-interface/misc.c
>+++ b/gcc/ada/gcc-interface/misc.c
>@@ -54,9 +54,6 @@
> #include "ada-tree.h"
> #include "gigi.h"
> 
>-/* This symbol needs to be defined for the front-end.  */
>-void *callgraph_info_file = NULL;
>-
>/* Command-line argc and argv.  These variables are global since they
>are
>    imported in back_end.adb.  */
> unsigned int save_argc;
>diff --git a/gcc/builtins.c b/gcc/builtins.c
>index 5d811f113c907..bd302383377ba 100644
>--- a/gcc/builtins.c
>+++ b/gcc/builtins.c
>@@ -5406,6 +5406,10 @@ expand_builtin_alloca (tree exp)
>= allocate_dynamic_stack_space (op0, 0, align, max_size,
>alloca_for_var);
>   result = convert_memory_address (ptr_mode, result);
> 
>+  /* Dynamic allocations for variables are recorded during
>gimplification.  */
>+  if (!alloca_for_var && (flag_callgraph_info &
>CALLGRAPH_INFO_DYNAMIC_ALLOC))
>+    record_dynamic_alloc (exp);
>+
>   return result;
> }
> 
>diff --git a/gcc/calls.c b/gcc/calls.c
>index ae904473d0dc6..67c7c77598a3f 100644
>--- a/gcc/calls.c
>+++ b/gcc/calls.c
>@@ -3759,6 +3759,9 @@ expand_call (tree exp, rtx target, int ignore)
> 
>preferred_unit_stack_boundary = preferred_stack_boundary /
>BITS_PER_UNIT;
> 
>+  if (flag_callgraph_info)
>+    record_final_call (fndecl, EXPR_LOCATION (exp));
>+
>  /* We want to make two insn chains; one for a sibling call, the other
>      for a normal call.  We will select one of the two chains after
>      initial RTL generation is complete.  */
>@@ -5343,6 +5346,9 @@ emit_library_call_value_1 (int retval, rtx
>orgfun, rtx value,
> 
>   before_call = get_last_insn ();
> 
>+  if (flag_callgraph_info)
>+    record_final_call (SYMBOL_REF_DECL (orgfun), UNKNOWN_LOCATION);
>+
>/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
>      will set inhibit_defer_pop to that value.  */
>/* The return type is needed to decide how many bytes the function
>pops.
>diff --git a/gcc/common.opt b/gcc/common.opt
>index cc279f411d796..63d646fba2b42 100644
>--- a/gcc/common.opt
>+++ b/gcc/common.opt
>@@ -1091,6 +1091,14 @@ fbtr-bb-exclusive
> Common Ignore
> Does nothing.  Preserved for backward compatibility.
> 
>+fcallgraph-info
>+Common Report RejectNegative Var(flag_callgraph_info)
>Init(NO_CALLGRAPH_INFO);
>+Output callgraph information on a per-file basis
>+
>+fcallgraph-info=
>+Common Report RejectNegative Joined
>+Output callgraph information on a per-file basis with decorations
>+
> fcall-saved-
> Common Joined RejectNegative Var(common_deferred_options) Defer
>-fcall-saved-<register>	Mark <register> as being preserved across
>functions.
>diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>index 1407d019d1404..545b842eade71 100644
>--- a/gcc/doc/invoke.texi
>+++ b/gcc/doc/invoke.texi
>@@ -583,8 +583,9 @@ Objective-C and Objective-C++ Dialects}.
> @item Developer Options
> @xref{Developer Options,,GCC Developer Options}.
>@gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion
>@gol
>--dumpfullversion  -fchecking  -fchecking=@var{n}  -fdbg-cnt-list @gol
>--fdbg-cnt=@var{counter-value-list} @gol
>+-dumpfullversion  -fcallgraph-info@r{[}=su,da@r{]}
>+-fchecking  -fchecking=@var{n}
>+-fdbg-cnt-list @gol  -fdbg-cnt=@var{counter-value-list} @gol
> -fdisable-ipa-@var{pass_name} @gol
> -fdisable-rtl-@var{pass_name} @gol
> -fdisable-rtl-@var{pass-name}=@var{range-list} @gol
>@@ -14533,6 +14534,18 @@ The files are created in the directory of the
>output file.
> 
> @table @gcctabopt
> 
>+@item -fcallgraph-info
>+@itemx -fcallgraph-info=@var{MARKERS}
>+@opindex fcallgraph-info
>+Makes the compiler output callgraph information for the program, on a
>+per-file basis.  The information is generated in the common VCG
>format.
>+It can be decorated with additional, per-node and/or per-edge
>information,
>+if a list of comma-separated markers is additionally specified.  When
>the
>+@code{su} marker is specified, the callgraph is decorated with stack
>usage
>+information; it is equivalent to @option{-fstack-usage}.  When the
>@code{da}
>+marker is specified, the callgraph is decorated with information about
>+dynamically allocated objects.
>+
> @item -d@var{letters}
> @itemx -fdump-rtl-@var{pass}
> @itemx -fdump-rtl-@var{pass}=@var{filename}
>diff --git a/gcc/explow.c b/gcc/explow.c
>index 7eb854bca4a6d..83c786366c1aa 100644
>--- a/gcc/explow.c
>+++ b/gcc/explow.c
>@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
> #include "dojump.h"
> #include "explow.h"
> #include "expr.h"
>+#include "stringpool.h"
> #include "common/common-target.h"
> #include "output.h"
> #include "params.h"
>@@ -1611,6 +1612,10 @@ set_stack_check_libfunc (const char
>*libfunc_name)
> {
>   gcc_assert (stack_check_libfunc == NULL_RTX);
>   stack_check_libfunc = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
>+  tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
>+			  get_identifier (libfunc_name), void_type_node);
>+  DECL_EXTERNAL (decl) = 1;
>+  SET_SYMBOL_REF_DECL (stack_check_libfunc, decl);
> }
>
> /* Emit one stack probe at ADDRESS, an address within the stack.  */
>diff --git a/gcc/flag-types.h b/gcc/flag-types.h
>index a2103282d469d..b23d3a271f1ee 100644
>--- a/gcc/flag-types.h
>+++ b/gcc/flag-types.h
>@@ -200,6 +200,22 @@ enum stack_check_type
>   FULL_BUILTIN_STACK_CHECK
> };
> 
>+/* Type of callgraph information.  */
>+enum callgraph_info_type
>+{
>+  /* No information.  */
>+  NO_CALLGRAPH_INFO = 0,
>+
>+  /* Naked callgraph.  */
>+  CALLGRAPH_INFO_NAKED = 1,
>+
>+  /* Callgraph decorated with stack usage information.  */
>+  CALLGRAPH_INFO_STACK_USAGE = 2,
>+
>+  /* Callgraph decoration with dynamic allocation information.  */
>+  CALLGRAPH_INFO_DYNAMIC_ALLOC = 4
>+};
>+
> /* Floating-point contraction mode.  */
> enum fp_contract_mode {
>   FP_CONTRACT_OFF = 0,
>diff --git a/gcc/function.c b/gcc/function.c
>index a1c76a4dd7a84..152f927097c47 100644
>--- a/gcc/function.c
>+++ b/gcc/function.c
>@@ -4725,6 +4725,16 @@ get_last_funcdef_no (void)
>   return funcdef_no;
> }
> 
>+/* Allocate and initialize the stack usage info data structure for the
>+   current function.  */
>+static void
>+allocate_stack_usage_info (void)
>+{
>+  gcc_assert (!cfun->su);
>+  cfun->su = ggc_cleared_alloc<stack_usage> ();
>+  cfun->su->static_stack_size = -1;
>+}
>+
> /* Allocate a function structure for FNDECL and set its contents
>    to the defaults.  Set cfun to the newly-allocated object.
>    Some of the helper functions invoked during initialization assume
>@@ -4802,6 +4812,9 @@ allocate_struct_function (tree fndecl, bool
>abstract_p)
> 
>       if (!profile_flag && !flag_instrument_function_entry_exit)
> 	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
>+
>+      if (flag_callgraph_info)
>+	allocate_stack_usage_info ();
>     }
> 
>   /* Don't enable begin stmt markers if var-tracking at assignments is
>@@ -4846,11 +4859,8 @@ prepare_function_start (void)
>   init_expr ();
>   default_rtl_profile ();
> 
>-  if (flag_stack_usage_info)
>-    {
>-      cfun->su = ggc_cleared_alloc<stack_usage> ();
>-      cfun->su->static_stack_size = -1;
>-    }
>+  if (flag_stack_usage_info && !flag_callgraph_info)
>+    allocate_stack_usage_info ();
> 
>   cse_not_expected = ! optimize;
> 
>@@ -6373,12 +6383,51 @@ rest_of_handle_thread_prologue_and_epilogue
>(void)
>   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
> 
>   /* The stack usage info is finalized during prologue expansion.  */
>-  if (flag_stack_usage_info)
>-    output_stack_usage ();
>+  if (flag_stack_usage_info || flag_callgraph_info)
>+    {
>+      output_stack_usage ();
>+      vec_free (cfun->su->dallocs);
>+      cfun->su->dallocs = NULL;
>+      vec_free (cfun->su->callees);
>+      cfun->su->callees = NULL;
>+    }
> 
>   return 0;
> }
> 
>+/* Record a final call to CALLEE at LOCATION.  */
>+
>+void
>+record_final_call (tree callee, location_t location)
>+{
>+  struct callee datum = { location, callee };
>+  vec_safe_push (cfun->su->callees, datum);
>+}
>+
>+/* Record a dynamic allocation made for DECL_OR_EXP.  */
>+
>+void
>+record_dynamic_alloc (tree decl_or_exp)
>+{
>+  struct dalloc datum;
>+
>+  if (DECL_P (decl_or_exp))
>+    {
>+      datum.location = DECL_SOURCE_LOCATION (decl_or_exp);
>+      const char *name = lang_hooks.decl_printable_name (decl_or_exp,
>2);
>+      const char *dot = strrchr (name, '.');
>+      if (dot)
>+	name = dot + 1;
>+      datum.name = ggc_strdup (name);
>+    }
>+  else
>+    {
>+      datum.location = EXPR_LOCATION (decl_or_exp);
>+      datum.name = NULL;
>+    }
>+  vec_safe_push (cfun->su->dallocs, datum);
>+}
>+
> namespace {
> 
> const pass_data pass_data_thread_prologue_and_epilogue =
>diff --git a/gcc/function.h b/gcc/function.h
>index 43ac5dffd2457..ec523765d6eec 100644
>--- a/gcc/function.h
>+++ b/gcc/function.h
>@@ -192,6 +192,18 @@ public:
>   poly_int64 length;
> };
> 
>+struct GTY(()) callee
>+{
>+  location_t location;
>+  tree decl;
>+};
>+
>+struct GTY(()) dalloc
>+{
>+  location_t location;
>+  char const *name;
>+};
>+
> class GTY(()) stack_usage
> {
> public:
>@@ -210,6 +222,13 @@ public:
>   /* Nonzero if the amount of stack space allocated dynamically cannot
>      be bounded at compile-time.  */
>   unsigned int has_unbounded_dynamic_stack_size : 1;
>+
>+  /* Functions called within the function, if callgraph is enabled. 
>*/
>+  vec<callee, va_gc> *callees;
>+
>+  /* Dynamic allocations enocuntered within the function, if callgraph
>+     da is enabled.  */
>+  vec<dalloc, va_gc> *dallocs;
> };
> 
>#define current_function_static_stack_size
>(cfun->su->static_stack_size)
>@@ -406,6 +425,12 @@ void add_local_decl (struct function *fun, tree
>d);
> #define FOR_EACH_LOCAL_DECL(FUN, I, D)		\
>   FOR_EACH_VEC_SAFE_ELT_REVERSE ((FUN)->local_decls, I, D)
> 
>+/* Record a final call to CALLEE at LOCATION.  */
>+void record_final_call (tree callee, location_t location);
>+
>+/* Record a dynamic allocation made for DECL_OR_EXP.  */
>+void record_dynamic_alloc (tree decl_or_exp);
>+
> /* If va_list_[gf]pr_size is set to this, it means we don't know how
>    many units need to be saved.  */
> #define VA_LIST_MAX_GPR_SIZE	255
>diff --git a/gcc/gimplify.c b/gcc/gimplify.c
>index 914bb8eb8d699..394f0fda9c98c 100644
>--- a/gcc/gimplify.c
>+++ b/gcc/gimplify.c
>@@ -1697,6 +1697,10 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
>   t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
> 
>   gimplify_and_add (t, seq_p);
>+
>+  /* Record the dynamic allocation associated with DECL if requested. 
>*/
>+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
>+    record_dynamic_alloc (decl);
> }
> 
>/* A helper function to be called via walk_tree.  Mark all labels under
>*TP
>diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c
>index ef43dae12fb64..8916f7e4da0bb 100644
>--- a/gcc/optabs-libfuncs.c
>+++ b/gcc/optabs-libfuncs.c
>@@ -735,10 +735,6 @@ build_libfunc_function_visibility (const char
>*name, symbol_visibility vis)
>   DECL_VISIBILITY_SPECIFIED (decl) = 1;
>   gcc_assert (DECL_ASSEMBLER_NAME (decl));
> 
>-  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left
>with
>-     are the flags assigned by targetm.encode_section_info.  */
>-  SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
>-
>   return decl;
> }
> 
>diff --git a/gcc/opts.c b/gcc/opts.c
>index 10b9f108f8d06..f46b468a968e7 100644
>--- a/gcc/opts.c
>+++ b/gcc/opts.c
>@@ -2433,6 +2433,32 @@ common_handle_option (struct gcc_options *opts,
>       /* Deferred.  */
>       break;
> 
>+    case OPT_fcallgraph_info:
>+      opts->x_flag_callgraph_info = CALLGRAPH_INFO_NAKED;
>+      break;
>+
>+    case OPT_fcallgraph_info_:
>+      {
>+	char *my_arg, *p;
>+	my_arg = xstrdup (arg);
>+	p = strtok (my_arg, ",");
>+	while (p)
>+	  {
>+	    if (strcmp (p, "su") == 0)
>+	      {
>+		opts->x_flag_callgraph_info |= CALLGRAPH_INFO_STACK_USAGE;
>+		opts->x_flag_stack_usage_info = true;
>+	      }
>+	    else if (strcmp (p, "da") == 0)
>+	      opts->x_flag_callgraph_info |= CALLGRAPH_INFO_DYNAMIC_ALLOC;
>+	    else
>+	      return 0;
>+	    p = strtok (NULL, ",");
>+	  }
>+	free (my_arg);
>+      }
>+      break;
>+
>     case OPT_fdiagnostics_show_location_:
>  diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value;
>       break;
>diff --git a/gcc/output.h b/gcc/output.h
>index 835d63556e6a8..6cccada4aeb1d 100644
>--- a/gcc/output.h
>+++ b/gcc/output.h
>@@ -604,7 +604,7 @@ extern int maybe_assemble_visibility (tree);
> 
>extern int default_address_cost (rtx, machine_mode, addr_space_t,
>bool);
> 
>-/* Output stack usage information.  */
>+/* Stack usage.  */
> extern void output_stack_usage (void);
> 
> #endif /* ! GCC_OUTPUT_H */
>diff --git a/gcc/print-tree.c b/gcc/print-tree.c
>index 6dcbb2dcb1369..bd09ec4d7a7af 100644
>--- a/gcc/print-tree.c
>+++ b/gcc/print-tree.c
>@@ -1035,6 +1035,82 @@ print_node (FILE *file, const char *prefix, tree
>node, int indent,
>   fprintf (file, ">");
> }
> 
>+/* Print the identifier for DECL according to FLAGS.  */
>+
>+void
>+print_decl_identifier (FILE *file, tree decl, int flags)
>+{
>+  bool needs_colon = false;
>+  const char *name;
>+  char c;
>+
>+  if (flags & PRINT_DECL_ORIGIN)
>+    {
>+      if (DECL_IS_BUILTIN (decl))
>+	fputs ("<built-in>", file);
>+      else
>+	{
>+	  expanded_location loc
>+	    = expand_location (DECL_SOURCE_LOCATION (decl));
>+	  fprintf (file, "%s:%d:%d", loc.file, loc.line, loc.column);
>+	}
>+      needs_colon = true;
>+    }
>+
>+  if (flags & PRINT_DECL_UNIQUE_NAME)
>+    {
>+      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
>+      if (!TREE_PUBLIC (decl)
>+	  || (DECL_WEAK (decl) && !DECL_EXTERNAL (decl)))
>+	/* The symbol has internal or weak linkage so its assembler name
>+	   is not necessarily unique among the compilation units of the
>+	   program.  We therefore have to further mangle it.  But we can't
>+	   simply use DECL_SOURCE_FILE because it contains the name of the
>+	   file the symbol originates from so, e.g. for function templates
>+	   in C++ where the templates are defined in a header file, we can
>+	   have symbols with the same assembler name and DECL_SOURCE_FILE.
>+	   That's why we use the name of the top-level source file of the
>+	   compilation unit.  ??? Unnecessary for Ada.  */
>+	name = ACONCAT ((main_input_filename, ":", name, NULL));
>+    }
>+  else if (flags & PRINT_DECL_NAME)
>+    {
>+      /* We don't want to print the full qualified name because it can
>be long,
>+	 so we strip the scope prefix, but we may need to deal with the
>suffix
>+	 created by the compiler.  */
>+      const char *suffix = strchr (IDENTIFIER_POINTER (DECL_NAME
>(decl)), '.');
>+      name = lang_hooks.decl_printable_name (decl, 2);
>+      if (suffix)
>+	{
>+	  const char *dot = strchr (name, '.');
>+	  while (dot && strcasecmp (dot, suffix) != 0)
>+	    {
>+	      name = dot + 1;
>+	      dot = strchr (name, '.');
>+	    }
>+	}
>+      else
>+	{
>+	  const char *dot = strrchr (name, '.');
>+	  if (dot)
>+	    name = dot + 1;
>+	}
>+    }
>+  else
>+    return;
>+
>+  if (needs_colon)
>+    fputc (':', file);
>+
>+  while ((c = *name++) != '\0')
>+    {
>+      /* Strip double-quotes because of VCG.  */
>+      if (c == '"')
>+	continue;
>+      fputc (c, file);
>+    }
>+}
>+
> 
> /* Print the node NODE on standard error, for debugging.
>    Most nodes referred to by this one are printed recursively
>diff --git a/gcc/print-tree.h b/gcc/print-tree.h
>index 1d4fe6e8950cc..cbea48c486e3c 100644
>--- a/gcc/print-tree.h
>+++ b/gcc/print-tree.h
>@@ -42,5 +42,9 @@ extern void print_node (FILE *, const char *, tree,
>int,
> extern void print_node_brief (FILE *, const char *, const_tree, int);
> extern void indent_to (FILE *, int);
> #endif
>+#define PRINT_DECL_ORIGIN       0x1
>+#define PRINT_DECL_NAME         0x2
>+#define PRINT_DECL_UNIQUE_NAME  0x4
>+extern void print_decl_identifier (FILE *, tree, int flags);
> 
> #endif  // GCC_PRINT_TREE_H
>diff --git a/gcc/toplev.c b/gcc/toplev.c
>index 1c7002f5c37cd..016f6d688f324 100644
>--- a/gcc/toplev.c
>+++ b/gcc/toplev.c
>@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  If not see
> #include "dumpfile.h"
> #include "ipa-fnsummary.h"
> #include "dump-context.h"
>+#include "print-tree.h"
> #include "optinfo-emit-json.h"
> 
> #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
>@@ -174,6 +175,8 @@ const char *user_label_prefix;
> 
> FILE *asm_out_file;
> FILE *aux_info_file;
>+FILE *callgraph_info_file = NULL;
>+static bool callgraph_info_indirect_emitted = false;
> FILE *stack_usage_file = NULL;
> 
> /* The current working directory of a translation.  It's generally the
>@@ -913,8 +916,8 @@ alloc_for_identifier_to_locale (size_t len)
> }
> 
> /* Output stack usage information.  */
>-void
>-output_stack_usage (void)
>+static void
>+output_stack_usage_1 (FILE *cf)
> {
>   static bool warning_issued = false;
>   enum stack_usage_kind_type { STATIC = 0, DYNAMIC, DYNAMIC_BOUNDED };
>@@ -970,41 +973,22 @@ output_stack_usage (void)
>       stack_usage += current_function_dynamic_stack_size;
>     }
> 
>-  if (stack_usage_file)
>+  if (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE)
>     {
>-      expanded_location loc
>-	= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
>-      /* We don't want to print the full qualified name because it can
>be long,
>-	 so we strip the scope prefix, but we may need to deal with the
>suffix
>-	 created by the compiler.  */
>-      const char *suffix
>-	= strchr (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
>'.');
>-      const char *name
>-	= lang_hooks.decl_printable_name (current_function_decl, 2);
>-      if (suffix)
>-	{
>-	  const char *dot = strchr (name, '.');
>-	  while (dot && strcasecmp (dot, suffix) != 0)
>-	    {
>-	      name = dot + 1;
>-	      dot = strchr (name, '.');
>-	    }
>-	}
>+      if (stack_usage)
>+	fprintf (cf, "\\n" HOST_WIDE_INT_PRINT_DEC " bytes (%s)",
>+		 stack_usage,
>+		 stack_usage_kind_str[stack_usage_kind]);
>       else
>-	{
>-	  const char *dot = strrchr (name, '.');
>-	  if (dot)
>-	    name = dot + 1;
>-	}
>+	fputs ("\\n0 bytes", cf);
>+    }
> 
>-      fprintf (stack_usage_file,
>-	       "%s:%d:%d:%s\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
>-	       loc.file == NULL ? "(artificial)" : lbasename (loc.file),
>-	       loc.line,
>-	       loc.column,
>-	       name,
>-	       stack_usage,
>-	       stack_usage_kind_str[stack_usage_kind]);
>+  if (stack_usage_file)
>+    {
>+      print_decl_identifier (stack_usage_file, current_function_decl,
>+			     PRINT_DECL_ORIGIN | PRINT_DECL_NAME);
>+      fprintf (stack_usage_file, "\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
>+	       stack_usage, stack_usage_kind_str[stack_usage_kind]);
>     }
> 
>   if (warn_stack_usage >= 0 && warn_stack_usage < HOST_WIDE_INT_MAX)
>@@ -1026,6 +1010,106 @@ output_stack_usage (void)
>     }
> }
> 
>+/* Dump placeholder node for indirect calls in VCG format.  */
>+
>+#define INDIRECT_CALL_NAME  "__indirect_call"
>+
>+static void
>+dump_final_indirect_call_node_vcg (FILE *f)
>+{
>+  if (callgraph_info_indirect_emitted)
>+    return;
>+
>+  fputs ("node: { title: \"", f);
>+  fputs (INDIRECT_CALL_NAME, f);
>+  fputs ("\" label: \"", f);
>+  fputs ("Indirect Call Placeholder", f);
>+  fputs ("\" shape : ellipse }\n", f);
>+  callgraph_info_indirect_emitted = true;
>+}
>+
>+/* Dump final cgraph edge in VCG format.  */
>+
>+static void
>+dump_final_callee_vcg (FILE *f, struct callee *callee)
>+{
>+  fputs ("edge: { sourcename: \"", f);
>+  print_decl_identifier (f, current_function_decl,
>PRINT_DECL_UNIQUE_NAME);
>+  fputs ("\" targetname: \"", f);
>+  if (callee->decl)
>+    print_decl_identifier (f, callee->decl, PRINT_DECL_UNIQUE_NAME);
>+  else
>+    fputs (INDIRECT_CALL_NAME, f);
>+  if (LOCATION_LOCUS (callee->location) != UNKNOWN_LOCATION)
>+    {
>+      expanded_location loc;
>+      fputs ("\" label: \"", f);
>+      loc = expand_location (callee->location);
>+      fprintf (f, "%s:%d:%d", loc.file, loc.line, loc.column);
>+    }
>+  fputs ("\" }\n", f);
>+
>+  if (!callee->decl)
>+    dump_final_indirect_call_node_vcg (f);
>+}
>+
>+/* Dump final cgraph node in VCG format.  */
>+
>+static void
>+dump_final_node_vcg (FILE *f)
>+{
>+  fputs ("node: { title: \"", f);
>+  print_decl_identifier (f, current_function_decl,
>PRINT_DECL_UNIQUE_NAME);
>+  fputs ("\" label: \"", f);
>+  print_decl_identifier (f, current_function_decl, PRINT_DECL_NAME);
>+  fputs ("\\n", f);
>+  print_decl_identifier (f, current_function_decl, PRINT_DECL_ORIGIN);
>+
>+  if (DECL_EXTERNAL (current_function_decl))
>+    {
>+      fputs ("\" shape : ellipse }\n", f);
>+      return;
>+    }
>+
>+  if (flag_stack_usage_info
>+      || (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE))
>+    output_stack_usage_1 (f);
>+
>+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
>+    {
>+      fprintf (f, "\\n%u dynamic objects", vec_safe_length
>(cfun->su->dallocs));
>+
>+      unsigned i;
>+      dalloc *cda;
>+      FOR_EACH_VEC_SAFE_ELT (cfun->su->dallocs, i, cda)
>+	{
>+	  expanded_location loc = expand_location (cda->location);
>+	  fprintf (f, "\\n %s", cda->name);
>+	  fprintf (f, " %s:%d:%d", loc.file, loc.line, loc.column);
>+	}
>+    }
>+
>+  fputs ("\" }\n", f);
>+
>+  if (flag_callgraph_info)
>+    {
>+      unsigned i;
>+      callee *c;
>+      FOR_EACH_VEC_SAFE_ELT (cfun->su->callees, i, c)
>+	dump_final_callee_vcg (f, c);
>+    }
>+}
>+
>+/* Output stack usage and callgraph info, as requested.  */
>+void
>+output_stack_usage (void)
>+{
>+  if (flag_callgraph_info)
>+    dump_final_node_vcg (callgraph_info_file);
>+  else
>+    output_stack_usage_1 (NULL);
>+}
>+
> /* Open an auxiliary output file.  */
> static FILE *
> open_auxiliary_file (const char *ext)
>@@ -1900,6 +1984,15 @@ lang_dependent_init (const char *name)
>    /* If stack usage information is desired, open the output file.  */
>       if (flag_stack_usage && !flag_generate_lto)
> 	stack_usage_file = open_auxiliary_file ("su");
>+
>+      /* If call graph information is desired, open the output file. 
>*/
>+      if (flag_callgraph_info && !flag_generate_lto)
>+	{
>+	  callgraph_info_file = open_auxiliary_file ("ci");
>+	  /* Write the file header.  */
>+	  fprintf (callgraph_info_file,
>+		   "graph: { title: \"%s\"\n", main_input_filename);
>+	}
>     }
> 
>   /* This creates various _DECL nodes, so needs to be called after the
>@@ -2044,6 +2137,14 @@ finalize (bool no_backend)
>       stack_usage_file = NULL;
>     }
> 
>+  if (callgraph_info_file)
>+    {
>+      fputs ("}\n", callgraph_info_file);
>+      fclose (callgraph_info_file);
>+      callgraph_info_file = NULL;
>+      callgraph_info_indirect_emitted = false;
>+    }
>+
>   if (seen_error ())
>     coverage_remove_note_file ();
>
Alexandre Oliva Oct. 26, 2019, 8:57 a.m. UTC | #2
Hi, Richi,

On Oct 26, 2019, Richard Biener <rguenther@suse.de> wrote:

> How does it relate to the LTO-dump utility we have now which can in
> theory provide a more complete view?

Erhm...  Not at all, AFAICT.  The only vague resemblance I see is in the
presence of the word "callgraph" in the description of what both can do,
but even that's not quite the same callgraph, besides the different
format.

E.g., the reason we gather expanded calls rather than just use
cgraph_edges is that the latter would dump several "calls" that are
builtins expanded internally by the compiler, and would NOT dump other
ops that are expanded as (lib)calls.  In order to get an accurate
assessment of stack size requirements, the presence of the builtins
could be confusing but not so much trouble, but the absence of libcalls
would underestimate the potential max total stack use by a symbol.

> Maybe some infrastructure can be
> shared here (the actual dumping of the cgraph?)

You mean the one-liner loop in cgraph_node::dump_graphviz, called by
lto-dump to dump the cgraph?  That doesn't really seem worth sharing;
more so considering we dump edges in a quite different format, and not
just the edges.  In this different format expected by gnatstack, we also
dump the nodes, and include information in the labels of the nodes, such
as their original spelling and location, as well as stack use:

node: { title: "_ada_p" label: "P\np.adb:1:1\n48 bytes (static)" }

and dynamic stack allocations (alloca and vlas):

node: { title: "p.adb:p__u" label: "u\np.adb:21:3\n2 dynamic objects\n rt p.adb:23:5\n ri p.adb:24:5" }

and though edges to libcalls may carry just as little info as a graphviz
"from" -> "to" edge:

edge: { sourcename: "add" targetname: "__addvsi3" }

those between user symbols carry location info as well:

edge: { sourcename: "p__s" targetname: "p.adb:p__v" label: "p.adb:46:5" }

So I'm afraid I don't see anything that could be usefully factored out.
Do you?

Thanks,
Alexandre Oliva Oct. 27, 2019, 8:16 a.m. UTC | #3
On Oct 26, 2019, Alexandre Oliva <oliva@adacore.com> wrote:

> E.g., the reason we gather expanded calls rather than just use
> cgraph_edges is that the latter would dump several "calls" that are
> builtins expanded internally by the compiler, and would NOT dump other
> ops that are expanded as (lib)calls.

It occurred to me that we could reuse most cgraph edges and avoid
duplicating them in the callees vec, namely those that aren't builtins
or libcalls.  Those that are builtins might or might not become actual
calls, so we disregard the cgraph_edges and record them in the vec
instead.  Those that are libcalls (builtins in a different sense)
introduced during expand are not even present in the cgraph edges, so we
record them in the vec as well.  Here's the patch that implements this.

Regstrapped on x86_64-linux-gnu.  Ok to install?

for  gcc/ChangeLog
From  Eric Botcazou  <ebotcazou@adacore.com>, Alexandre Oliva  <oliva@adacore.com>

	* common.opt (-fcallgraph-info[=]): New option.
	* doc/invoke.texi (Debugging options): Document it.
	* opts.c (common_handle_option): Handle it.
	* builtins.c (expand_builtin_alloca): Record allocation if
	-fcallgraph-info=da.
	* calls.c (expand_call): If -fcallgraph-info, record the call.
	(emit_library_call_value_1): Likewise.
	* flag-types.h (enum callgraph_info_type): New type.
	* explow.c: Include stringpool.h.
	(set_stack_check_libfunc): Set SET_SYMBOL_REF_DECL on the symbol.
	* function.c (allocate_stack_usage_info): New.
	(allocate_struct_function): Call it for -fcallgraph-info.
	(prepare_function_start): Call it otherwise.
	(record_final_call, record_dynamic_alloc): New.
	* function.h (struct callinfo_callee): New.
	(CALLEE_FROM_CGRAPH_P): New.
	(struct callinfo_dalloc): New.
	(struct stack_usage): Add callees and dallocs.
	(record_final_call, record_dynamic_alloc): Declare.
	* gimplify.c (gimplify_decl_expr): Record dynamically-allocated
	object if -fcallgraph-info=da.
	* optabs-libfuncs.c (build_libfunc_function): Keep SYMBOL_REF_DECL.
	* print-tree.h (print_decl_identifier): Declare.
	(PRINT_DECL_ORIGIN, PRINT_DECL_NAME, PRINT_DECL_UNIQUE_NAME): New.
	* print-tree.c: Include print-tree.h.
	(print_decl_identifier): New function.
	* toplev.c: Include print-tree.h.
	(callgraph_info_file): New global variable.
	(callgraph_info_indirect_emitted): Likewise.
	(output_stack_usage): Rename to...
	(output_stack_usage_1): ... this.  Make it static, add cf
	parameter.  If -fcallgraph-info=su, print stack usage to cf.
	If -fstack-usage, use print_decl_identifier for
	pretty-printing.
	(INDIRECT_CALL_NAME): New.
	(dump_final_indirect_call_node_vcg): New.
	(dump_final_callee_vcg, dump_final_node_vcg): New.
	(output_stack_usage): New.
	(lang_dependent_init): Open and start file if
	-fcallgraph-info.
	(finalize): If callgraph_info_file is not null, finish it,
	close it, and reset callgraph info state.

for  gcc/ada/ChangeLog

	* gcc-interface/misc.c (callgraph_info_file): Delete.
---
 gcc/ada/gcc-interface/misc.c |    3 -
 gcc/builtins.c               |    4 +
 gcc/calls.c                  |    6 +
 gcc/common.opt               |    8 ++
 gcc/doc/invoke.texi          |   17 ++++
 gcc/explow.c                 |    5 +
 gcc/flag-types.h             |   16 ++++
 gcc/function.c               |   59 ++++++++++++--
 gcc/function.h               |   30 +++++++
 gcc/gimplify.c               |    4 +
 gcc/optabs-libfuncs.c        |    4 -
 gcc/opts.c                   |   26 ++++++
 gcc/output.h                 |    2 
 gcc/print-tree.c             |   76 ++++++++++++++++++
 gcc/print-tree.h             |    4 +
 gcc/toplev.c                 |  179 ++++++++++++++++++++++++++++++++++--------
 16 files changed, 393 insertions(+), 50 deletions(-)

diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 4abd4d5708a54..d68b37384ff7f 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -54,9 +54,6 @@
 #include "ada-tree.h"
 #include "gigi.h"
 
-/* This symbol needs to be defined for the front-end.  */
-void *callgraph_info_file = NULL;
-
 /* Command-line argc and argv.  These variables are global since they are
    imported in back_end.adb.  */
 unsigned int save_argc;
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5d811f113c907..bd302383377ba 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5406,6 +5406,10 @@ expand_builtin_alloca (tree exp)
     = allocate_dynamic_stack_space (op0, 0, align, max_size, alloca_for_var);
   result = convert_memory_address (ptr_mode, result);
 
+  /* Dynamic allocations for variables are recorded during gimplification.  */
+  if (!alloca_for_var && (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC))
+    record_dynamic_alloc (exp);
+
   return result;
 }
 
diff --git a/gcc/calls.c b/gcc/calls.c
index ae904473d0dc6..67c7c77598a3f 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -3759,6 +3759,9 @@ expand_call (tree exp, rtx target, int ignore)
 
   preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
 
+  if (flag_callgraph_info)
+    record_final_call (fndecl, EXPR_LOCATION (exp));
+
   /* We want to make two insn chains; one for a sibling call, the other
      for a normal call.  We will select one of the two chains after
      initial RTL generation is complete.  */
@@ -5343,6 +5346,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
   before_call = get_last_insn ();
 
+  if (flag_callgraph_info)
+    record_final_call (SYMBOL_REF_DECL (orgfun), UNKNOWN_LOCATION);
+
   /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
      will set inhibit_defer_pop to that value.  */
   /* The return type is needed to decide how many bytes the function pops.
diff --git a/gcc/common.opt b/gcc/common.opt
index cc279f411d796..63d646fba2b42 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1091,6 +1091,14 @@ fbtr-bb-exclusive
 Common Ignore
 Does nothing.  Preserved for backward compatibility.
 
+fcallgraph-info
+Common Report RejectNegative Var(flag_callgraph_info) Init(NO_CALLGRAPH_INFO);
+Output callgraph information on a per-file basis
+
+fcallgraph-info=
+Common Report RejectNegative Joined
+Output callgraph information on a per-file basis with decorations
+
 fcall-saved-
 Common Joined RejectNegative Var(common_deferred_options) Defer
 -fcall-saved-<register>	Mark <register> as being preserved across functions.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1407d019d1404..545b842eade71 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -583,8 +583,9 @@ Objective-C and Objective-C++ Dialects}.
 @item Developer Options
 @xref{Developer Options,,GCC Developer Options}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
--dumpfullversion  -fchecking  -fchecking=@var{n}  -fdbg-cnt-list @gol
--fdbg-cnt=@var{counter-value-list} @gol
+-dumpfullversion  -fcallgraph-info@r{[}=su,da@r{]}
+-fchecking  -fchecking=@var{n}
+-fdbg-cnt-list @gol  -fdbg-cnt=@var{counter-value-list} @gol
 -fdisable-ipa-@var{pass_name} @gol
 -fdisable-rtl-@var{pass_name} @gol
 -fdisable-rtl-@var{pass-name}=@var{range-list} @gol
@@ -14533,6 +14534,18 @@ The files are created in the directory of the output file.
 
 @table @gcctabopt
 
+@item -fcallgraph-info
+@itemx -fcallgraph-info=@var{MARKERS}
+@opindex fcallgraph-info
+Makes the compiler output callgraph information for the program, on a
+per-file basis.  The information is generated in the common VCG format.
+It can be decorated with additional, per-node and/or per-edge information,
+if a list of comma-separated markers is additionally specified.  When the
+@code{su} marker is specified, the callgraph is decorated with stack usage
+information; it is equivalent to @option{-fstack-usage}.  When the @code{da}
+marker is specified, the callgraph is decorated with information about
+dynamically allocated objects.
+
 @item -d@var{letters}
 @itemx -fdump-rtl-@var{pass}
 @itemx -fdump-rtl-@var{pass}=@var{filename}
diff --git a/gcc/explow.c b/gcc/explow.c
index 7eb854bca4a6d..83c786366c1aa 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dojump.h"
 #include "explow.h"
 #include "expr.h"
+#include "stringpool.h"
 #include "common/common-target.h"
 #include "output.h"
 #include "params.h"
@@ -1611,6 +1612,10 @@ set_stack_check_libfunc (const char *libfunc_name)
 {
   gcc_assert (stack_check_libfunc == NULL_RTX);
   stack_check_libfunc = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
+  tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+			  get_identifier (libfunc_name), void_type_node);
+  DECL_EXTERNAL (decl) = 1;
+  SET_SYMBOL_REF_DECL (stack_check_libfunc, decl);
 }
 
 /* Emit one stack probe at ADDRESS, an address within the stack.  */
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index a2103282d469d..b23d3a271f1ee 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -200,6 +200,22 @@ enum stack_check_type
   FULL_BUILTIN_STACK_CHECK
 };
 
+/* Type of callgraph information.  */
+enum callgraph_info_type
+{
+  /* No information.  */
+  NO_CALLGRAPH_INFO = 0,
+
+  /* Naked callgraph.  */
+  CALLGRAPH_INFO_NAKED = 1,
+
+  /* Callgraph decorated with stack usage information.  */
+  CALLGRAPH_INFO_STACK_USAGE = 2,
+
+  /* Callgraph decoration with dynamic allocation information.  */
+  CALLGRAPH_INFO_DYNAMIC_ALLOC = 4
+};
+
 /* Floating-point contraction mode.  */
 enum fp_contract_mode {
   FP_CONTRACT_OFF = 0,
diff --git a/gcc/function.c b/gcc/function.c
index a1c76a4dd7a84..3f79a38aeaec8 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4725,6 +4725,16 @@ get_last_funcdef_no (void)
   return funcdef_no;
 }
 
+/* Allocate and initialize the stack usage info data structure for the
+   current function.  */
+static void
+allocate_stack_usage_info (void)
+{
+  gcc_assert (!cfun->su);
+  cfun->su = ggc_cleared_alloc<stack_usage> ();
+  cfun->su->static_stack_size = -1;
+}
+
 /* Allocate a function structure for FNDECL and set its contents
    to the defaults.  Set cfun to the newly-allocated object.
    Some of the helper functions invoked during initialization assume
@@ -4802,6 +4812,9 @@ allocate_struct_function (tree fndecl, bool abstract_p)
 
       if (!profile_flag && !flag_instrument_function_entry_exit)
 	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
+
+      if (flag_callgraph_info)
+	allocate_stack_usage_info ();
     }
 
   /* Don't enable begin stmt markers if var-tracking at assignments is
@@ -4846,11 +4859,8 @@ prepare_function_start (void)
   init_expr ();
   default_rtl_profile ();
 
-  if (flag_stack_usage_info)
-    {
-      cfun->su = ggc_cleared_alloc<stack_usage> ();
-      cfun->su->static_stack_size = -1;
-    }
+  if (flag_stack_usage_info && !flag_callgraph_info)
+    allocate_stack_usage_info ();
 
   cse_not_expected = ! optimize;
 
@@ -6373,12 +6383,49 @@ rest_of_handle_thread_prologue_and_epilogue (void)
   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
 
   /* The stack usage info is finalized during prologue expansion.  */
-  if (flag_stack_usage_info)
+  if (flag_stack_usage_info || flag_callgraph_info)
     output_stack_usage ();
 
   return 0;
 }
 
+/* Record a final call to CALLEE at LOCATION.  */
+
+void
+record_final_call (tree callee, location_t location)
+{
+  if (!callee || CALLEE_FROM_CGRAPH_P (callee))
+    return;
+
+  struct callinfo_callee datum = { location, callee };
+  vec_safe_push (cfun->su->callees, datum);
+}
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+
+void
+record_dynamic_alloc (tree decl_or_exp)
+{
+  struct callinfo_dalloc datum;
+
+  if (DECL_P (decl_or_exp))
+    {
+      datum.location = DECL_SOURCE_LOCATION (decl_or_exp);
+      const char *name = lang_hooks.decl_printable_name (decl_or_exp, 2);
+      const char *dot = strrchr (name, '.');
+      if (dot)
+	name = dot + 1;
+      datum.name = ggc_strdup (name);
+    }
+  else
+    {
+      datum.location = EXPR_LOCATION (decl_or_exp);
+      datum.name = NULL;
+    }
+
+  vec_safe_push (cfun->su->dallocs, datum);
+}
+
 namespace {
 
 const pass_data pass_data_thread_prologue_and_epilogue =
diff --git a/gcc/function.h b/gcc/function.h
index 43ac5dffd2457..14794c420a215 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -192,6 +192,23 @@ public:
   poly_int64 length;
 };
 
+/* Describe emitted builtin calls for -fcallgraph-info.  Those that
+   are not builtin are taken from cgraph edges.  */
+struct GTY(()) callinfo_callee
+{
+  location_t location;
+  tree decl;
+};
+#define CALLEE_FROM_CGRAPH_P(T)				\
+  (!fndecl_built_in_p (T) && !DECL_IS_BUILTIN (T))
+
+/* Describe dynamic allocation for -fcallgraph-info=da.  */
+struct GTY(()) callinfo_dalloc
+{
+  location_t location;
+  char const *name;
+};
+
 class GTY(()) stack_usage
 {
 public:
@@ -210,6 +227,13 @@ public:
   /* Nonzero if the amount of stack space allocated dynamically cannot
      be bounded at compile-time.  */
   unsigned int has_unbounded_dynamic_stack_size : 1;
+
+  /* Functions called within the function, if callgraph is enabled.  */
+  vec<callinfo_callee, va_gc> *callees;
+
+  /* Dynamic allocations encountered within the function, if callgraph
+     da is enabled.  */
+  vec<callinfo_dalloc, va_gc> *dallocs;
 };
 
 #define current_function_static_stack_size (cfun->su->static_stack_size)
@@ -406,6 +430,12 @@ void add_local_decl (struct function *fun, tree d);
 #define FOR_EACH_LOCAL_DECL(FUN, I, D)		\
   FOR_EACH_VEC_SAFE_ELT_REVERSE ((FUN)->local_decls, I, D)
 
+/* Record a final call to CALLEE at LOCATION.  */
+void record_final_call (tree callee, location_t location);
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+void record_dynamic_alloc (tree decl_or_exp);
+
 /* If va_list_[gf]pr_size is set to this, it means we don't know how
    many units need to be saved.  */
 #define VA_LIST_MAX_GPR_SIZE	255
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 914bb8eb8d699..394f0fda9c98c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1697,6 +1697,10 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
   t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
 
   gimplify_and_add (t, seq_p);
+
+  /* Record the dynamic allocation associated with DECL if requested.  */
+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+    record_dynamic_alloc (decl);
 }
 
 /* A helper function to be called via walk_tree.  Mark all labels under *TP
diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c
index ef43dae12fb64..8916f7e4da0bb 100644
--- a/gcc/optabs-libfuncs.c
+++ b/gcc/optabs-libfuncs.c
@@ -735,10 +735,6 @@ build_libfunc_function_visibility (const char *name, symbol_visibility vis)
   DECL_VISIBILITY_SPECIFIED (decl) = 1;
   gcc_assert (DECL_ASSEMBLER_NAME (decl));
 
-  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
-     are the flags assigned by targetm.encode_section_info.  */
-  SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
-
   return decl;
 }
 
diff --git a/gcc/opts.c b/gcc/opts.c
index 10b9f108f8d06..f46b468a968e7 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2433,6 +2433,32 @@ common_handle_option (struct gcc_options *opts,
       /* Deferred.  */
       break;
 
+    case OPT_fcallgraph_info:
+      opts->x_flag_callgraph_info = CALLGRAPH_INFO_NAKED;
+      break;
+
+    case OPT_fcallgraph_info_:
+      {
+	char *my_arg, *p;
+	my_arg = xstrdup (arg);
+	p = strtok (my_arg, ",");
+	while (p)
+	  {
+	    if (strcmp (p, "su") == 0)
+	      {
+		opts->x_flag_callgraph_info |= CALLGRAPH_INFO_STACK_USAGE;
+		opts->x_flag_stack_usage_info = true;
+	      }
+	    else if (strcmp (p, "da") == 0)
+	      opts->x_flag_callgraph_info |= CALLGRAPH_INFO_DYNAMIC_ALLOC;
+	    else
+	      return 0;
+	    p = strtok (NULL, ",");
+	  }
+	free (my_arg);
+      }
+      break;
+
     case OPT_fdiagnostics_show_location_:
       diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value;
       break;
diff --git a/gcc/output.h b/gcc/output.h
index 835d63556e6a8..6cccada4aeb1d 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -604,7 +604,7 @@ extern int maybe_assemble_visibility (tree);
 
 extern int default_address_cost (rtx, machine_mode, addr_space_t, bool);
 
-/* Output stack usage information.  */
+/* Stack usage.  */
 extern void output_stack_usage (void);
 
 #endif /* ! GCC_OUTPUT_H */
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 6dcbb2dcb1369..bd09ec4d7a7af 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -1035,6 +1035,82 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
   fprintf (file, ">");
 }
 
+/* Print the identifier for DECL according to FLAGS.  */
+
+void
+print_decl_identifier (FILE *file, tree decl, int flags)
+{
+  bool needs_colon = false;
+  const char *name;
+  char c;
+
+  if (flags & PRINT_DECL_ORIGIN)
+    {
+      if (DECL_IS_BUILTIN (decl))
+	fputs ("<built-in>", file);
+      else
+	{
+	  expanded_location loc
+	    = expand_location (DECL_SOURCE_LOCATION (decl));
+	  fprintf (file, "%s:%d:%d", loc.file, loc.line, loc.column);
+	}
+      needs_colon = true;
+    }
+
+  if (flags & PRINT_DECL_UNIQUE_NAME)
+    {
+      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+      if (!TREE_PUBLIC (decl)
+	  || (DECL_WEAK (decl) && !DECL_EXTERNAL (decl)))
+	/* The symbol has internal or weak linkage so its assembler name
+	   is not necessarily unique among the compilation units of the
+	   program.  We therefore have to further mangle it.  But we can't
+	   simply use DECL_SOURCE_FILE because it contains the name of the
+	   file the symbol originates from so, e.g. for function templates
+	   in C++ where the templates are defined in a header file, we can
+	   have symbols with the same assembler name and DECL_SOURCE_FILE.
+	   That's why we use the name of the top-level source file of the
+	   compilation unit.  ??? Unnecessary for Ada.  */
+	name = ACONCAT ((main_input_filename, ":", name, NULL));
+    }
+  else if (flags & PRINT_DECL_NAME)
+    {
+      /* We don't want to print the full qualified name because it can be long,
+	 so we strip the scope prefix, but we may need to deal with the suffix
+	 created by the compiler.  */
+      const char *suffix = strchr (IDENTIFIER_POINTER (DECL_NAME (decl)), '.');
+      name = lang_hooks.decl_printable_name (decl, 2);
+      if (suffix)
+	{
+	  const char *dot = strchr (name, '.');
+	  while (dot && strcasecmp (dot, suffix) != 0)
+	    {
+	      name = dot + 1;
+	      dot = strchr (name, '.');
+	    }
+	}
+      else
+	{
+	  const char *dot = strrchr (name, '.');
+	  if (dot)
+	    name = dot + 1;
+	}
+    }
+  else
+    return;
+
+  if (needs_colon)
+    fputc (':', file);
+
+  while ((c = *name++) != '\0')
+    {
+      /* Strip double-quotes because of VCG.  */
+      if (c == '"')
+	continue;
+      fputc (c, file);
+    }
+}
+
 
 /* Print the node NODE on standard error, for debugging.
    Most nodes referred to by this one are printed recursively
diff --git a/gcc/print-tree.h b/gcc/print-tree.h
index 1d4fe6e8950cc..cbea48c486e3c 100644
--- a/gcc/print-tree.h
+++ b/gcc/print-tree.h
@@ -42,5 +42,9 @@ extern void print_node (FILE *, const char *, tree, int,
 extern void print_node_brief (FILE *, const char *, const_tree, int);
 extern void indent_to (FILE *, int);
 #endif
+#define PRINT_DECL_ORIGIN       0x1
+#define PRINT_DECL_NAME         0x2
+#define PRINT_DECL_UNIQUE_NAME  0x4
+extern void print_decl_identifier (FILE *, tree, int flags);
 
 #endif  // GCC_PRINT_TREE_H
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 1c7002f5c37cd..4589bc09fb0c7 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dumpfile.h"
 #include "ipa-fnsummary.h"
 #include "dump-context.h"
+#include "print-tree.h"
 #include "optinfo-emit-json.h"
 
 #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
@@ -174,6 +175,8 @@ const char *user_label_prefix;
 
 FILE *asm_out_file;
 FILE *aux_info_file;
+FILE *callgraph_info_file = NULL;
+static bool callgraph_info_indirect_emitted = false;
 FILE *stack_usage_file = NULL;
 
 /* The current working directory of a translation.  It's generally the
@@ -913,8 +916,8 @@ alloc_for_identifier_to_locale (size_t len)
 }
 
 /* Output stack usage information.  */
-void
-output_stack_usage (void)
+static void
+output_stack_usage_1 (FILE *cf)
 {
   static bool warning_issued = false;
   enum stack_usage_kind_type { STATIC = 0, DYNAMIC, DYNAMIC_BOUNDED };
@@ -970,41 +973,22 @@ output_stack_usage (void)
       stack_usage += current_function_dynamic_stack_size;
     }
 
-  if (stack_usage_file)
+  if (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE)
     {
-      expanded_location loc
-	= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
-      /* We don't want to print the full qualified name because it can be long,
-	 so we strip the scope prefix, but we may need to deal with the suffix
-	 created by the compiler.  */
-      const char *suffix
-	= strchr (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), '.');
-      const char *name
-	= lang_hooks.decl_printable_name (current_function_decl, 2);
-      if (suffix)
-	{
-	  const char *dot = strchr (name, '.');
-	  while (dot && strcasecmp (dot, suffix) != 0)
-	    {
-	      name = dot + 1;
-	      dot = strchr (name, '.');
-	    }
-	}
+      if (stack_usage)
+	fprintf (cf, "\\n" HOST_WIDE_INT_PRINT_DEC " bytes (%s)",
+		 stack_usage,
+		 stack_usage_kind_str[stack_usage_kind]);
       else
-	{
-	  const char *dot = strrchr (name, '.');
-	  if (dot)
-	    name = dot + 1;
-	}
+	fputs ("\\n0 bytes", cf);
+    }
 
-      fprintf (stack_usage_file,
-	       "%s:%d:%d:%s\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
-	       loc.file == NULL ? "(artificial)" : lbasename (loc.file),
-	       loc.line,
-	       loc.column,
-	       name,
-	       stack_usage,
-	       stack_usage_kind_str[stack_usage_kind]);
+  if (stack_usage_file)
+    {
+      print_decl_identifier (stack_usage_file, current_function_decl,
+			     PRINT_DECL_ORIGIN | PRINT_DECL_NAME);
+      fprintf (stack_usage_file, "\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
+	       stack_usage, stack_usage_kind_str[stack_usage_kind]);
     }
 
   if (warn_stack_usage >= 0 && warn_stack_usage < HOST_WIDE_INT_MAX)
@@ -1026,6 +1010,116 @@ output_stack_usage (void)
     }
 }
 
+/* Dump placeholder node for indirect calls in VCG format.  */
+
+#define INDIRECT_CALL_NAME  "__indirect_call"
+
+static void
+dump_final_indirect_call_node_vcg (FILE *f)
+{
+  if (callgraph_info_indirect_emitted)
+    return;
+
+  fputs ("node: { title: \"", f);
+  fputs (INDIRECT_CALL_NAME, f);
+  fputs ("\" label: \"", f);
+  fputs ("Indirect Call Placeholder", f);
+  fputs ("\" shape : ellipse }\n", f);
+  callgraph_info_indirect_emitted = true;
+}
+
+/* Dump final cgraph edge in VCG format.  */
+
+static void
+dump_final_callee_vcg (FILE *f, location_t location, tree callee)
+{
+  fputs ("edge: { sourcename: \"", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_UNIQUE_NAME);
+  fputs ("\" targetname: \"", f);
+  if (callee)
+    print_decl_identifier (f, callee, PRINT_DECL_UNIQUE_NAME);
+  else
+    fputs (INDIRECT_CALL_NAME, f);
+  if (LOCATION_LOCUS (location) != UNKNOWN_LOCATION)
+    {
+      expanded_location loc;
+      fputs ("\" label: \"", f);
+      loc = expand_location (location);
+      fprintf (f, "%s:%d:%d", loc.file, loc.line, loc.column);
+    }
+  fputs ("\" }\n", f);
+
+  if (!callee)
+    dump_final_indirect_call_node_vcg (f);
+}
+
+/* Dump final cgraph node in VCG format.  */
+
+static void
+dump_final_node_vcg (FILE *f)
+{
+  fputs ("node: { title: \"", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_UNIQUE_NAME);
+  fputs ("\" label: \"", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_NAME);
+  fputs ("\\n", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_ORIGIN);
+
+  if (DECL_EXTERNAL (current_function_decl))
+    {
+      fputs ("\" shape : ellipse }\n", f);
+      return;
+    }
+
+  if (flag_stack_usage_info
+      || (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE))
+    output_stack_usage_1 (f);
+
+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+    {
+      fprintf (f, "\\n%u dynamic objects", vec_safe_length (cfun->su->dallocs));
+
+      unsigned i;
+      callinfo_dalloc *cda;
+      FOR_EACH_VEC_SAFE_ELT (cfun->su->dallocs, i, cda)
+	{
+	  expanded_location loc = expand_location (cda->location);
+	  fprintf (f, "\\n %s", cda->name);
+	  fprintf (f, " %s:%d:%d", loc.file, loc.line, loc.column);
+	}
+
+      vec_free (cfun->su->dallocs);
+      cfun->su->dallocs = NULL;
+    }
+
+  fputs ("\" }\n", f);
+
+  unsigned i;
+  callinfo_callee *c;
+  FOR_EACH_VEC_SAFE_ELT (cfun->su->callees, i, c)
+    dump_final_callee_vcg (f, c->location, c->decl);
+  vec_free (cfun->su->callees);
+  cfun->su->callees = NULL;
+
+  cgraph_node *cnode = cgraph_node::get (current_function_decl);
+  for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
+    if (CALLEE_FROM_CGRAPH_P (e->callee->decl))
+      dump_final_callee_vcg (f, gimple_location (e->call_stmt),
+			     e->callee->decl);
+  for (cgraph_edge *e = cnode->indirect_calls; e; e = e->next_callee)
+    dump_final_callee_vcg (f, gimple_location (e->call_stmt), NULL);
+}
+
+/* Output stack usage and callgraph info, as requested.  */
+void
+output_stack_usage (void)
+{
+  if (flag_callgraph_info)
+    dump_final_node_vcg (callgraph_info_file);
+  else
+    output_stack_usage_1 (NULL);
+}
+
 /* Open an auxiliary output file.  */
 static FILE *
 open_auxiliary_file (const char *ext)
@@ -1900,6 +1994,15 @@ lang_dependent_init (const char *name)
       /* If stack usage information is desired, open the output file.  */
       if (flag_stack_usage && !flag_generate_lto)
 	stack_usage_file = open_auxiliary_file ("su");
+
+      /* If call graph information is desired, open the output file.  */
+      if (flag_callgraph_info && !flag_generate_lto)
+	{
+	  callgraph_info_file = open_auxiliary_file ("ci");
+	  /* Write the file header.  */
+	  fprintf (callgraph_info_file,
+		   "graph: { title: \"%s\"\n", main_input_filename);
+	}
     }
 
   /* This creates various _DECL nodes, so needs to be called after the
@@ -2044,6 +2147,14 @@ finalize (bool no_backend)
       stack_usage_file = NULL;
     }
 
+  if (callgraph_info_file)
+    {
+      fputs ("}\n", callgraph_info_file);
+      fclose (callgraph_info_file);
+      callgraph_info_file = NULL;
+      callgraph_info_indirect_emitted = false;
+    }
+
   if (seen_error ())
     coverage_remove_note_file ();
Richard Biener Oct. 28, 2019, 8:34 a.m. UTC | #4
On Sun, 27 Oct 2019, Alexandre Oliva wrote:

> On Oct 26, 2019, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > E.g., the reason we gather expanded calls rather than just use
> > cgraph_edges is that the latter would dump several "calls" that are
> > builtins expanded internally by the compiler, and would NOT dump other
> > ops that are expanded as (lib)calls.
> 
> It occurred to me that we could reuse most cgraph edges and avoid
> duplicating them in the callees vec, namely those that aren't builtins
> or libcalls.  Those that are builtins might or might not become actual
> calls, so we disregard the cgraph_edges and record them in the vec
> instead.  Those that are libcalls (builtins in a different sense)
> introduced during expand are not even present in the cgraph edges, so we
> record them in the vec as well.  Here's the patch that implements this.
> 
> Regstrapped on x86_64-linux-gnu.  Ok to install?

<...>

> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1091,6 +1091,14 @@ fbtr-bb-exclusive
>  Common Ignore
>  Does nothing.  Preserved for backward compatibility.
>  
> +fcallgraph-info
> +Common Report RejectNegative Var(flag_callgraph_info) Init(NO_CALLGRAPH_INFO);
> +Output callgraph information on a per-file basis
> +
> +fcallgraph-info=
> +Common Report RejectNegative Joined
> +Output callgraph information on a per-file basis with decorations
> +
>  fcall-saved-
>  Common Joined RejectNegative Var(common_deferred_options) Defer
>  -fcall-saved-<register>	Mark <register> as being preserved across functions.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 1407d019d1404..545b842eade71 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -583,8 +583,9 @@ Objective-C and Objective-C++ Dialects}.
>  @item Developer Options
>  @xref{Developer Options,,GCC Developer Options}.
>  @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
> --dumpfullversion  -fchecking  -fchecking=@var{n}  -fdbg-cnt-list @gol
> --fdbg-cnt=@var{counter-value-list} @gol
> +-dumpfullversion  -fcallgraph-info@r{[}=su,da@r{]}
> +-fchecking  -fchecking=@var{n}
> +-fdbg-cnt-list @gol  -fdbg-cnt=@var{counter-value-list} @gol
>  -fdisable-ipa-@var{pass_name} @gol
>  -fdisable-rtl-@var{pass_name} @gol
>  -fdisable-rtl-@var{pass-name}=@var{range-list} @gol
> @@ -14533,6 +14534,18 @@ The files are created in the directory of the output file.
>  
>  @table @gcctabopt
>  
> +@item -fcallgraph-info
> +@itemx -fcallgraph-info=@var{MARKERS}
> +@opindex fcallgraph-info
> +Makes the compiler output callgraph information for the program, on a
> +per-file basis.  The information is generated in the common VCG format.

I guess you need to elaborate on 'per-file'.  With LTO as far as I
understand you'll get the graph per LTRANS unit (did you check
where the output is generated?).

Is this mainly a debugging tool or does it serve a different purpose?

Otherwise OK.

Thanks,
Richard.

> +It can be decorated with additional, per-node and/or per-edge information,
> +if a list of comma-separated markers is additionally specified.  When the
> +@code{su} marker is specified, the callgraph is decorated with stack usage
> +information; it is equivalent to @option{-fstack-usage}.  When the @code{da}
> +marker is specified, the callgraph is decorated with information about
> +dynamically allocated objects.
Joseph Myers Oct. 28, 2019, 11:25 p.m. UTC | #5
On Sat, 26 Oct 2019, Alexandre Oliva wrote:

> Regstrapped on x86_64-linux-gnu.  Ok to install?

I have only a peripheral comment:

> diff --git a/gcc/common.opt b/gcc/common.opt
> index cc279f411d796..63d646fba2b42 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1091,6 +1091,14 @@ fbtr-bb-exclusive
>  Common Ignore
>  Does nothing.  Preserved for backward compatibility.
>  
> +fcallgraph-info
> +Common Report RejectNegative Var(flag_callgraph_info) Init(NO_CALLGRAPH_INFO);
> +Output callgraph information on a per-file basis
> +
> +fcallgraph-info=
> +Common Report RejectNegative Joined
> +Output callgraph information on a per-file basis with decorations

We have a test in the testsuite that all option help text consistently 
ends with '.' (see gcc.misc-tests/help.exp).  I'd have expected these 
options, lacking that '.', to cause that test to fail.
Alexandre Oliva Oct. 30, 2019, 9:09 a.m. UTC | #6
On Oct 28, 2019, Joseph Myers <joseph@codesourcery.com> wrote:

> We have a test in the testsuite that all option help text consistently 
> ends with '.' (see gcc.misc-tests/help.exp).  I'd have expected these 
> options, lacking that '.', to cause that test to fail.

Thanks.  I've fixed the common.opt changes, and I'll submit momentarily
a patch for help.exp to extend it to cover --help=common output as well.
Alexandre Oliva Oct. 30, 2019, 9:40 a.m. UTC | #7
On Oct 28, 2019, Joseph Myers <joseph@codesourcery.com> wrote:

> We have a test in the testsuite that all option help text consistently 
> ends with '.' (see gcc.misc-tests/help.exp).  I'd have expected these 
> options, lacking that '.', to cause that test to fail.

Here's the patch.  Tested on x86_64-linux-gnu.  Ok to install?


Test --help=common for full sentences

The portion of help.exp that checks that help output contains full
sentences failed to cover common options.


for  gcc/testsuite/ChangeLog

	* gcc.misc-tests/help.exp: Test --help=common for full sentences.
---
 gcc/testsuite/gcc.misc-tests/help.exp |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
index b8a09fc..4bb359f 100644
--- a/gcc/testsuite/gcc.misc-tests/help.exp
+++ b/gcc/testsuite/gcc.misc-tests/help.exp
@@ -146,8 +146,7 @@ check_for_options c "--help=joined,undocumented" "" "" ""
 # find the source a failure.
 
 foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
-		    "optimizers" "param" "target" "warnings" } {
-
+		"common" "optimizers" "param" "target" "warnings" } {
     check_for_options c "--help=$cls" "" "^ +-.*\[^:.\]$" ""
 }
Alexandre Oliva Oct. 30, 2019, 10:10 a.m. UTC | #8
On Oct 28, 2019, Richard Biener <rguenther@suse.de> wrote:

> I guess you need to elaborate on 'per-file'.  With LTO as far as I
> understand you'll get the graph per LTRANS unit (did you check
> where the output is generated?).

Yeah, I guess this was not designed with LTO in mind; it probably even
predates LTO.  We get per-LTRANS unit indeed, and the output is
generated in the temporary dir, which is not desirable behavior for
sure.  The outputs seem to be usable if you can figure out what they
are, but I'm not sure how to go about combining the multiple .ci files,
or how to name the combined output, since it's not generally expected
that these files will be created at link time, rather than at compile
time.  I'll bring this up internally and come back with some
improvement.

> Is this mainly a debugging tool or does it serve a different purpose?

It feeds gnatstack, that's a tool to compute max stack depth and perform
other call graph analyzes.  I don't think of it as a debugging tool.

https://www.adacore.com/gnatpro/toolsuite/gnatstack
http://docs.adacore.com/live/wave/gnatstack/html/gnatstack_ug/index.html
Richard Biener Oct. 30, 2019, 11:24 a.m. UTC | #9
On Wed, 30 Oct 2019, Alexandre Oliva wrote:

> On Oct 28, 2019, Richard Biener <rguenther@suse.de> wrote:
> 
> > I guess you need to elaborate on 'per-file'.  With LTO as far as I
> > understand you'll get the graph per LTRANS unit (did you check
> > where the output is generated?).
> 
> Yeah, I guess this was not designed with LTO in mind; it probably even
> predates LTO.  We get per-LTRANS unit indeed, and the output is
> generated in the temporary dir, which is not desirable behavior for
> sure.  The outputs seem to be usable if you can figure out what they
> are, but I'm not sure how to go about combining the multiple .ci files,
> or how to name the combined output, since it's not generally expected
> that these files will be created at link time, rather than at compile
> time.  I'll bring this up internally and come back with some
> improvement.
> 
> > Is this mainly a debugging tool or does it serve a different purpose?
> 
> It feeds gnatstack, that's a tool to compute max stack depth and perform
> other call graph analyzes.  I don't think of it as a debugging tool.
> 
> https://www.adacore.com/gnatpro/toolsuite/gnatstack
> http://docs.adacore.com/live/wave/gnatstack/html/gnatstack_ug/index.html

Ah, thanks for clarification.  One way of operation would be to
generate the graph during the compilation step even with LTO though
it then becomes much less precise.  Note that during LTRANS you
could get at the original file via the DECL_SOURCE_LOCATION of
the TRANSLATION_UNIT_DECL each function is ultimately rooted in
so there's the vague possibility to annotate the graph accordingly
to help combining the output.  Additional arguments to
-fcallgraph-info might be used to direct the output to a specific
directory as well.

Richard.
Joseph Myers Oct. 30, 2019, 6:10 p.m. UTC | #10
On Wed, 30 Oct 2019, Alexandre Oliva wrote:

> On Oct 28, 2019, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> > We have a test in the testsuite that all option help text consistently 
> > ends with '.' (see gcc.misc-tests/help.exp).  I'd have expected these 
> > options, lacking that '.', to cause that test to fail.
> 
> Here's the patch.  Tested on x86_64-linux-gnu.  Ok to install?
> 
> 
> Test --help=common for full sentences
> 
> The portion of help.exp that checks that help output contains full
> sentences failed to cover common options.

OK.
Alexandre Oliva Nov. 2, 2019, 7:31 p.m. UTC | #11
On Oct 30, 2019, Richard Biener <rguenther@suse.de> wrote:

> One way of operation would be to
> generate the graph during the compilation step

Stack usage is only computed during prologue/epilogue generation in RTL.

> Additional arguments to -fcallgraph-info might be used to direct the
> output to a specific directory as well.

I've adjusted open_auxiliary_file for LTO recompilation auxiliary files
to be placed in the same location as the specified executable output
name, and noted that in the documentation.

I've also added a bitmap to output nodes for externals, accidentally
dropped in the transition to incremental generation of the .ci file.

Regstrapped on x86_64-linux-gnu.  Ok to install?


introduce -fcallgraph-info option

This was first submitted many years ago
https://gcc.gnu.org/ml/gcc-patches/2010-10/msg02468.html

The command line option -fcallgraph-info is added and makes the
compiler generate another output file (xxx.ci) for each compilation
unit (or LTO partitoin), which is a valid VCG file (you can launch
your favorite VCG viewer on it unmodified) and contains the "final"
callgraph of the unit.  "final" is a bit of a misnomer as this is
actually the callgraph at RTL expansion time, but since most
high-level optimizations are done at the Tree level and RTL doesn't
usually fiddle with calls, it's final in almost all cases.  Moreover,
the nodes can be decorated with additional info: -fcallgraph-info=su
adds stack usage info and -fcallgraph-info=da dynamic allocation info.


for  gcc/ChangeLog
From  Eric Botcazou  <ebotcazou@adacore.com>, Alexandre Oliva  <oliva@adacore.com>

	* common.opt (-fcallgraph-info[=]): New option.
	* doc/invoke.texi (Developer options): Document it.
	* opts.c (common_handle_option): Handle it.
	* builtins.c (expand_builtin_alloca): Record allocation if
	-fcallgraph-info=da.
	* calls.c (expand_call): If -fcallgraph-info, record the call.
	(emit_library_call_value_1): Likewise.
	* flag-types.h (enum callgraph_info_type): New type.
	* explow.c: Include stringpool.h.
	(set_stack_check_libfunc): Set SET_SYMBOL_REF_DECL on the symbol.
	* function.c (allocate_stack_usage_info): New.
	(allocate_struct_function): Call it for -fcallgraph-info.
	(prepare_function_start): Call it otherwise.
	(record_final_call, record_dynamic_alloc): New.
	* function.h (struct callinfo_callee): New.
	(CALLEE_FROM_CGRAPH_P): New.
	(struct callinfo_dalloc): New.
	(struct stack_usage): Add callees and dallocs.
	(record_final_call, record_dynamic_alloc): Declare.
	* gimplify.c (gimplify_decl_expr): Record dynamically-allocated
	object if -fcallgraph-info=da.
	* optabs-libfuncs.c (build_libfunc_function): Keep SYMBOL_REF_DECL.
	* print-tree.h (print_decl_identifier): Declare.
	(PRINT_DECL_ORIGIN, PRINT_DECL_NAME, PRINT_DECL_UNIQUE_NAME): New.
	* print-tree.c: Include print-tree.h.
	(print_decl_identifier): New function.
	* toplev.c: Include print-tree.h.
	(callgraph_info_file): New global variable.
	(callgraph_info_external_printed): Likewise.
	(open_auxiliary_file): Use dump_base_name for LTO partitions.
	(output_stack_usage): Rename to...
	(output_stack_usage_1): ... this.  Make it static, add cf
	parameter.  If -fcallgraph-info=su, print stack usage to cf.
	If -fstack-usage, use print_decl_identifier for
	pretty-printing.
	(INDIRECT_CALL_NAME): New.
	(dump_final_node_vcg_start): New.
	(dump_final_callee_vcg, dump_final_node_vcg): New.
	(output_stack_usage): New.
	(lang_dependent_init): Open and start file if
	-fcallgraph-info.  Allocated callgraph_info_external_printed.
	(finalize): If callgraph_info_file is not null, finish it,
	close it, and release callgraph_info_external_printed.

for  gcc/ada/ChangeLog

	* gcc-interface/misc.c (callgraph_info_file): Delete.
---
 gcc/ada/gcc-interface/misc.c |    3 -
 gcc/builtins.c               |    4 +
 gcc/calls.c                  |    6 +
 gcc/common.opt               |    8 ++
 gcc/doc/invoke.texi          |   22 +++++
 gcc/explow.c                 |    5 +
 gcc/flag-types.h             |   16 ++++
 gcc/function.c               |   59 ++++++++++++-
 gcc/function.h               |   30 +++++++
 gcc/gimplify.c               |    4 +
 gcc/optabs-libfuncs.c        |    4 -
 gcc/opts.c                   |   26 ++++++
 gcc/output.h                 |    2 
 gcc/print-tree.c             |   76 +++++++++++++++++
 gcc/print-tree.h             |    4 +
 gcc/toplev.c                 |  186 ++++++++++++++++++++++++++++++++++--------
 16 files changed, 402 insertions(+), 53 deletions(-)

diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 4abd4d5..d68b373 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -54,9 +54,6 @@
 #include "ada-tree.h"
 #include "gigi.h"
 
-/* This symbol needs to be defined for the front-end.  */
-void *callgraph_info_file = NULL;
-
 /* Command-line argc and argv.  These variables are global since they are
    imported in back_end.adb.  */
 unsigned int save_argc;
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5d811f1..bd30238 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5406,6 +5406,10 @@ expand_builtin_alloca (tree exp)
     = allocate_dynamic_stack_space (op0, 0, align, max_size, alloca_for_var);
   result = convert_memory_address (ptr_mode, result);
 
+  /* Dynamic allocations for variables are recorded during gimplification.  */
+  if (!alloca_for_var && (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC))
+    record_dynamic_alloc (exp);
+
   return result;
 }
 
diff --git a/gcc/calls.c b/gcc/calls.c
index e2b770f..6292135 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -3759,6 +3759,9 @@ expand_call (tree exp, rtx target, int ignore)
 
   preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
 
+  if (flag_callgraph_info)
+    record_final_call (fndecl, EXPR_LOCATION (exp));
+
   /* We want to make two insn chains; one for a sibling call, the other
      for a normal call.  We will select one of the two chains after
      initial RTL generation is complete.  */
@@ -5343,6 +5346,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
   before_call = get_last_insn ();
 
+  if (flag_callgraph_info)
+    record_final_call (SYMBOL_REF_DECL (orgfun), UNKNOWN_LOCATION);
+
   /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
      will set inhibit_defer_pop to that value.  */
   /* The return type is needed to decide how many bytes the function pops.
diff --git a/gcc/common.opt b/gcc/common.opt
index cc279f4..299eac6 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1091,6 +1091,14 @@ fbtr-bb-exclusive
 Common Ignore
 Does nothing.  Preserved for backward compatibility.
 
+fcallgraph-info
+Common Report RejectNegative Var(flag_callgraph_info) Init(NO_CALLGRAPH_INFO);
+Output callgraph information on a per-file basis.
+
+fcallgraph-info=
+Common Report RejectNegative Joined
+Output callgraph information on a per-file basis with decorations.
+
 fcall-saved-
 Common Joined RejectNegative Var(common_deferred_options) Defer
 -fcall-saved-<register>	Mark <register> as being preserved across functions.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index faa7fa9..266021c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -584,8 +584,9 @@ Objective-C and Objective-C++ Dialects}.
 @item Developer Options
 @xref{Developer Options,,GCC Developer Options}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
--dumpfullversion  -fchecking  -fchecking=@var{n}  -fdbg-cnt-list @gol
--fdbg-cnt=@var{counter-value-list} @gol
+-dumpfullversion  -fcallgraph-info@r{[}=su,da@r{]}
+-fchecking  -fchecking=@var{n}
+-fdbg-cnt-list @gol  -fdbg-cnt=@var{counter-value-list} @gol
 -fdisable-ipa-@var{pass_name} @gol
 -fdisable-rtl-@var{pass_name} @gol
 -fdisable-rtl-@var{pass-name}=@var{range-list} @gol
@@ -14564,6 +14565,23 @@ The files are created in the directory of the output file.
 
 @table @gcctabopt
 
+@item -fcallgraph-info
+@itemx -fcallgraph-info=@var{MARKERS}
+@opindex fcallgraph-info
+Makes the compiler output callgraph information for the program, on a
+per-object-file basis.  The information is generated in the common VCG format.
+It can be decorated with additional, per-node and/or per-edge information,
+if a list of comma-separated markers is additionally specified.  When the
+@code{su} marker is specified, the callgraph is decorated with stack usage
+information; it is equivalent to @option{-fstack-usage}.  When the @code{da}
+marker is specified, the callgraph is decorated with information about
+dynamically allocated objects.
+
+When compiling with @option{-flto}, no callgraph information is output
+along with the object file.  At LTO link time, @option{-fcallgraph-info}
+may generate multiple callgraph information files next to the specified
+output file.
+
 @item -d@var{letters}
 @itemx -fdump-rtl-@var{pass}
 @itemx -fdump-rtl-@var{pass}=@var{filename}
diff --git a/gcc/explow.c b/gcc/explow.c
index 7eb854b..83c7863 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dojump.h"
 #include "explow.h"
 #include "expr.h"
+#include "stringpool.h"
 #include "common/common-target.h"
 #include "output.h"
 #include "params.h"
@@ -1611,6 +1612,10 @@ set_stack_check_libfunc (const char *libfunc_name)
 {
   gcc_assert (stack_check_libfunc == NULL_RTX);
   stack_check_libfunc = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
+  tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+			  get_identifier (libfunc_name), void_type_node);
+  DECL_EXTERNAL (decl) = 1;
+  SET_SYMBOL_REF_DECL (stack_check_libfunc, decl);
 }
 
 /* Emit one stack probe at ADDRESS, an address within the stack.  */
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index a210328..b23d3a2 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -200,6 +200,22 @@ enum stack_check_type
   FULL_BUILTIN_STACK_CHECK
 };
 
+/* Type of callgraph information.  */
+enum callgraph_info_type
+{
+  /* No information.  */
+  NO_CALLGRAPH_INFO = 0,
+
+  /* Naked callgraph.  */
+  CALLGRAPH_INFO_NAKED = 1,
+
+  /* Callgraph decorated with stack usage information.  */
+  CALLGRAPH_INFO_STACK_USAGE = 2,
+
+  /* Callgraph decoration with dynamic allocation information.  */
+  CALLGRAPH_INFO_DYNAMIC_ALLOC = 4
+};
+
 /* Floating-point contraction mode.  */
 enum fp_contract_mode {
   FP_CONTRACT_OFF = 0,
diff --git a/gcc/function.c b/gcc/function.c
index a1c76a4..3f79a38 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4725,6 +4725,16 @@ get_last_funcdef_no (void)
   return funcdef_no;
 }
 
+/* Allocate and initialize the stack usage info data structure for the
+   current function.  */
+static void
+allocate_stack_usage_info (void)
+{
+  gcc_assert (!cfun->su);
+  cfun->su = ggc_cleared_alloc<stack_usage> ();
+  cfun->su->static_stack_size = -1;
+}
+
 /* Allocate a function structure for FNDECL and set its contents
    to the defaults.  Set cfun to the newly-allocated object.
    Some of the helper functions invoked during initialization assume
@@ -4802,6 +4812,9 @@ allocate_struct_function (tree fndecl, bool abstract_p)
 
       if (!profile_flag && !flag_instrument_function_entry_exit)
 	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
+
+      if (flag_callgraph_info)
+	allocate_stack_usage_info ();
     }
 
   /* Don't enable begin stmt markers if var-tracking at assignments is
@@ -4846,11 +4859,8 @@ prepare_function_start (void)
   init_expr ();
   default_rtl_profile ();
 
-  if (flag_stack_usage_info)
-    {
-      cfun->su = ggc_cleared_alloc<stack_usage> ();
-      cfun->su->static_stack_size = -1;
-    }
+  if (flag_stack_usage_info && !flag_callgraph_info)
+    allocate_stack_usage_info ();
 
   cse_not_expected = ! optimize;
 
@@ -6373,12 +6383,49 @@ rest_of_handle_thread_prologue_and_epilogue (void)
   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
 
   /* The stack usage info is finalized during prologue expansion.  */
-  if (flag_stack_usage_info)
+  if (flag_stack_usage_info || flag_callgraph_info)
     output_stack_usage ();
 
   return 0;
 }
 
+/* Record a final call to CALLEE at LOCATION.  */
+
+void
+record_final_call (tree callee, location_t location)
+{
+  if (!callee || CALLEE_FROM_CGRAPH_P (callee))
+    return;
+
+  struct callinfo_callee datum = { location, callee };
+  vec_safe_push (cfun->su->callees, datum);
+}
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+
+void
+record_dynamic_alloc (tree decl_or_exp)
+{
+  struct callinfo_dalloc datum;
+
+  if (DECL_P (decl_or_exp))
+    {
+      datum.location = DECL_SOURCE_LOCATION (decl_or_exp);
+      const char *name = lang_hooks.decl_printable_name (decl_or_exp, 2);
+      const char *dot = strrchr (name, '.');
+      if (dot)
+	name = dot + 1;
+      datum.name = ggc_strdup (name);
+    }
+  else
+    {
+      datum.location = EXPR_LOCATION (decl_or_exp);
+      datum.name = NULL;
+    }
+
+  vec_safe_push (cfun->su->dallocs, datum);
+}
+
 namespace {
 
 const pass_data pass_data_thread_prologue_and_epilogue =
diff --git a/gcc/function.h b/gcc/function.h
index 43ac5dff..14794c4 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -192,6 +192,23 @@ public:
   poly_int64 length;
 };
 
+/* Describe emitted builtin calls for -fcallgraph-info.  Those that
+   are not builtin are taken from cgraph edges.  */
+struct GTY(()) callinfo_callee
+{
+  location_t location;
+  tree decl;
+};
+#define CALLEE_FROM_CGRAPH_P(T)				\
+  (!fndecl_built_in_p (T) && !DECL_IS_BUILTIN (T))
+
+/* Describe dynamic allocation for -fcallgraph-info=da.  */
+struct GTY(()) callinfo_dalloc
+{
+  location_t location;
+  char const *name;
+};
+
 class GTY(()) stack_usage
 {
 public:
@@ -210,6 +227,13 @@ public:
   /* Nonzero if the amount of stack space allocated dynamically cannot
      be bounded at compile-time.  */
   unsigned int has_unbounded_dynamic_stack_size : 1;
+
+  /* Functions called within the function, if callgraph is enabled.  */
+  vec<callinfo_callee, va_gc> *callees;
+
+  /* Dynamic allocations encountered within the function, if callgraph
+     da is enabled.  */
+  vec<callinfo_dalloc, va_gc> *dallocs;
 };
 
 #define current_function_static_stack_size (cfun->su->static_stack_size)
@@ -406,6 +430,12 @@ void add_local_decl (struct function *fun, tree d);
 #define FOR_EACH_LOCAL_DECL(FUN, I, D)		\
   FOR_EACH_VEC_SAFE_ELT_REVERSE ((FUN)->local_decls, I, D)
 
+/* Record a final call to CALLEE at LOCATION.  */
+void record_final_call (tree callee, location_t location);
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+void record_dynamic_alloc (tree decl_or_exp);
+
 /* If va_list_[gf]pr_size is set to this, it means we don't know how
    many units need to be saved.  */
 #define VA_LIST_MAX_GPR_SIZE	255
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 12ed3f8..74fc45a 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1698,6 +1698,10 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
   t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
 
   gimplify_and_add (t, seq_p);
+
+  /* Record the dynamic allocation associated with DECL if requested.  */
+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+    record_dynamic_alloc (decl);
 }
 
 /* A helper function to be called via walk_tree.  Mark all labels under *TP
diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c
index ef43dae..8916f7e4 100644
--- a/gcc/optabs-libfuncs.c
+++ b/gcc/optabs-libfuncs.c
@@ -735,10 +735,6 @@ build_libfunc_function_visibility (const char *name, symbol_visibility vis)
   DECL_VISIBILITY_SPECIFIED (decl) = 1;
   gcc_assert (DECL_ASSEMBLER_NAME (decl));
 
-  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
-     are the flags assigned by targetm.encode_section_info.  */
-  SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
-
   return decl;
 }
 
diff --git a/gcc/opts.c b/gcc/opts.c
index 10b9f10..f46b468 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2433,6 +2433,32 @@ common_handle_option (struct gcc_options *opts,
       /* Deferred.  */
       break;
 
+    case OPT_fcallgraph_info:
+      opts->x_flag_callgraph_info = CALLGRAPH_INFO_NAKED;
+      break;
+
+    case OPT_fcallgraph_info_:
+      {
+	char *my_arg, *p;
+	my_arg = xstrdup (arg);
+	p = strtok (my_arg, ",");
+	while (p)
+	  {
+	    if (strcmp (p, "su") == 0)
+	      {
+		opts->x_flag_callgraph_info |= CALLGRAPH_INFO_STACK_USAGE;
+		opts->x_flag_stack_usage_info = true;
+	      }
+	    else if (strcmp (p, "da") == 0)
+	      opts->x_flag_callgraph_info |= CALLGRAPH_INFO_DYNAMIC_ALLOC;
+	    else
+	      return 0;
+	    p = strtok (NULL, ",");
+	  }
+	free (my_arg);
+      }
+      break;
+
     case OPT_fdiagnostics_show_location_:
       diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value;
       break;
diff --git a/gcc/output.h b/gcc/output.h
index 835d635..6cccada 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -604,7 +604,7 @@ extern int maybe_assemble_visibility (tree);
 
 extern int default_address_cost (rtx, machine_mode, addr_space_t, bool);
 
-/* Output stack usage information.  */
+/* Stack usage.  */
 extern void output_stack_usage (void);
 
 #endif /* ! GCC_OUTPUT_H */
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 6dcbb2d..bd09ec4 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -1035,6 +1035,82 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
   fprintf (file, ">");
 }
 
+/* Print the identifier for DECL according to FLAGS.  */
+
+void
+print_decl_identifier (FILE *file, tree decl, int flags)
+{
+  bool needs_colon = false;
+  const char *name;
+  char c;
+
+  if (flags & PRINT_DECL_ORIGIN)
+    {
+      if (DECL_IS_BUILTIN (decl))
+	fputs ("<built-in>", file);
+      else
+	{
+	  expanded_location loc
+	    = expand_location (DECL_SOURCE_LOCATION (decl));
+	  fprintf (file, "%s:%d:%d", loc.file, loc.line, loc.column);
+	}
+      needs_colon = true;
+    }
+
+  if (flags & PRINT_DECL_UNIQUE_NAME)
+    {
+      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+      if (!TREE_PUBLIC (decl)
+	  || (DECL_WEAK (decl) && !DECL_EXTERNAL (decl)))
+	/* The symbol has internal or weak linkage so its assembler name
+	   is not necessarily unique among the compilation units of the
+	   program.  We therefore have to further mangle it.  But we can't
+	   simply use DECL_SOURCE_FILE because it contains the name of the
+	   file the symbol originates from so, e.g. for function templates
+	   in C++ where the templates are defined in a header file, we can
+	   have symbols with the same assembler name and DECL_SOURCE_FILE.
+	   That's why we use the name of the top-level source file of the
+	   compilation unit.  ??? Unnecessary for Ada.  */
+	name = ACONCAT ((main_input_filename, ":", name, NULL));
+    }
+  else if (flags & PRINT_DECL_NAME)
+    {
+      /* We don't want to print the full qualified name because it can be long,
+	 so we strip the scope prefix, but we may need to deal with the suffix
+	 created by the compiler.  */
+      const char *suffix = strchr (IDENTIFIER_POINTER (DECL_NAME (decl)), '.');
+      name = lang_hooks.decl_printable_name (decl, 2);
+      if (suffix)
+	{
+	  const char *dot = strchr (name, '.');
+	  while (dot && strcasecmp (dot, suffix) != 0)
+	    {
+	      name = dot + 1;
+	      dot = strchr (name, '.');
+	    }
+	}
+      else
+	{
+	  const char *dot = strrchr (name, '.');
+	  if (dot)
+	    name = dot + 1;
+	}
+    }
+  else
+    return;
+
+  if (needs_colon)
+    fputc (':', file);
+
+  while ((c = *name++) != '\0')
+    {
+      /* Strip double-quotes because of VCG.  */
+      if (c == '"')
+	continue;
+      fputc (c, file);
+    }
+}
+
 
 /* Print the node NODE on standard error, for debugging.
    Most nodes referred to by this one are printed recursively
diff --git a/gcc/print-tree.h b/gcc/print-tree.h
index 1d4fe6e..cbea48c 100644
--- a/gcc/print-tree.h
+++ b/gcc/print-tree.h
@@ -42,5 +42,9 @@ extern void print_node (FILE *, const char *, tree, int,
 extern void print_node_brief (FILE *, const char *, const_tree, int);
 extern void indent_to (FILE *, int);
 #endif
+#define PRINT_DECL_ORIGIN       0x1
+#define PRINT_DECL_NAME         0x2
+#define PRINT_DECL_UNIQUE_NAME  0x4
+extern void print_decl_identifier (FILE *, tree, int flags);
 
 #endif  // GCC_PRINT_TREE_H
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 00a5e83..8aaf216 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dumpfile.h"
 #include "ipa-fnsummary.h"
 #include "dump-context.h"
+#include "print-tree.h"
 #include "optinfo-emit-json.h"
 
 #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
@@ -174,6 +175,8 @@ const char *user_label_prefix;
 
 FILE *asm_out_file;
 FILE *aux_info_file;
+FILE *callgraph_info_file = NULL;
+static bitmap callgraph_info_external_printed;
 FILE *stack_usage_file = NULL;
 
 /* The current working directory of a translation.  It's generally the
@@ -913,8 +916,8 @@ alloc_for_identifier_to_locale (size_t len)
 }
 
 /* Output stack usage information.  */
-void
-output_stack_usage (void)
+static void
+output_stack_usage_1 (FILE *cf)
 {
   static bool warning_issued = false;
   enum stack_usage_kind_type { STATIC = 0, DYNAMIC, DYNAMIC_BOUNDED };
@@ -970,41 +973,17 @@ output_stack_usage (void)
       stack_usage += current_function_dynamic_stack_size;
     }
 
+  if (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE)
+    fprintf (cf, "\\n" HOST_WIDE_INT_PRINT_DEC " bytes (%s)",
+	     stack_usage,
+	     stack_usage_kind_str[stack_usage_kind]);
+
   if (stack_usage_file)
     {
-      expanded_location loc
-	= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
-      /* We don't want to print the full qualified name because it can be long,
-	 so we strip the scope prefix, but we may need to deal with the suffix
-	 created by the compiler.  */
-      const char *suffix
-	= strchr (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), '.');
-      const char *name
-	= lang_hooks.decl_printable_name (current_function_decl, 2);
-      if (suffix)
-	{
-	  const char *dot = strchr (name, '.');
-	  while (dot && strcasecmp (dot, suffix) != 0)
-	    {
-	      name = dot + 1;
-	      dot = strchr (name, '.');
-	    }
-	}
-      else
-	{
-	  const char *dot = strrchr (name, '.');
-	  if (dot)
-	    name = dot + 1;
-	}
-
-      fprintf (stack_usage_file,
-	       "%s:%d:%d:%s\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
-	       loc.file == NULL ? "(artificial)" : lbasename (loc.file),
-	       loc.line,
-	       loc.column,
-	       name,
-	       stack_usage,
-	       stack_usage_kind_str[stack_usage_kind]);
+      print_decl_identifier (stack_usage_file, current_function_decl,
+			     PRINT_DECL_ORIGIN | PRINT_DECL_NAME);
+      fprintf (stack_usage_file, "\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
+	       stack_usage, stack_usage_kind_str[stack_usage_kind]);
     }
 
   if (warn_stack_usage >= 0 && warn_stack_usage < HOST_WIDE_INT_MAX)
@@ -1026,14 +1005,127 @@ output_stack_usage (void)
     }
 }
 
-/* Open an auxiliary output file.  */
+/* Dump placeholder node for indirect calls in VCG format.  */
+
+#define INDIRECT_CALL_NAME  "__indirect_call"
+
+static void
+dump_final_node_vcg_start (FILE *f, tree decl)
+{
+  fputs ("node: { title: \"", f);
+  if (decl)
+    print_decl_identifier (f, decl, PRINT_DECL_UNIQUE_NAME);
+  else
+    fputs (INDIRECT_CALL_NAME, f);
+  fputs ("\" label: \"", f);
+  if (decl)
+    {
+      print_decl_identifier (f, decl, PRINT_DECL_NAME);
+      fputs ("\\n", f);
+      print_decl_identifier (f, decl, PRINT_DECL_ORIGIN);
+    }
+  else
+    fputs ("Indirect Call Placeholder", f);
+}
+
+/* Dump final cgraph edge in VCG format.  */
+
+static void
+dump_final_callee_vcg (FILE *f, location_t location, tree callee)
+{
+  if ((!callee || DECL_EXTERNAL (callee))
+      && bitmap_set_bit (callgraph_info_external_printed,
+			 callee ? DECL_UID (callee) + 1 : 0))
+    {
+      dump_final_node_vcg_start (f, callee);
+      fputs ("\" shape : ellipse }\n", f);
+    }
+
+  fputs ("edge: { sourcename: \"", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_UNIQUE_NAME);
+  fputs ("\" targetname: \"", f);
+  if (callee)
+    print_decl_identifier (f, callee, PRINT_DECL_UNIQUE_NAME);
+  else
+    fputs (INDIRECT_CALL_NAME, f);
+  if (LOCATION_LOCUS (location) != UNKNOWN_LOCATION)
+    {
+      expanded_location loc;
+      fputs ("\" label: \"", f);
+      loc = expand_location (location);
+      fprintf (f, "%s:%d:%d", loc.file, loc.line, loc.column);
+    }
+  fputs ("\" }\n", f);
+}
+
+/* Dump final cgraph node in VCG format.  */
+
+static void
+dump_final_node_vcg (FILE *f)
+{
+  dump_final_node_vcg_start (f, current_function_decl);
+
+  if (flag_stack_usage_info
+      || (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE))
+    output_stack_usage_1 (f);
+
+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+    {
+      fprintf (f, "\\n%u dynamic objects", vec_safe_length (cfun->su->dallocs));
+
+      unsigned i;
+      callinfo_dalloc *cda;
+      FOR_EACH_VEC_SAFE_ELT (cfun->su->dallocs, i, cda)
+	{
+	  expanded_location loc = expand_location (cda->location);
+	  fprintf (f, "\\n %s", cda->name);
+	  fprintf (f, " %s:%d:%d", loc.file, loc.line, loc.column);
+	}
+
+      vec_free (cfun->su->dallocs);
+      cfun->su->dallocs = NULL;
+    }
+
+  fputs ("\" }\n", f);
+
+  unsigned i;
+  callinfo_callee *c;
+  FOR_EACH_VEC_SAFE_ELT (cfun->su->callees, i, c)
+    dump_final_callee_vcg (f, c->location, c->decl);
+  vec_free (cfun->su->callees);
+  cfun->su->callees = NULL;
+
+  cgraph_node *cnode = cgraph_node::get (current_function_decl);
+  for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
+    if (CALLEE_FROM_CGRAPH_P (e->callee->decl))
+      dump_final_callee_vcg (f, gimple_location (e->call_stmt),
+			     e->callee->decl);
+  for (cgraph_edge *e = cnode->indirect_calls; e; e = e->next_callee)
+    dump_final_callee_vcg (f, gimple_location (e->call_stmt), NULL);
+}
+
+/* Output stack usage and callgraph info, as requested.  */
+void
+output_stack_usage (void)
+{
+  if (flag_callgraph_info)
+    dump_final_node_vcg (callgraph_info_file);
+  else
+    output_stack_usage_1 (NULL);
+}
+
+/* Open an auxiliary or dump output file.  */
 static FILE *
 open_auxiliary_file (const char *ext)
 {
   char *filename;
   FILE *file;
+  const char *base_name = aux_base_name;
 
-  filename = concat (aux_base_name, ".", ext, NULL);
+  if (in_lto_p)
+    base_name = dump_base_name;
+
+  filename = concat (base_name, ".", ext, NULL);
   file = fopen (filename, "w");
   if (!file)
     fatal_error (input_location, "cannot open %s for writing: %m", filename);
@@ -1900,6 +1992,17 @@ lang_dependent_init (const char *name)
       /* If stack usage information is desired, open the output file.  */
       if (flag_stack_usage && !flag_generate_lto)
 	stack_usage_file = open_auxiliary_file ("su");
+
+      /* If call graph information is desired, open the output file.  */
+      if (flag_callgraph_info && !flag_generate_lto)
+	{
+	  callgraph_info_file = open_auxiliary_file ("ci");
+	  /* Write the file header.  */
+	  fprintf (callgraph_info_file,
+		   "graph: { title: \"%s\"\n", main_input_filename);
+	  bitmap_obstack_initialize (NULL);
+	  callgraph_info_external_printed = BITMAP_ALLOC (NULL);
+	}
     }
 
   /* This creates various _DECL nodes, so needs to be called after the
@@ -2053,6 +2156,15 @@ finalize (bool no_backend)
       stack_usage_file = NULL;
     }
 
+  if (callgraph_info_file)
+    {
+      fputs ("}\n", callgraph_info_file);
+      fclose (callgraph_info_file);
+      callgraph_info_file = NULL;
+      BITMAP_FREE (callgraph_info_external_printed);
+      bitmap_obstack_release (NULL);
+    }
+
   if (seen_error ())
     coverage_remove_note_file ();
Richard Biener Nov. 4, 2019, 8:28 a.m. UTC | #12
On Sat, 2 Nov 2019, Alexandre Oliva wrote:

> On Oct 30, 2019, Richard Biener <rguenther@suse.de> wrote:
> 
> > One way of operation would be to
> > generate the graph during the compilation step
> 
> Stack usage is only computed during prologue/epilogue generation in RTL.
> 
> > Additional arguments to -fcallgraph-info might be used to direct the
> > output to a specific directory as well.
> 
> I've adjusted open_auxiliary_file for LTO recompilation auxiliary files
> to be placed in the same location as the specified executable output
> name, and noted that in the documentation.

Please leave that part out for now, I'd rather discuss this separately
from the bulk of the patch.  That is, I wonder why we shouldn't
simply adjust aux_base_name to something else for -flto [in the driver].

> I've also added a bitmap to output nodes for externals, accidentally
> dropped in the transition to incremental generation of the .ci file.
> 
> Regstrapped on x86_64-linux-gnu.  Ok to install?

OK for the rest.

Thanks,
Richard.

> 
> introduce -fcallgraph-info option
> 
> This was first submitted many years ago
> https://gcc.gnu.org/ml/gcc-patches/2010-10/msg02468.html
> 
> The command line option -fcallgraph-info is added and makes the
> compiler generate another output file (xxx.ci) for each compilation
> unit (or LTO partitoin), which is a valid VCG file (you can launch
> your favorite VCG viewer on it unmodified) and contains the "final"
> callgraph of the unit.  "final" is a bit of a misnomer as this is
> actually the callgraph at RTL expansion time, but since most
> high-level optimizations are done at the Tree level and RTL doesn't
> usually fiddle with calls, it's final in almost all cases.  Moreover,
> the nodes can be decorated with additional info: -fcallgraph-info=su
> adds stack usage info and -fcallgraph-info=da dynamic allocation info.
> 
> 
> for  gcc/ChangeLog
> From  Eric Botcazou  <ebotcazou@adacore.com>, Alexandre Oliva  <oliva@adacore.com>
> 
> 	* common.opt (-fcallgraph-info[=]): New option.
> 	* doc/invoke.texi (Developer options): Document it.
> 	* opts.c (common_handle_option): Handle it.
> 	* builtins.c (expand_builtin_alloca): Record allocation if
> 	-fcallgraph-info=da.
> 	* calls.c (expand_call): If -fcallgraph-info, record the call.
> 	(emit_library_call_value_1): Likewise.
> 	* flag-types.h (enum callgraph_info_type): New type.
> 	* explow.c: Include stringpool.h.
> 	(set_stack_check_libfunc): Set SET_SYMBOL_REF_DECL on the symbol.
> 	* function.c (allocate_stack_usage_info): New.
> 	(allocate_struct_function): Call it for -fcallgraph-info.
> 	(prepare_function_start): Call it otherwise.
> 	(record_final_call, record_dynamic_alloc): New.
> 	* function.h (struct callinfo_callee): New.
> 	(CALLEE_FROM_CGRAPH_P): New.
> 	(struct callinfo_dalloc): New.
> 	(struct stack_usage): Add callees and dallocs.
> 	(record_final_call, record_dynamic_alloc): Declare.
> 	* gimplify.c (gimplify_decl_expr): Record dynamically-allocated
> 	object if -fcallgraph-info=da.
> 	* optabs-libfuncs.c (build_libfunc_function): Keep SYMBOL_REF_DECL.
> 	* print-tree.h (print_decl_identifier): Declare.
> 	(PRINT_DECL_ORIGIN, PRINT_DECL_NAME, PRINT_DECL_UNIQUE_NAME): New.
> 	* print-tree.c: Include print-tree.h.
> 	(print_decl_identifier): New function.
> 	* toplev.c: Include print-tree.h.
> 	(callgraph_info_file): New global variable.
> 	(callgraph_info_external_printed): Likewise.
> 	(open_auxiliary_file): Use dump_base_name for LTO partitions.
> 	(output_stack_usage): Rename to...
> 	(output_stack_usage_1): ... this.  Make it static, add cf
> 	parameter.  If -fcallgraph-info=su, print stack usage to cf.
> 	If -fstack-usage, use print_decl_identifier for
> 	pretty-printing.
> 	(INDIRECT_CALL_NAME): New.
> 	(dump_final_node_vcg_start): New.
> 	(dump_final_callee_vcg, dump_final_node_vcg): New.
> 	(output_stack_usage): New.
> 	(lang_dependent_init): Open and start file if
> 	-fcallgraph-info.  Allocated callgraph_info_external_printed.
> 	(finalize): If callgraph_info_file is not null, finish it,
> 	close it, and release callgraph_info_external_printed.
> 
> for  gcc/ada/ChangeLog
> 
> 	* gcc-interface/misc.c (callgraph_info_file): Delete.
> ---
>  gcc/ada/gcc-interface/misc.c |    3 -
>  gcc/builtins.c               |    4 +
>  gcc/calls.c                  |    6 +
>  gcc/common.opt               |    8 ++
>  gcc/doc/invoke.texi          |   22 +++++
>  gcc/explow.c                 |    5 +
>  gcc/flag-types.h             |   16 ++++
>  gcc/function.c               |   59 ++++++++++++-
>  gcc/function.h               |   30 +++++++
>  gcc/gimplify.c               |    4 +
>  gcc/optabs-libfuncs.c        |    4 -
>  gcc/opts.c                   |   26 ++++++
>  gcc/output.h                 |    2 
>  gcc/print-tree.c             |   76 +++++++++++++++++
>  gcc/print-tree.h             |    4 +
>  gcc/toplev.c                 |  186 ++++++++++++++++++++++++++++++++++--------
>  16 files changed, 402 insertions(+), 53 deletions(-)
> 
> diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
> index 4abd4d5..d68b373 100644
> --- a/gcc/ada/gcc-interface/misc.c
> +++ b/gcc/ada/gcc-interface/misc.c
> @@ -54,9 +54,6 @@
>  #include "ada-tree.h"
>  #include "gigi.h"
>  
> -/* This symbol needs to be defined for the front-end.  */
> -void *callgraph_info_file = NULL;
> -
>  /* Command-line argc and argv.  These variables are global since they are
>     imported in back_end.adb.  */
>  unsigned int save_argc;
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index 5d811f1..bd30238 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -5406,6 +5406,10 @@ expand_builtin_alloca (tree exp)
>      = allocate_dynamic_stack_space (op0, 0, align, max_size, alloca_for_var);
>    result = convert_memory_address (ptr_mode, result);
>  
> +  /* Dynamic allocations for variables are recorded during gimplification.  */
> +  if (!alloca_for_var && (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC))
> +    record_dynamic_alloc (exp);
> +
>    return result;
>  }
>  
> diff --git a/gcc/calls.c b/gcc/calls.c
> index e2b770f..6292135 100644
> --- a/gcc/calls.c
> +++ b/gcc/calls.c
> @@ -3759,6 +3759,9 @@ expand_call (tree exp, rtx target, int ignore)
>  
>    preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
>  
> +  if (flag_callgraph_info)
> +    record_final_call (fndecl, EXPR_LOCATION (exp));
> +
>    /* We want to make two insn chains; one for a sibling call, the other
>       for a normal call.  We will select one of the two chains after
>       initial RTL generation is complete.  */
> @@ -5343,6 +5346,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
>  
>    before_call = get_last_insn ();
>  
> +  if (flag_callgraph_info)
> +    record_final_call (SYMBOL_REF_DECL (orgfun), UNKNOWN_LOCATION);
> +
>    /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
>       will set inhibit_defer_pop to that value.  */
>    /* The return type is needed to decide how many bytes the function pops.
> diff --git a/gcc/common.opt b/gcc/common.opt
> index cc279f4..299eac6 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1091,6 +1091,14 @@ fbtr-bb-exclusive
>  Common Ignore
>  Does nothing.  Preserved for backward compatibility.
>  
> +fcallgraph-info
> +Common Report RejectNegative Var(flag_callgraph_info) Init(NO_CALLGRAPH_INFO);
> +Output callgraph information on a per-file basis.
> +
> +fcallgraph-info=
> +Common Report RejectNegative Joined
> +Output callgraph information on a per-file basis with decorations.
> +
>  fcall-saved-
>  Common Joined RejectNegative Var(common_deferred_options) Defer
>  -fcall-saved-<register>	Mark <register> as being preserved across functions.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index faa7fa9..266021c 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -584,8 +584,9 @@ Objective-C and Objective-C++ Dialects}.
>  @item Developer Options
>  @xref{Developer Options,,GCC Developer Options}.
>  @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
> --dumpfullversion  -fchecking  -fchecking=@var{n}  -fdbg-cnt-list @gol
> --fdbg-cnt=@var{counter-value-list} @gol
> +-dumpfullversion  -fcallgraph-info@r{[}=su,da@r{]}
> +-fchecking  -fchecking=@var{n}
> +-fdbg-cnt-list @gol  -fdbg-cnt=@var{counter-value-list} @gol
>  -fdisable-ipa-@var{pass_name} @gol
>  -fdisable-rtl-@var{pass_name} @gol
>  -fdisable-rtl-@var{pass-name}=@var{range-list} @gol
> @@ -14564,6 +14565,23 @@ The files are created in the directory of the output file.
>  
>  @table @gcctabopt
>  
> +@item -fcallgraph-info
> +@itemx -fcallgraph-info=@var{MARKERS}
> +@opindex fcallgraph-info
> +Makes the compiler output callgraph information for the program, on a
> +per-object-file basis.  The information is generated in the common VCG format.
> +It can be decorated with additional, per-node and/or per-edge information,
> +if a list of comma-separated markers is additionally specified.  When the
> +@code{su} marker is specified, the callgraph is decorated with stack usage
> +information; it is equivalent to @option{-fstack-usage}.  When the @code{da}
> +marker is specified, the callgraph is decorated with information about
> +dynamically allocated objects.
> +
> +When compiling with @option{-flto}, no callgraph information is output
> +along with the object file.  At LTO link time, @option{-fcallgraph-info}
> +may generate multiple callgraph information files next to the specified
> +output file.
> +
>  @item -d@var{letters}
>  @itemx -fdump-rtl-@var{pass}
>  @itemx -fdump-rtl-@var{pass}=@var{filename}
> diff --git a/gcc/explow.c b/gcc/explow.c
> index 7eb854b..83c7863 100644
> --- a/gcc/explow.c
> +++ b/gcc/explow.c
> @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "dojump.h"
>  #include "explow.h"
>  #include "expr.h"
> +#include "stringpool.h"
>  #include "common/common-target.h"
>  #include "output.h"
>  #include "params.h"
> @@ -1611,6 +1612,10 @@ set_stack_check_libfunc (const char *libfunc_name)
>  {
>    gcc_assert (stack_check_libfunc == NULL_RTX);
>    stack_check_libfunc = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
> +  tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
> +			  get_identifier (libfunc_name), void_type_node);
> +  DECL_EXTERNAL (decl) = 1;
> +  SET_SYMBOL_REF_DECL (stack_check_libfunc, decl);
>  }
>  
>  /* Emit one stack probe at ADDRESS, an address within the stack.  */
> diff --git a/gcc/flag-types.h b/gcc/flag-types.h
> index a210328..b23d3a2 100644
> --- a/gcc/flag-types.h
> +++ b/gcc/flag-types.h
> @@ -200,6 +200,22 @@ enum stack_check_type
>    FULL_BUILTIN_STACK_CHECK
>  };
>  
> +/* Type of callgraph information.  */
> +enum callgraph_info_type
> +{
> +  /* No information.  */
> +  NO_CALLGRAPH_INFO = 0,
> +
> +  /* Naked callgraph.  */
> +  CALLGRAPH_INFO_NAKED = 1,
> +
> +  /* Callgraph decorated with stack usage information.  */
> +  CALLGRAPH_INFO_STACK_USAGE = 2,
> +
> +  /* Callgraph decoration with dynamic allocation information.  */
> +  CALLGRAPH_INFO_DYNAMIC_ALLOC = 4
> +};
> +
>  /* Floating-point contraction mode.  */
>  enum fp_contract_mode {
>    FP_CONTRACT_OFF = 0,
> diff --git a/gcc/function.c b/gcc/function.c
> index a1c76a4..3f79a38 100644
> --- a/gcc/function.c
> +++ b/gcc/function.c
> @@ -4725,6 +4725,16 @@ get_last_funcdef_no (void)
>    return funcdef_no;
>  }
>  
> +/* Allocate and initialize the stack usage info data structure for the
> +   current function.  */
> +static void
> +allocate_stack_usage_info (void)
> +{
> +  gcc_assert (!cfun->su);
> +  cfun->su = ggc_cleared_alloc<stack_usage> ();
> +  cfun->su->static_stack_size = -1;
> +}
> +
>  /* Allocate a function structure for FNDECL and set its contents
>     to the defaults.  Set cfun to the newly-allocated object.
>     Some of the helper functions invoked during initialization assume
> @@ -4802,6 +4812,9 @@ allocate_struct_function (tree fndecl, bool abstract_p)
>  
>        if (!profile_flag && !flag_instrument_function_entry_exit)
>  	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
> +
> +      if (flag_callgraph_info)
> +	allocate_stack_usage_info ();
>      }
>  
>    /* Don't enable begin stmt markers if var-tracking at assignments is
> @@ -4846,11 +4859,8 @@ prepare_function_start (void)
>    init_expr ();
>    default_rtl_profile ();
>  
> -  if (flag_stack_usage_info)
> -    {
> -      cfun->su = ggc_cleared_alloc<stack_usage> ();
> -      cfun->su->static_stack_size = -1;
> -    }
> +  if (flag_stack_usage_info && !flag_callgraph_info)
> +    allocate_stack_usage_info ();
>  
>    cse_not_expected = ! optimize;
>  
> @@ -6373,12 +6383,49 @@ rest_of_handle_thread_prologue_and_epilogue (void)
>    cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
>  
>    /* The stack usage info is finalized during prologue expansion.  */
> -  if (flag_stack_usage_info)
> +  if (flag_stack_usage_info || flag_callgraph_info)
>      output_stack_usage ();
>  
>    return 0;
>  }
>  
> +/* Record a final call to CALLEE at LOCATION.  */
> +
> +void
> +record_final_call (tree callee, location_t location)
> +{
> +  if (!callee || CALLEE_FROM_CGRAPH_P (callee))
> +    return;
> +
> +  struct callinfo_callee datum = { location, callee };
> +  vec_safe_push (cfun->su->callees, datum);
> +}
> +
> +/* Record a dynamic allocation made for DECL_OR_EXP.  */
> +
> +void
> +record_dynamic_alloc (tree decl_or_exp)
> +{
> +  struct callinfo_dalloc datum;
> +
> +  if (DECL_P (decl_or_exp))
> +    {
> +      datum.location = DECL_SOURCE_LOCATION (decl_or_exp);
> +      const char *name = lang_hooks.decl_printable_name (decl_or_exp, 2);
> +      const char *dot = strrchr (name, '.');
> +      if (dot)
> +	name = dot + 1;
> +      datum.name = ggc_strdup (name);
> +    }
> +  else
> +    {
> +      datum.location = EXPR_LOCATION (decl_or_exp);
> +      datum.name = NULL;
> +    }
> +
> +  vec_safe_push (cfun->su->dallocs, datum);
> +}
> +
>  namespace {
>  
>  const pass_data pass_data_thread_prologue_and_epilogue =
> diff --git a/gcc/function.h b/gcc/function.h
> index 43ac5dff..14794c4 100644
> --- a/gcc/function.h
> +++ b/gcc/function.h
> @@ -192,6 +192,23 @@ public:
>    poly_int64 length;
>  };
>  
> +/* Describe emitted builtin calls for -fcallgraph-info.  Those that
> +   are not builtin are taken from cgraph edges.  */
> +struct GTY(()) callinfo_callee
> +{
> +  location_t location;
> +  tree decl;
> +};
> +#define CALLEE_FROM_CGRAPH_P(T)				\
> +  (!fndecl_built_in_p (T) && !DECL_IS_BUILTIN (T))
> +
> +/* Describe dynamic allocation for -fcallgraph-info=da.  */
> +struct GTY(()) callinfo_dalloc
> +{
> +  location_t location;
> +  char const *name;
> +};
> +
>  class GTY(()) stack_usage
>  {
>  public:
> @@ -210,6 +227,13 @@ public:
>    /* Nonzero if the amount of stack space allocated dynamically cannot
>       be bounded at compile-time.  */
>    unsigned int has_unbounded_dynamic_stack_size : 1;
> +
> +  /* Functions called within the function, if callgraph is enabled.  */
> +  vec<callinfo_callee, va_gc> *callees;
> +
> +  /* Dynamic allocations encountered within the function, if callgraph
> +     da is enabled.  */
> +  vec<callinfo_dalloc, va_gc> *dallocs;
>  };
>  
>  #define current_function_static_stack_size (cfun->su->static_stack_size)
> @@ -406,6 +430,12 @@ void add_local_decl (struct function *fun, tree d);
>  #define FOR_EACH_LOCAL_DECL(FUN, I, D)		\
>    FOR_EACH_VEC_SAFE_ELT_REVERSE ((FUN)->local_decls, I, D)
>  
> +/* Record a final call to CALLEE at LOCATION.  */
> +void record_final_call (tree callee, location_t location);
> +
> +/* Record a dynamic allocation made for DECL_OR_EXP.  */
> +void record_dynamic_alloc (tree decl_or_exp);
> +
>  /* If va_list_[gf]pr_size is set to this, it means we don't know how
>     many units need to be saved.  */
>  #define VA_LIST_MAX_GPR_SIZE	255
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index 12ed3f8..74fc45a 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -1698,6 +1698,10 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
>    t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
>  
>    gimplify_and_add (t, seq_p);
> +
> +  /* Record the dynamic allocation associated with DECL if requested.  */
> +  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
> +    record_dynamic_alloc (decl);
>  }
>  
>  /* A helper function to be called via walk_tree.  Mark all labels under *TP
> diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c
> index ef43dae..8916f7e4 100644
> --- a/gcc/optabs-libfuncs.c
> +++ b/gcc/optabs-libfuncs.c
> @@ -735,10 +735,6 @@ build_libfunc_function_visibility (const char *name, symbol_visibility vis)
>    DECL_VISIBILITY_SPECIFIED (decl) = 1;
>    gcc_assert (DECL_ASSEMBLER_NAME (decl));
>  
> -  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
> -     are the flags assigned by targetm.encode_section_info.  */
> -  SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
> -
>    return decl;
>  }
>  
> diff --git a/gcc/opts.c b/gcc/opts.c
> index 10b9f10..f46b468 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2433,6 +2433,32 @@ common_handle_option (struct gcc_options *opts,
>        /* Deferred.  */
>        break;
>  
> +    case OPT_fcallgraph_info:
> +      opts->x_flag_callgraph_info = CALLGRAPH_INFO_NAKED;
> +      break;
> +
> +    case OPT_fcallgraph_info_:
> +      {
> +	char *my_arg, *p;
> +	my_arg = xstrdup (arg);
> +	p = strtok (my_arg, ",");
> +	while (p)
> +	  {
> +	    if (strcmp (p, "su") == 0)
> +	      {
> +		opts->x_flag_callgraph_info |= CALLGRAPH_INFO_STACK_USAGE;
> +		opts->x_flag_stack_usage_info = true;
> +	      }
> +	    else if (strcmp (p, "da") == 0)
> +	      opts->x_flag_callgraph_info |= CALLGRAPH_INFO_DYNAMIC_ALLOC;
> +	    else
> +	      return 0;
> +	    p = strtok (NULL, ",");
> +	  }
> +	free (my_arg);
> +      }
> +      break;
> +
>      case OPT_fdiagnostics_show_location_:
>        diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value;
>        break;
> diff --git a/gcc/output.h b/gcc/output.h
> index 835d635..6cccada 100644
> --- a/gcc/output.h
> +++ b/gcc/output.h
> @@ -604,7 +604,7 @@ extern int maybe_assemble_visibility (tree);
>  
>  extern int default_address_cost (rtx, machine_mode, addr_space_t, bool);
>  
> -/* Output stack usage information.  */
> +/* Stack usage.  */
>  extern void output_stack_usage (void);
>  
>  #endif /* ! GCC_OUTPUT_H */
> diff --git a/gcc/print-tree.c b/gcc/print-tree.c
> index 6dcbb2d..bd09ec4 100644
> --- a/gcc/print-tree.c
> +++ b/gcc/print-tree.c
> @@ -1035,6 +1035,82 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
>    fprintf (file, ">");
>  }
>  
> +/* Print the identifier for DECL according to FLAGS.  */
> +
> +void
> +print_decl_identifier (FILE *file, tree decl, int flags)
> +{
> +  bool needs_colon = false;
> +  const char *name;
> +  char c;
> +
> +  if (flags & PRINT_DECL_ORIGIN)
> +    {
> +      if (DECL_IS_BUILTIN (decl))
> +	fputs ("<built-in>", file);
> +      else
> +	{
> +	  expanded_location loc
> +	    = expand_location (DECL_SOURCE_LOCATION (decl));
> +	  fprintf (file, "%s:%d:%d", loc.file, loc.line, loc.column);
> +	}
> +      needs_colon = true;
> +    }
> +
> +  if (flags & PRINT_DECL_UNIQUE_NAME)
> +    {
> +      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
> +      if (!TREE_PUBLIC (decl)
> +	  || (DECL_WEAK (decl) && !DECL_EXTERNAL (decl)))
> +	/* The symbol has internal or weak linkage so its assembler name
> +	   is not necessarily unique among the compilation units of the
> +	   program.  We therefore have to further mangle it.  But we can't
> +	   simply use DECL_SOURCE_FILE because it contains the name of the
> +	   file the symbol originates from so, e.g. for function templates
> +	   in C++ where the templates are defined in a header file, we can
> +	   have symbols with the same assembler name and DECL_SOURCE_FILE.
> +	   That's why we use the name of the top-level source file of the
> +	   compilation unit.  ??? Unnecessary for Ada.  */
> +	name = ACONCAT ((main_input_filename, ":", name, NULL));
> +    }
> +  else if (flags & PRINT_DECL_NAME)
> +    {
> +      /* We don't want to print the full qualified name because it can be long,
> +	 so we strip the scope prefix, but we may need to deal with the suffix
> +	 created by the compiler.  */
> +      const char *suffix = strchr (IDENTIFIER_POINTER (DECL_NAME (decl)), '.');
> +      name = lang_hooks.decl_printable_name (decl, 2);
> +      if (suffix)
> +	{
> +	  const char *dot = strchr (name, '.');
> +	  while (dot && strcasecmp (dot, suffix) != 0)
> +	    {
> +	      name = dot + 1;
> +	      dot = strchr (name, '.');
> +	    }
> +	}
> +      else
> +	{
> +	  const char *dot = strrchr (name, '.');
> +	  if (dot)
> +	    name = dot + 1;
> +	}
> +    }
> +  else
> +    return;
> +
> +  if (needs_colon)
> +    fputc (':', file);
> +
> +  while ((c = *name++) != '\0')
> +    {
> +      /* Strip double-quotes because of VCG.  */
> +      if (c == '"')
> +	continue;
> +      fputc (c, file);
> +    }
> +}
> +
>  
>  /* Print the node NODE on standard error, for debugging.
>     Most nodes referred to by this one are printed recursively
> diff --git a/gcc/print-tree.h b/gcc/print-tree.h
> index 1d4fe6e..cbea48c 100644
> --- a/gcc/print-tree.h
> +++ b/gcc/print-tree.h
> @@ -42,5 +42,9 @@ extern void print_node (FILE *, const char *, tree, int,
>  extern void print_node_brief (FILE *, const char *, const_tree, int);
>  extern void indent_to (FILE *, int);
>  #endif
> +#define PRINT_DECL_ORIGIN       0x1
> +#define PRINT_DECL_NAME         0x2
> +#define PRINT_DECL_UNIQUE_NAME  0x4
> +extern void print_decl_identifier (FILE *, tree, int flags);
>  
>  #endif  // GCC_PRINT_TREE_H
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index 00a5e83..8aaf216 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "dumpfile.h"
>  #include "ipa-fnsummary.h"
>  #include "dump-context.h"
> +#include "print-tree.h"
>  #include "optinfo-emit-json.h"
>  
>  #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
> @@ -174,6 +175,8 @@ const char *user_label_prefix;
>  
>  FILE *asm_out_file;
>  FILE *aux_info_file;
> +FILE *callgraph_info_file = NULL;
> +static bitmap callgraph_info_external_printed;
>  FILE *stack_usage_file = NULL;
>  
>  /* The current working directory of a translation.  It's generally the
> @@ -913,8 +916,8 @@ alloc_for_identifier_to_locale (size_t len)
>  }
>  
>  /* Output stack usage information.  */
> -void
> -output_stack_usage (void)
> +static void
> +output_stack_usage_1 (FILE *cf)
>  {
>    static bool warning_issued = false;
>    enum stack_usage_kind_type { STATIC = 0, DYNAMIC, DYNAMIC_BOUNDED };
> @@ -970,41 +973,17 @@ output_stack_usage (void)
>        stack_usage += current_function_dynamic_stack_size;
>      }
>  
> +  if (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE)
> +    fprintf (cf, "\\n" HOST_WIDE_INT_PRINT_DEC " bytes (%s)",
> +	     stack_usage,
> +	     stack_usage_kind_str[stack_usage_kind]);
> +
>    if (stack_usage_file)
>      {
> -      expanded_location loc
> -	= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
> -      /* We don't want to print the full qualified name because it can be long,
> -	 so we strip the scope prefix, but we may need to deal with the suffix
> -	 created by the compiler.  */
> -      const char *suffix
> -	= strchr (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), '.');
> -      const char *name
> -	= lang_hooks.decl_printable_name (current_function_decl, 2);
> -      if (suffix)
> -	{
> -	  const char *dot = strchr (name, '.');
> -	  while (dot && strcasecmp (dot, suffix) != 0)
> -	    {
> -	      name = dot + 1;
> -	      dot = strchr (name, '.');
> -	    }
> -	}
> -      else
> -	{
> -	  const char *dot = strrchr (name, '.');
> -	  if (dot)
> -	    name = dot + 1;
> -	}
> -
> -      fprintf (stack_usage_file,
> -	       "%s:%d:%d:%s\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
> -	       loc.file == NULL ? "(artificial)" : lbasename (loc.file),
> -	       loc.line,
> -	       loc.column,
> -	       name,
> -	       stack_usage,
> -	       stack_usage_kind_str[stack_usage_kind]);
> +      print_decl_identifier (stack_usage_file, current_function_decl,
> +			     PRINT_DECL_ORIGIN | PRINT_DECL_NAME);
> +      fprintf (stack_usage_file, "\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
> +	       stack_usage, stack_usage_kind_str[stack_usage_kind]);
>      }
>  
>    if (warn_stack_usage >= 0 && warn_stack_usage < HOST_WIDE_INT_MAX)
> @@ -1026,14 +1005,127 @@ output_stack_usage (void)
>      }
>  }
>  
> -/* Open an auxiliary output file.  */
> +/* Dump placeholder node for indirect calls in VCG format.  */
> +
> +#define INDIRECT_CALL_NAME  "__indirect_call"
> +
> +static void
> +dump_final_node_vcg_start (FILE *f, tree decl)
> +{
> +  fputs ("node: { title: \"", f);
> +  if (decl)
> +    print_decl_identifier (f, decl, PRINT_DECL_UNIQUE_NAME);
> +  else
> +    fputs (INDIRECT_CALL_NAME, f);
> +  fputs ("\" label: \"", f);
> +  if (decl)
> +    {
> +      print_decl_identifier (f, decl, PRINT_DECL_NAME);
> +      fputs ("\\n", f);
> +      print_decl_identifier (f, decl, PRINT_DECL_ORIGIN);
> +    }
> +  else
> +    fputs ("Indirect Call Placeholder", f);
> +}
> +
> +/* Dump final cgraph edge in VCG format.  */
> +
> +static void
> +dump_final_callee_vcg (FILE *f, location_t location, tree callee)
> +{
> +  if ((!callee || DECL_EXTERNAL (callee))
> +      && bitmap_set_bit (callgraph_info_external_printed,
> +			 callee ? DECL_UID (callee) + 1 : 0))
> +    {
> +      dump_final_node_vcg_start (f, callee);
> +      fputs ("\" shape : ellipse }\n", f);
> +    }
> +
> +  fputs ("edge: { sourcename: \"", f);
> +  print_decl_identifier (f, current_function_decl, PRINT_DECL_UNIQUE_NAME);
> +  fputs ("\" targetname: \"", f);
> +  if (callee)
> +    print_decl_identifier (f, callee, PRINT_DECL_UNIQUE_NAME);
> +  else
> +    fputs (INDIRECT_CALL_NAME, f);
> +  if (LOCATION_LOCUS (location) != UNKNOWN_LOCATION)
> +    {
> +      expanded_location loc;
> +      fputs ("\" label: \"", f);
> +      loc = expand_location (location);
> +      fprintf (f, "%s:%d:%d", loc.file, loc.line, loc.column);
> +    }
> +  fputs ("\" }\n", f);
> +}
> +
> +/* Dump final cgraph node in VCG format.  */
> +
> +static void
> +dump_final_node_vcg (FILE *f)
> +{
> +  dump_final_node_vcg_start (f, current_function_decl);
> +
> +  if (flag_stack_usage_info
> +      || (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE))
> +    output_stack_usage_1 (f);
> +
> +  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
> +    {
> +      fprintf (f, "\\n%u dynamic objects", vec_safe_length (cfun->su->dallocs));
> +
> +      unsigned i;
> +      callinfo_dalloc *cda;
> +      FOR_EACH_VEC_SAFE_ELT (cfun->su->dallocs, i, cda)
> +	{
> +	  expanded_location loc = expand_location (cda->location);
> +	  fprintf (f, "\\n %s", cda->name);
> +	  fprintf (f, " %s:%d:%d", loc.file, loc.line, loc.column);
> +	}
> +
> +      vec_free (cfun->su->dallocs);
> +      cfun->su->dallocs = NULL;
> +    }
> +
> +  fputs ("\" }\n", f);
> +
> +  unsigned i;
> +  callinfo_callee *c;
> +  FOR_EACH_VEC_SAFE_ELT (cfun->su->callees, i, c)
> +    dump_final_callee_vcg (f, c->location, c->decl);
> +  vec_free (cfun->su->callees);
> +  cfun->su->callees = NULL;
> +
> +  cgraph_node *cnode = cgraph_node::get (current_function_decl);
> +  for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
> +    if (CALLEE_FROM_CGRAPH_P (e->callee->decl))
> +      dump_final_callee_vcg (f, gimple_location (e->call_stmt),
> +			     e->callee->decl);
> +  for (cgraph_edge *e = cnode->indirect_calls; e; e = e->next_callee)
> +    dump_final_callee_vcg (f, gimple_location (e->call_stmt), NULL);
> +}
> +
> +/* Output stack usage and callgraph info, as requested.  */
> +void
> +output_stack_usage (void)
> +{
> +  if (flag_callgraph_info)
> +    dump_final_node_vcg (callgraph_info_file);
> +  else
> +    output_stack_usage_1 (NULL);
> +}
> +
> +/* Open an auxiliary or dump output file.  */
>  static FILE *
>  open_auxiliary_file (const char *ext)
>  {
>    char *filename;
>    FILE *file;
> +  const char *base_name = aux_base_name;
>  
> -  filename = concat (aux_base_name, ".", ext, NULL);
> +  if (in_lto_p)
> +    base_name = dump_base_name;
> +
> +  filename = concat (base_name, ".", ext, NULL);
>    file = fopen (filename, "w");
>    if (!file)
>      fatal_error (input_location, "cannot open %s for writing: %m", filename);
> @@ -1900,6 +1992,17 @@ lang_dependent_init (const char *name)
>        /* If stack usage information is desired, open the output file.  */
>        if (flag_stack_usage && !flag_generate_lto)
>  	stack_usage_file = open_auxiliary_file ("su");
> +
> +      /* If call graph information is desired, open the output file.  */
> +      if (flag_callgraph_info && !flag_generate_lto)
> +	{
> +	  callgraph_info_file = open_auxiliary_file ("ci");
> +	  /* Write the file header.  */
> +	  fprintf (callgraph_info_file,
> +		   "graph: { title: \"%s\"\n", main_input_filename);
> +	  bitmap_obstack_initialize (NULL);
> +	  callgraph_info_external_printed = BITMAP_ALLOC (NULL);
> +	}
>      }
>  
>    /* This creates various _DECL nodes, so needs to be called after the
> @@ -2053,6 +2156,15 @@ finalize (bool no_backend)
>        stack_usage_file = NULL;
>      }
>  
> +  if (callgraph_info_file)
> +    {
> +      fputs ("}\n", callgraph_info_file);
> +      fclose (callgraph_info_file);
> +      callgraph_info_file = NULL;
> +      BITMAP_FREE (callgraph_info_external_printed);
> +      bitmap_obstack_release (NULL);
> +    }
> +
>    if (seen_error ())
>      coverage_remove_note_file ();
>  
> 
> 
>
Alexandre Oliva Nov. 6, 2019, 10:53 a.m. UTC | #13
On Nov  4, 2019, Richard Biener <rguenther@suse.de> wrote:

> Please leave that part out for now, I'd rather discuss this separately
> from the bulk of the patch.  That is, I wonder why we shouldn't
> simply adjust aux_base_name to something else for -flto [in the driver].

*nod*, that makes sense to me.  After seeing your suggestion, I started
looking into how to do that, but didn't get very far yet.  For now, I've
split that bit out of the main patch.  So I'm installing the first, big
one, and not installing the latter, posted mainly so that the
documentation bit can be picked up.  Thanks!


introduce -fcallgraph-info option

This was first submitted many years ago
https://gcc.gnu.org/ml/gcc-patches/2010-10/msg02468.html

The command line option -fcallgraph-info is added and makes the
compiler generate another output file (xxx.ci) for each compilation
unit (or LTO partitoin), which is a valid VCG file (you can launch
your favorite VCG viewer on it unmodified) and contains the "final"
callgraph of the unit.  "final" is a bit of a misnomer as this is
actually the callgraph at RTL expansion time, but since most
high-level optimizations are done at the Tree level and RTL doesn't
usually fiddle with calls, it's final in almost all cases.  Moreover,
the nodes can be decorated with additional info: -fcallgraph-info=su
adds stack usage info and -fcallgraph-info=da dynamic allocation info.


for  gcc/ChangeLog
From  Eric Botcazou  <ebotcazou@adacore.com>, Alexandre Oliva  <oliva@adacore.com>

	* common.opt (-fcallgraph-info[=]): New option.
	* doc/invoke.texi (Developer options): Document it.
	* opts.c (common_handle_option): Handle it.
	* builtins.c (expand_builtin_alloca): Record allocation if
	-fcallgraph-info=da.
	* calls.c (expand_call): If -fcallgraph-info, record the call.
	(emit_library_call_value_1): Likewise.
	* flag-types.h (enum callgraph_info_type): New type.
	* explow.c: Include stringpool.h.
	(set_stack_check_libfunc): Set SET_SYMBOL_REF_DECL on the symbol.
	* function.c (allocate_stack_usage_info): New.
	(allocate_struct_function): Call it for -fcallgraph-info.
	(prepare_function_start): Call it otherwise.
	(record_final_call, record_dynamic_alloc): New.
	* function.h (struct callinfo_callee): New.
	(CALLEE_FROM_CGRAPH_P): New.
	(struct callinfo_dalloc): New.
	(struct stack_usage): Add callees and dallocs.
	(record_final_call, record_dynamic_alloc): Declare.
	* gimplify.c (gimplify_decl_expr): Record dynamically-allocated
	object if -fcallgraph-info=da.
	* optabs-libfuncs.c (build_libfunc_function): Keep SYMBOL_REF_DECL.
	* print-tree.h (print_decl_identifier): Declare.
	(PRINT_DECL_ORIGIN, PRINT_DECL_NAME, PRINT_DECL_UNIQUE_NAME): New.
	* print-tree.c: Include print-tree.h.
	(print_decl_identifier): New function.
	* toplev.c: Include print-tree.h.
	(callgraph_info_file): New global variable.
	(callgraph_info_external_printed): Likewise.
	(output_stack_usage): Rename to...
	(output_stack_usage_1): ... this.  Make it static, add cf
	parameter.  If -fcallgraph-info=su, print stack usage to cf.
	If -fstack-usage, use print_decl_identifier for
	pretty-printing.
	(INDIRECT_CALL_NAME): New.
	(dump_final_node_vcg_start): New.
	(dump_final_callee_vcg, dump_final_node_vcg): New.
	(output_stack_usage): New.
	(lang_dependent_init): Open and start file if
	-fcallgraph-info.  Allocated callgraph_info_external_printed.
	(finalize): If callgraph_info_file is not null, finish it,
	close it, and release callgraph_info_external_printed.

for  gcc/ada/ChangeLog

	* gcc-interface/misc.c (callgraph_info_file): Delete.
---
 gcc/ada/gcc-interface/misc.c |    3 -
 gcc/builtins.c               |    4 +
 gcc/calls.c                  |    6 +
 gcc/common.opt               |    8 ++
 gcc/doc/invoke.texi          |   23 +++++
 gcc/explow.c                 |    5 +
 gcc/flag-types.h             |   16 ++++
 gcc/function.c               |   59 +++++++++++++-
 gcc/function.h               |   30 +++++++
 gcc/gimplify.c               |    4 +
 gcc/optabs-libfuncs.c        |    4 -
 gcc/opts.c                   |   26 ++++++
 gcc/output.h                 |    2 
 gcc/print-tree.c             |   76 ++++++++++++++++++
 gcc/print-tree.h             |    4 +
 gcc/toplev.c                 |  178 ++++++++++++++++++++++++++++++++++--------
 16 files changed, 397 insertions(+), 51 deletions(-)

diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 4abd4d5..d68b373 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -54,9 +54,6 @@
 #include "ada-tree.h"
 #include "gigi.h"
 
-/* This symbol needs to be defined for the front-end.  */
-void *callgraph_info_file = NULL;
-
 /* Command-line argc and argv.  These variables are global since they are
    imported in back_end.adb.  */
 unsigned int save_argc;
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5d811f1..bd30238 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5406,6 +5406,10 @@ expand_builtin_alloca (tree exp)
     = allocate_dynamic_stack_space (op0, 0, align, max_size, alloca_for_var);
   result = convert_memory_address (ptr_mode, result);
 
+  /* Dynamic allocations for variables are recorded during gimplification.  */
+  if (!alloca_for_var && (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC))
+    record_dynamic_alloc (exp);
+
   return result;
 }
 
diff --git a/gcc/calls.c b/gcc/calls.c
index e2b770f..6292135 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -3759,6 +3759,9 @@ expand_call (tree exp, rtx target, int ignore)
 
   preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
 
+  if (flag_callgraph_info)
+    record_final_call (fndecl, EXPR_LOCATION (exp));
+
   /* We want to make two insn chains; one for a sibling call, the other
      for a normal call.  We will select one of the two chains after
      initial RTL generation is complete.  */
@@ -5343,6 +5346,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
   before_call = get_last_insn ();
 
+  if (flag_callgraph_info)
+    record_final_call (SYMBOL_REF_DECL (orgfun), UNKNOWN_LOCATION);
+
   /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
      will set inhibit_defer_pop to that value.  */
   /* The return type is needed to decide how many bytes the function pops.
diff --git a/gcc/common.opt b/gcc/common.opt
index cc279f4..299eac6 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1091,6 +1091,14 @@ fbtr-bb-exclusive
 Common Ignore
 Does nothing.  Preserved for backward compatibility.
 
+fcallgraph-info
+Common Report RejectNegative Var(flag_callgraph_info) Init(NO_CALLGRAPH_INFO);
+Output callgraph information on a per-file basis.
+
+fcallgraph-info=
+Common Report RejectNegative Joined
+Output callgraph information on a per-file basis with decorations.
+
 fcall-saved-
 Common Joined RejectNegative Var(common_deferred_options) Defer
 -fcall-saved-<register>	Mark <register> as being preserved across functions.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index faa7fa9..179452c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -584,8 +584,9 @@ Objective-C and Objective-C++ Dialects}.
 @item Developer Options
 @xref{Developer Options,,GCC Developer Options}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
--dumpfullversion  -fchecking  -fchecking=@var{n}  -fdbg-cnt-list @gol
--fdbg-cnt=@var{counter-value-list} @gol
+-dumpfullversion  -fcallgraph-info@r{[}=su,da@r{]}
+-fchecking  -fchecking=@var{n}
+-fdbg-cnt-list @gol  -fdbg-cnt=@var{counter-value-list} @gol
 -fdisable-ipa-@var{pass_name} @gol
 -fdisable-rtl-@var{pass_name} @gol
 -fdisable-rtl-@var{pass-name}=@var{range-list} @gol
@@ -14564,6 +14565,24 @@ The files are created in the directory of the output file.
 
 @table @gcctabopt
 
+@item -fcallgraph-info
+@itemx -fcallgraph-info=@var{MARKERS}
+@opindex fcallgraph-info
+Makes the compiler output callgraph information for the program, on a
+per-object-file basis.  The information is generated in the common VCG
+format.  It can be decorated with additional, per-node and/or per-edge
+information, if a list of comma-separated markers is additionally
+specified.  When the @code{su} marker is specified, the callgraph is
+decorated with stack usage information; it is equivalent to
+@option{-fstack-usage}.  When the @code{da} marker is specified, the
+callgraph is decorated with information about dynamically allocated
+objects.
+
+When compiling with @option{-flto}, no callgraph information is output
+along with the object file.  At LTO link time, @option{-fcallgraph-info}
+may generate multiple callgraph information files next to intermediate
+LTO output files.
+
 @item -d@var{letters}
 @itemx -fdump-rtl-@var{pass}
 @itemx -fdump-rtl-@var{pass}=@var{filename}
diff --git a/gcc/explow.c b/gcc/explow.c
index 7eb854b..83c7863 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dojump.h"
 #include "explow.h"
 #include "expr.h"
+#include "stringpool.h"
 #include "common/common-target.h"
 #include "output.h"
 #include "params.h"
@@ -1611,6 +1612,10 @@ set_stack_check_libfunc (const char *libfunc_name)
 {
   gcc_assert (stack_check_libfunc == NULL_RTX);
   stack_check_libfunc = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
+  tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+			  get_identifier (libfunc_name), void_type_node);
+  DECL_EXTERNAL (decl) = 1;
+  SET_SYMBOL_REF_DECL (stack_check_libfunc, decl);
 }
 
 /* Emit one stack probe at ADDRESS, an address within the stack.  */
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index a210328..b23d3a2 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -200,6 +200,22 @@ enum stack_check_type
   FULL_BUILTIN_STACK_CHECK
 };
 
+/* Type of callgraph information.  */
+enum callgraph_info_type
+{
+  /* No information.  */
+  NO_CALLGRAPH_INFO = 0,
+
+  /* Naked callgraph.  */
+  CALLGRAPH_INFO_NAKED = 1,
+
+  /* Callgraph decorated with stack usage information.  */
+  CALLGRAPH_INFO_STACK_USAGE = 2,
+
+  /* Callgraph decoration with dynamic allocation information.  */
+  CALLGRAPH_INFO_DYNAMIC_ALLOC = 4
+};
+
 /* Floating-point contraction mode.  */
 enum fp_contract_mode {
   FP_CONTRACT_OFF = 0,
diff --git a/gcc/function.c b/gcc/function.c
index a1c76a4..3f79a38 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4725,6 +4725,16 @@ get_last_funcdef_no (void)
   return funcdef_no;
 }
 
+/* Allocate and initialize the stack usage info data structure for the
+   current function.  */
+static void
+allocate_stack_usage_info (void)
+{
+  gcc_assert (!cfun->su);
+  cfun->su = ggc_cleared_alloc<stack_usage> ();
+  cfun->su->static_stack_size = -1;
+}
+
 /* Allocate a function structure for FNDECL and set its contents
    to the defaults.  Set cfun to the newly-allocated object.
    Some of the helper functions invoked during initialization assume
@@ -4802,6 +4812,9 @@ allocate_struct_function (tree fndecl, bool abstract_p)
 
       if (!profile_flag && !flag_instrument_function_entry_exit)
 	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
+
+      if (flag_callgraph_info)
+	allocate_stack_usage_info ();
     }
 
   /* Don't enable begin stmt markers if var-tracking at assignments is
@@ -4846,11 +4859,8 @@ prepare_function_start (void)
   init_expr ();
   default_rtl_profile ();
 
-  if (flag_stack_usage_info)
-    {
-      cfun->su = ggc_cleared_alloc<stack_usage> ();
-      cfun->su->static_stack_size = -1;
-    }
+  if (flag_stack_usage_info && !flag_callgraph_info)
+    allocate_stack_usage_info ();
 
   cse_not_expected = ! optimize;
 
@@ -6373,12 +6383,49 @@ rest_of_handle_thread_prologue_and_epilogue (void)
   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
 
   /* The stack usage info is finalized during prologue expansion.  */
-  if (flag_stack_usage_info)
+  if (flag_stack_usage_info || flag_callgraph_info)
     output_stack_usage ();
 
   return 0;
 }
 
+/* Record a final call to CALLEE at LOCATION.  */
+
+void
+record_final_call (tree callee, location_t location)
+{
+  if (!callee || CALLEE_FROM_CGRAPH_P (callee))
+    return;
+
+  struct callinfo_callee datum = { location, callee };
+  vec_safe_push (cfun->su->callees, datum);
+}
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+
+void
+record_dynamic_alloc (tree decl_or_exp)
+{
+  struct callinfo_dalloc datum;
+
+  if (DECL_P (decl_or_exp))
+    {
+      datum.location = DECL_SOURCE_LOCATION (decl_or_exp);
+      const char *name = lang_hooks.decl_printable_name (decl_or_exp, 2);
+      const char *dot = strrchr (name, '.');
+      if (dot)
+	name = dot + 1;
+      datum.name = ggc_strdup (name);
+    }
+  else
+    {
+      datum.location = EXPR_LOCATION (decl_or_exp);
+      datum.name = NULL;
+    }
+
+  vec_safe_push (cfun->su->dallocs, datum);
+}
+
 namespace {
 
 const pass_data pass_data_thread_prologue_and_epilogue =
diff --git a/gcc/function.h b/gcc/function.h
index 43ac5dff..14794c4 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -192,6 +192,23 @@ public:
   poly_int64 length;
 };
 
+/* Describe emitted builtin calls for -fcallgraph-info.  Those that
+   are not builtin are taken from cgraph edges.  */
+struct GTY(()) callinfo_callee
+{
+  location_t location;
+  tree decl;
+};
+#define CALLEE_FROM_CGRAPH_P(T)				\
+  (!fndecl_built_in_p (T) && !DECL_IS_BUILTIN (T))
+
+/* Describe dynamic allocation for -fcallgraph-info=da.  */
+struct GTY(()) callinfo_dalloc
+{
+  location_t location;
+  char const *name;
+};
+
 class GTY(()) stack_usage
 {
 public:
@@ -210,6 +227,13 @@ public:
   /* Nonzero if the amount of stack space allocated dynamically cannot
      be bounded at compile-time.  */
   unsigned int has_unbounded_dynamic_stack_size : 1;
+
+  /* Functions called within the function, if callgraph is enabled.  */
+  vec<callinfo_callee, va_gc> *callees;
+
+  /* Dynamic allocations encountered within the function, if callgraph
+     da is enabled.  */
+  vec<callinfo_dalloc, va_gc> *dallocs;
 };
 
 #define current_function_static_stack_size (cfun->su->static_stack_size)
@@ -406,6 +430,12 @@ void add_local_decl (struct function *fun, tree d);
 #define FOR_EACH_LOCAL_DECL(FUN, I, D)		\
   FOR_EACH_VEC_SAFE_ELT_REVERSE ((FUN)->local_decls, I, D)
 
+/* Record a final call to CALLEE at LOCATION.  */
+void record_final_call (tree callee, location_t location);
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+void record_dynamic_alloc (tree decl_or_exp);
+
 /* If va_list_[gf]pr_size is set to this, it means we don't know how
    many units need to be saved.  */
 #define VA_LIST_MAX_GPR_SIZE	255
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 12ed3f8..74fc45a 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1698,6 +1698,10 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
   t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
 
   gimplify_and_add (t, seq_p);
+
+  /* Record the dynamic allocation associated with DECL if requested.  */
+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+    record_dynamic_alloc (decl);
 }
 
 /* A helper function to be called via walk_tree.  Mark all labels under *TP
diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c
index ef43dae..8916f7e4 100644
--- a/gcc/optabs-libfuncs.c
+++ b/gcc/optabs-libfuncs.c
@@ -735,10 +735,6 @@ build_libfunc_function_visibility (const char *name, symbol_visibility vis)
   DECL_VISIBILITY_SPECIFIED (decl) = 1;
   gcc_assert (DECL_ASSEMBLER_NAME (decl));
 
-  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
-     are the flags assigned by targetm.encode_section_info.  */
-  SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
-
   return decl;
 }
 
diff --git a/gcc/opts.c b/gcc/opts.c
index 10b9f10..f46b468 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2433,6 +2433,32 @@ common_handle_option (struct gcc_options *opts,
       /* Deferred.  */
       break;
 
+    case OPT_fcallgraph_info:
+      opts->x_flag_callgraph_info = CALLGRAPH_INFO_NAKED;
+      break;
+
+    case OPT_fcallgraph_info_:
+      {
+	char *my_arg, *p;
+	my_arg = xstrdup (arg);
+	p = strtok (my_arg, ",");
+	while (p)
+	  {
+	    if (strcmp (p, "su") == 0)
+	      {
+		opts->x_flag_callgraph_info |= CALLGRAPH_INFO_STACK_USAGE;
+		opts->x_flag_stack_usage_info = true;
+	      }
+	    else if (strcmp (p, "da") == 0)
+	      opts->x_flag_callgraph_info |= CALLGRAPH_INFO_DYNAMIC_ALLOC;
+	    else
+	      return 0;
+	    p = strtok (NULL, ",");
+	  }
+	free (my_arg);
+      }
+      break;
+
     case OPT_fdiagnostics_show_location_:
       diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value;
       break;
diff --git a/gcc/output.h b/gcc/output.h
index 835d635..6cccada 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -604,7 +604,7 @@ extern int maybe_assemble_visibility (tree);
 
 extern int default_address_cost (rtx, machine_mode, addr_space_t, bool);
 
-/* Output stack usage information.  */
+/* Stack usage.  */
 extern void output_stack_usage (void);
 
 #endif /* ! GCC_OUTPUT_H */
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 6dcbb2d..bd09ec4 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -1035,6 +1035,82 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
   fprintf (file, ">");
 }
 
+/* Print the identifier for DECL according to FLAGS.  */
+
+void
+print_decl_identifier (FILE *file, tree decl, int flags)
+{
+  bool needs_colon = false;
+  const char *name;
+  char c;
+
+  if (flags & PRINT_DECL_ORIGIN)
+    {
+      if (DECL_IS_BUILTIN (decl))
+	fputs ("<built-in>", file);
+      else
+	{
+	  expanded_location loc
+	    = expand_location (DECL_SOURCE_LOCATION (decl));
+	  fprintf (file, "%s:%d:%d", loc.file, loc.line, loc.column);
+	}
+      needs_colon = true;
+    }
+
+  if (flags & PRINT_DECL_UNIQUE_NAME)
+    {
+      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+      if (!TREE_PUBLIC (decl)
+	  || (DECL_WEAK (decl) && !DECL_EXTERNAL (decl)))
+	/* The symbol has internal or weak linkage so its assembler name
+	   is not necessarily unique among the compilation units of the
+	   program.  We therefore have to further mangle it.  But we can't
+	   simply use DECL_SOURCE_FILE because it contains the name of the
+	   file the symbol originates from so, e.g. for function templates
+	   in C++ where the templates are defined in a header file, we can
+	   have symbols with the same assembler name and DECL_SOURCE_FILE.
+	   That's why we use the name of the top-level source file of the
+	   compilation unit.  ??? Unnecessary for Ada.  */
+	name = ACONCAT ((main_input_filename, ":", name, NULL));
+    }
+  else if (flags & PRINT_DECL_NAME)
+    {
+      /* We don't want to print the full qualified name because it can be long,
+	 so we strip the scope prefix, but we may need to deal with the suffix
+	 created by the compiler.  */
+      const char *suffix = strchr (IDENTIFIER_POINTER (DECL_NAME (decl)), '.');
+      name = lang_hooks.decl_printable_name (decl, 2);
+      if (suffix)
+	{
+	  const char *dot = strchr (name, '.');
+	  while (dot && strcasecmp (dot, suffix) != 0)
+	    {
+	      name = dot + 1;
+	      dot = strchr (name, '.');
+	    }
+	}
+      else
+	{
+	  const char *dot = strrchr (name, '.');
+	  if (dot)
+	    name = dot + 1;
+	}
+    }
+  else
+    return;
+
+  if (needs_colon)
+    fputc (':', file);
+
+  while ((c = *name++) != '\0')
+    {
+      /* Strip double-quotes because of VCG.  */
+      if (c == '"')
+	continue;
+      fputc (c, file);
+    }
+}
+
 
 /* Print the node NODE on standard error, for debugging.
    Most nodes referred to by this one are printed recursively
diff --git a/gcc/print-tree.h b/gcc/print-tree.h
index 1d4fe6e..cbea48c 100644
--- a/gcc/print-tree.h
+++ b/gcc/print-tree.h
@@ -42,5 +42,9 @@ extern void print_node (FILE *, const char *, tree, int,
 extern void print_node_brief (FILE *, const char *, const_tree, int);
 extern void indent_to (FILE *, int);
 #endif
+#define PRINT_DECL_ORIGIN       0x1
+#define PRINT_DECL_NAME         0x2
+#define PRINT_DECL_UNIQUE_NAME  0x4
+extern void print_decl_identifier (FILE *, tree, int flags);
 
 #endif  // GCC_PRINT_TREE_H
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 00a5e83..18fea1c 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dumpfile.h"
 #include "ipa-fnsummary.h"
 #include "dump-context.h"
+#include "print-tree.h"
 #include "optinfo-emit-json.h"
 
 #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
@@ -174,6 +175,8 @@ const char *user_label_prefix;
 
 FILE *asm_out_file;
 FILE *aux_info_file;
+FILE *callgraph_info_file = NULL;
+static bitmap callgraph_info_external_printed;
 FILE *stack_usage_file = NULL;
 
 /* The current working directory of a translation.  It's generally the
@@ -913,8 +916,8 @@ alloc_for_identifier_to_locale (size_t len)
 }
 
 /* Output stack usage information.  */
-void
-output_stack_usage (void)
+static void
+output_stack_usage_1 (FILE *cf)
 {
   static bool warning_issued = false;
   enum stack_usage_kind_type { STATIC = 0, DYNAMIC, DYNAMIC_BOUNDED };
@@ -970,41 +973,17 @@ output_stack_usage (void)
       stack_usage += current_function_dynamic_stack_size;
     }
 
+  if (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE)
+    fprintf (cf, "\\n" HOST_WIDE_INT_PRINT_DEC " bytes (%s)",
+	     stack_usage,
+	     stack_usage_kind_str[stack_usage_kind]);
+
   if (stack_usage_file)
     {
-      expanded_location loc
-	= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
-      /* We don't want to print the full qualified name because it can be long,
-	 so we strip the scope prefix, but we may need to deal with the suffix
-	 created by the compiler.  */
-      const char *suffix
-	= strchr (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), '.');
-      const char *name
-	= lang_hooks.decl_printable_name (current_function_decl, 2);
-      if (suffix)
-	{
-	  const char *dot = strchr (name, '.');
-	  while (dot && strcasecmp (dot, suffix) != 0)
-	    {
-	      name = dot + 1;
-	      dot = strchr (name, '.');
-	    }
-	}
-      else
-	{
-	  const char *dot = strrchr (name, '.');
-	  if (dot)
-	    name = dot + 1;
-	}
-
-      fprintf (stack_usage_file,
-	       "%s:%d:%d:%s\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
-	       loc.file == NULL ? "(artificial)" : lbasename (loc.file),
-	       loc.line,
-	       loc.column,
-	       name,
-	       stack_usage,
-	       stack_usage_kind_str[stack_usage_kind]);
+      print_decl_identifier (stack_usage_file, current_function_decl,
+			     PRINT_DECL_ORIGIN | PRINT_DECL_NAME);
+      fprintf (stack_usage_file, "\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
+	       stack_usage, stack_usage_kind_str[stack_usage_kind]);
     }
 
   if (warn_stack_usage >= 0 && warn_stack_usage < HOST_WIDE_INT_MAX)
@@ -1026,6 +1005,115 @@ output_stack_usage (void)
     }
 }
 
+/* Dump placeholder node for indirect calls in VCG format.  */
+
+#define INDIRECT_CALL_NAME  "__indirect_call"
+
+static void
+dump_final_node_vcg_start (FILE *f, tree decl)
+{
+  fputs ("node: { title: \"", f);
+  if (decl)
+    print_decl_identifier (f, decl, PRINT_DECL_UNIQUE_NAME);
+  else
+    fputs (INDIRECT_CALL_NAME, f);
+  fputs ("\" label: \"", f);
+  if (decl)
+    {
+      print_decl_identifier (f, decl, PRINT_DECL_NAME);
+      fputs ("\\n", f);
+      print_decl_identifier (f, decl, PRINT_DECL_ORIGIN);
+    }
+  else
+    fputs ("Indirect Call Placeholder", f);
+}
+
+/* Dump final cgraph edge in VCG format.  */
+
+static void
+dump_final_callee_vcg (FILE *f, location_t location, tree callee)
+{
+  if ((!callee || DECL_EXTERNAL (callee))
+      && bitmap_set_bit (callgraph_info_external_printed,
+			 callee ? DECL_UID (callee) + 1 : 0))
+    {
+      dump_final_node_vcg_start (f, callee);
+      fputs ("\" shape : ellipse }\n", f);
+    }
+
+  fputs ("edge: { sourcename: \"", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_UNIQUE_NAME);
+  fputs ("\" targetname: \"", f);
+  if (callee)
+    print_decl_identifier (f, callee, PRINT_DECL_UNIQUE_NAME);
+  else
+    fputs (INDIRECT_CALL_NAME, f);
+  if (LOCATION_LOCUS (location) != UNKNOWN_LOCATION)
+    {
+      expanded_location loc;
+      fputs ("\" label: \"", f);
+      loc = expand_location (location);
+      fprintf (f, "%s:%d:%d", loc.file, loc.line, loc.column);
+    }
+  fputs ("\" }\n", f);
+}
+
+/* Dump final cgraph node in VCG format.  */
+
+static void
+dump_final_node_vcg (FILE *f)
+{
+  dump_final_node_vcg_start (f, current_function_decl);
+
+  if (flag_stack_usage_info
+      || (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE))
+    output_stack_usage_1 (f);
+
+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+    {
+      fprintf (f, "\\n%u dynamic objects", vec_safe_length (cfun->su->dallocs));
+
+      unsigned i;
+      callinfo_dalloc *cda;
+      FOR_EACH_VEC_SAFE_ELT (cfun->su->dallocs, i, cda)
+	{
+	  expanded_location loc = expand_location (cda->location);
+	  fprintf (f, "\\n %s", cda->name);
+	  fprintf (f, " %s:%d:%d", loc.file, loc.line, loc.column);
+	}
+
+      vec_free (cfun->su->dallocs);
+      cfun->su->dallocs = NULL;
+    }
+
+  fputs ("\" }\n", f);
+
+  unsigned i;
+  callinfo_callee *c;
+  FOR_EACH_VEC_SAFE_ELT (cfun->su->callees, i, c)
+    dump_final_callee_vcg (f, c->location, c->decl);
+  vec_free (cfun->su->callees);
+  cfun->su->callees = NULL;
+
+  cgraph_node *cnode = cgraph_node::get (current_function_decl);
+  for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
+    if (CALLEE_FROM_CGRAPH_P (e->callee->decl))
+      dump_final_callee_vcg (f, gimple_location (e->call_stmt),
+			     e->callee->decl);
+  for (cgraph_edge *e = cnode->indirect_calls; e; e = e->next_callee)
+    dump_final_callee_vcg (f, gimple_location (e->call_stmt), NULL);
+}
+
+/* Output stack usage and callgraph info, as requested.  */
+void
+output_stack_usage (void)
+{
+  if (flag_callgraph_info)
+    dump_final_node_vcg (callgraph_info_file);
+  else
+    output_stack_usage_1 (NULL);
+}
+
 /* Open an auxiliary output file.  */
 static FILE *
 open_auxiliary_file (const char *ext)
@@ -1900,6 +1988,17 @@ lang_dependent_init (const char *name)
       /* If stack usage information is desired, open the output file.  */
       if (flag_stack_usage && !flag_generate_lto)
 	stack_usage_file = open_auxiliary_file ("su");
+
+      /* If call graph information is desired, open the output file.  */
+      if (flag_callgraph_info && !flag_generate_lto)
+	{
+	  callgraph_info_file = open_auxiliary_file ("ci");
+	  /* Write the file header.  */
+	  fprintf (callgraph_info_file,
+		   "graph: { title: \"%s\"\n", main_input_filename);
+	  bitmap_obstack_initialize (NULL);
+	  callgraph_info_external_printed = BITMAP_ALLOC (NULL);
+	}
     }
 
   /* This creates various _DECL nodes, so needs to be called after the
@@ -2053,6 +2152,15 @@ finalize (bool no_backend)
       stack_usage_file = NULL;
     }
 
+  if (callgraph_info_file)
+    {
+      fputs ("}\n", callgraph_info_file);
+      fclose (callgraph_info_file);
+      callgraph_info_file = NULL;
+      BITMAP_FREE (callgraph_info_external_printed);
+      bitmap_obstack_release (NULL);
+    }
+
   if (seen_error ())
     coverage_remove_note_file ();
 


improve and document -flto -fcallgraph-info

From: Alexandre Oliva <oliva@adacore.com>

for  gcc/ChangeLog

	* toplev.c (open_auxiliary_file): Use dump_base_name for LTO
	partitions.
	* doc/invoke.texi (-fcallgraph-info): Adjust.
---
 gcc/doc/invoke.texi |    4 ++--
 gcc/toplev.c        |    8 ++++++--
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 179452c..b7011b7 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -14580,8 +14580,8 @@ objects.
 
 When compiling with @option{-flto}, no callgraph information is output
 along with the object file.  At LTO link time, @option{-fcallgraph-info}
-may generate multiple callgraph information files next to intermediate
-LTO output files.
+may generate multiple callgraph information files next to the specified
+output file.
 
 @item -d@var{letters}
 @itemx -fdump-rtl-@var{pass}
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 18fea1c..8aaf216 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1114,14 +1114,18 @@ output_stack_usage (void)
     output_stack_usage_1 (NULL);
 }
 
-/* Open an auxiliary output file.  */
+/* Open an auxiliary or dump output file.  */
 static FILE *
 open_auxiliary_file (const char *ext)
 {
   char *filename;
   FILE *file;
+  const char *base_name = aux_base_name;
 
-  filename = concat (aux_base_name, ".", ext, NULL);
+  if (in_lto_p)
+    base_name = dump_base_name;
+
+  filename = concat (base_name, ".", ext, NULL);
   file = fopen (filename, "w");
   if (!file)
     fatal_error (input_location, "cannot open %s for writing: %m", filename);
Alexandre Oliva Nov. 6, 2019, 3:37 p.m. UTC | #14
On Nov  4, 2019, Richard Biener <rguenther@suse.de> wrote:

> I wonder why we shouldn't simply adjust aux_base_name to something
> else for -flto [in the driver].

About that, having tried to make sense of the current uses of
aux_base_name and of lto-wrapper, three main possibilities occur to me:

a) adjust the driver code to accept -auxbase, and have lto-wrapper
explicitly pass -aux-base ${output_dir-.}/$(lbasename ${output_name}) or
somesuch for each -fltrans command;

b) introduce -auxdir and get lto-wrapper to pass -auxdir ${output_dir-.}
for each -fltrans (and offload) command; or

c) get -fltrans to implicitly adjust aux_base_name with the directory
passed to -dumpdir, if any, or . otherwise

Any preferences?
Thomas Schwinge Nov. 6, 2019, 9:27 p.m. UTC | #15
Hi Alexandre!

On 2019-10-26T01:35:43-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> This was first submitted many years ago
> https://gcc.gnu.org/ml/gcc-patches/2010-10/msg02468.html
>
> The command line option -fcallgraph-info is added and makes the
> compiler generate another output file (xxx.ci) for each compilation
> unit

Yay, for such analysis tools!  :-)


But I'm curious:

> which is a valid VCG file (you can launch your favorite VCG
> viewer on it unmodified)

What should be my "favorite VCG viewer"?

Google lead me to
<http://www.rw.cdl.uni-saarland.de/users/sander/html/gsvcg1.html>, where
I downloaded 'vcg.20050204.tgz' (which I understand is the 1995 sources
with just some licensing changed?), which I managed to build, but which
fails to run on a simple file:

    Wait....................e*** stack smashing detected ***: <unknown> terminated
    Aborted (core dumped)

I found the patch from
<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=152128#64> to cure
that one problem.

(It seems that vcg is not packaged in Debian/Ubuntu anymore, nowadays?)

> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi

> +@item -fcallgraph-info
> +@itemx -fcallgraph-info=@var{MARKERS}
> +@opindex fcallgraph-info
> +Makes the compiler output callgraph information for the program, on a
> +per-file basis.  The information is generated in the common VCG format.

Eh, "common VCG format" -- maybe common in the mid-90s?  ;-)

> +It can be decorated with additional, per-node and/or per-edge information,
> +if a list of comma-separated markers is additionally specified.  When the
> +@code{su} marker is specified, the callgraph is decorated with stack usage
> +information; it is equivalent to @option{-fstack-usage}.  When the @code{da}
> +marker is specified, the callgraph is decorated with information about
> +dynamically allocated objects.

I tried that, but 'xvcg' didn't render anything useful for a
'-fcallgraph-info=su,da' dump, hmm.


Also, I found that many years ago, in 2012, Steven Bosscher did "Rework
RTL CFG graph dumping to dump DOT format" (that's Graphviz), and then did
"remove vcg CFG dumper".

Note that I'm not actively objecting VCG if there's a good reason to use
unmaintained mid-90s software, containing obfuscated layout/rendering
source code (as far as I understand), not really in spirit of its GPL
license?  (But I'm not a lawyer, of course.)

So I guess I'm just curious why it's now coming back.


Grüße
 Thomas
Richard Biener Nov. 7, 2019, 7:49 a.m. UTC | #16
On Wed, 6 Nov 2019, Alexandre Oliva wrote:

> On Nov  4, 2019, Richard Biener <rguenther@suse.de> wrote:
> 
> > I wonder why we shouldn't simply adjust aux_base_name to something
> > else for -flto [in the driver].
> 
> About that, having tried to make sense of the current uses of
> aux_base_name and of lto-wrapper, three main possibilities occur to me:
> 
> a) adjust the driver code to accept -auxbase, and have lto-wrapper
> explicitly pass -aux-base ${output_dir-.}/$(lbasename ${output_name}) or
> somesuch for each -fltrans command;
> 
> b) introduce -auxdir and get lto-wrapper to pass -auxdir ${output_dir-.}
> for each -fltrans (and offload) command; or
> 
> c) get -fltrans to implicitly adjust aux_base_name with the directory
> passed to -dumpdir, if any, or . otherwise
>
> Any preferences?

A simple test shows we currently only pass -auxbase-strip /tmp/cc...o
to the LTRANS lto1 invocation plus -dumpbase cc...o
Even with -save-temps this doesn't "improve" unless you have an
explicit output via -o

So isn't one of the main issues that the naming of the auxiliar
files is based on some "temporary" file?  IMHO those should always
behave like if we passed -save-temps but I'm not sure how to achieve
that.  For example -dumpdir and -dumpbase seem to work like this
already so there must be code somewhere doing this and adjusting
-auxbase[-strip] to work the same way would make sense to me.

Doesn't really solve the case for "no output name given" (aka a.out
default) though - I suppose for dumping and auxiliar file naming
purpose we should simply assume -o a.out there?

Thanks,
Richard.
Alexandre Oliva Nov. 7, 2019, 10:50 a.m. UTC | #17
On Nov  7, 2019, Richard Biener <rguenther@suse.de> wrote:

> A simple test shows we currently only pass -auxbase-strip /tmp/cc...o
> to the LTRANS lto1 invocation plus -dumpbase cc...o

This -auxbase-strip argument is introduced by the gcc driver that runs
lto1, based on the -o (tmp ltrans .o) argument, but this driver has no
clue as to the executable name or location, and there's nothing
whatsoever in the driver interface that enables aux_base_name to be
located separately from the output name.  Thus the possibilities I
brought up of introducing means for it to be told so, explicitly or by
convention.
Alexandre Oliva Nov. 7, 2019, 11:22 a.m. UTC | #18
On Nov  6, 2019, Thomas Schwinge <thomas@codesourcery.com> wrote:

>> which is a valid VCG file (you can launch your favorite VCG
>> viewer on it unmodified)

> What should be my "favorite VCG viewer"?

-ENOCLUE, I'm afraid.  I honestly don't even know which one Eric used
back when he first attempted to contribute this feature, almost 10 years
ago.

What I do know is that visualization is not the primary goal.  There are
indeed newer and more elaborate and modern graph file formats for that.
The primary intended consumer of this output is gnatstack, that's long
used only this simple format.  It's hard to justify rewriting it and
creating an incompatibility when the simple format does the job well.

Plus, it's simple enough and regular enough that it should be quite easy
to parse it with a few lines of awk and post-process the .ci file into
any other graph format of interest, when visualization of the graph is
the aim.  If you show me examples of graph formats that you'd like, that
can represent all the data encoded in .ci files, it wouldn't take much
effort to persuade me to write the few lines of awk, or perhaps even
sed, to convert .ci files output by GCC to the other format ;-)


> I tried that, but 'xvcg' didn't render anything useful for a
> '-fcallgraph-info=su,da' dump, hmm.

Did xvcg fail to display the node information added by su and da?  As
in, do you see the difference the options make to the graph text file,
but not in the visualization?  Or is it something else?


> Also, I found that many years ago, in 2012, Steven Bosscher did "Rework
> RTL CFG graph dumping to dump DOT format" (that's Graphviz), and then did
> "remove vcg CFG dumper".

gnatstack and -fcallgraph-info have been available since long before
that move indeed.

> Note that I'm not actively objecting VCG

Good, thanks for pointing that out :-)

> unmaintained mid-90s software, containing obfuscated layout/rendering
> source code

Since gnatstack is the primary consumer, I think that objection doesn't
apply.


As a Free Software activist, however, I am a little concerned about the
claim about obfuscated source code.  I haven't been able to find any
substantiation of that in your message.  I think that would be OT for
this list, so would you please send me what you got about it at
oliva@fsf.org?  TIA,
Richard Biener Nov. 7, 2019, 11:48 a.m. UTC | #19
On Thu, 7 Nov 2019, Alexandre Oliva wrote:

> On Nov  7, 2019, Richard Biener <rguenther@suse.de> wrote:
> 
> > A simple test shows we currently only pass -auxbase-strip /tmp/cc...o
> > to the LTRANS lto1 invocation plus -dumpbase cc...o
> 
> This -auxbase-strip argument is introduced by the gcc driver that runs
> lto1, based on the -o (tmp ltrans .o) argument, but this driver has no
> clue as to the executable name or location, and there's nothing
> whatsoever in the driver interface that enables aux_base_name to be
> located separately from the output name.  Thus the possibilities I
> brought up of introducing means for it to be told so, explicitly or by
> convention.

So how's -dumpbase handled?  I'd prefer the same approach for -auxbase

Richard.
Alexandre Oliva Nov. 7, 2019, 12:30 p.m. UTC | #20
On Nov  7, 2019, Richard Biener <rguenther@suse.de> wrote:

> So how's -dumpbase handled?

It's part of the gcc driver interface, and lto-wrapper passes it to gcc
for -fltrans compilations.  -auxbase isn't, so one of the alternatives I
suggested involved our taking auxbase from dumpdir & dumpbase for
-fltrans compilations.  The other alternatives amounted to exposing
auxdir or auxbase in the driver interface, so that lto-wrapper could
specify them explicitly.
Richard Biener Nov. 7, 2019, 2:02 p.m. UTC | #21
On Thu, 7 Nov 2019, Alexandre Oliva wrote:

> On Nov  7, 2019, Richard Biener <rguenther@suse.de> wrote:
> 
> > So how's -dumpbase handled?
> 
> It's part of the gcc driver interface, and lto-wrapper passes it to gcc
> for -fltrans compilations.  -auxbase isn't, so one of the alternatives I
> suggested involved our taking auxbase from dumpdir & dumpbase for
> -fltrans compilations.  The other alternatives amounted to exposing
> auxdir or auxbase in the driver interface, so that lto-wrapper could
> specify them explicitly.

Both variants sound reasonable to me (also raises the question why
we have both -dumpbase and -auxbase ...)

Richard.
Alexandre Oliva Nov. 7, 2019, 10:39 p.m. UTC | #22
On Nov  7, 2019, Richard Biener <rguenther@suse.de> wrote:

> (also raises the question why we have both -dumpbase and -auxbase ...)

https://gcc.gnu.org/ml/gcc-patches/2002-08/msg00294.html

This was before -dumpdir, however.

Here's the current logic for aux_base_name:

-c or -S with -o [odir/]obase.oext: [odir/]obase
otherwise, given input [idir/]ibase.iext: ibase

Whereas the current logic for dump_base_name, once aux_base_name has
been determined as [auxdir/]auxbase, is:

given -dumpbase ddir/dbase: ddir/dbase
otherwise, given -dumpdir ddir and -dumpbase dbase: ddir/dbase
otherwise, given -dumpbase dbase: [auxdir/]dbase
otherwise, given -dumpdir ddir: ddir/ibase.iext
otherwise: [auxdir/]ibase.iext

Relevant cases to consider: (aux, dump) for each compilation with
CC='gcc -fstack-usage -fdump-tree-original'

compiling without -o: (ibase, ibase.iext)
ex $CC -c srcdir/foo.c srcdir/x/bar.c
-> foo.o foo.su foo.c.#t.original
 + bar.o bar.su bar.c.#t.original

compiling with -o: ([odir/]obase, [odir/]ibase.iext)
ex $CC -c srcdir/foo.c -o objdir/foobaz.o -Dfoobaz
-> objdir/foobaz.o objdir/foobaz.su objdir/foo.c.#t.original

compiling multiple sources with -dumpbase: (ibase, [ddir/]dbase)
ex $CC -dumpbase outdir/runme.dump -c srcdir/foo.c srcdir/x/bar.c
-> foo.o foo.su outdir/runme.dump.#t.original
 + bar.o bar.su outdir/runme.dump.#t.original (dupe)

compiling and linking with -o: (ibase, ibase.iext)
ex $CC -o outdir/runme srcdir/foo.c srcdir/x/bar.c
-> /tmp/temp().o foo.su foo.c.#t.original
 + /tmp/temp().o bar.su bar.c.#t.original
 + outdir/runme

lto-recompiling and linking with -o: (/tmp/obase.temp().ltrans#.ltrans, odir/obase.ltrans#)
ex $CC -o outdir/runme ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
-> /tmp/runme.temp().ltrans0.ltrans.o /tmp/runme.temp().ltrans0.ltrans.su
 + outdir/runme.ltrans0.#r.expand
 + outdir/runme

lto-recompiling and linking without -o: (/tmp/temp().ltrans#.ltrans, /tmp/temp().ltrans#.o)
ex $CC ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
-> /tmp/temp().ltrans0.ltrans.o /tmp/temp().ltrans0.ltrans.su
 + /tmp/temp().ltrans0.#r.expand
 + a.out


If we were to unify auxbase and dumpbase, I'd take the opportunity to
fix the -o objdir/foobaz.o compilation to output dumps named after
objdir/foobaz or objdir/foobaz-foo.c rather than ./foo.c; for
outdir/runme.dump to be used as a prefix for aux and dump names, so that
we wouldn't create and then overwrite outdir/runme.dump, and so that
other compilations of foo.c and bar.c wouldn't overwrite the .su files,
but rather create outdir/runme.dump-{foo,bar}.* dumps and aux files; and
likewise use outdir/runme.ltrans0 or a.out.ltrans0 for the .su and
.expand files.


The logic I suggest is involves combining some of the -auxbase and some
of the -dumpbase logic, namely:

In the driver:

compiling a single source idir/ibase.iext:

  -o odir/obase.oext specified: default -dumpdir odir -dumpbase obase.iext
  -o obase.oext specified: default -dumpbase obase.iext
  -o ibase.oext implied: default -dumpbase ibase.iext

compiling multiple sources named as ibase.iext for linking:

  -dumpbase [ddir/]dbase specified: make it -dumpbase [ddir/]dbase-ibase.iext
  -o odir/output specified: default -dumpdir odir -dumpbase output-ibase.iext
  -o output specified: default -dumpbase output-ibase.iext
  -o a.out implied: default -dumpbase a.out-ibase.iext

LTO recompiling:

  same as above, with each ibase.iext set to ltrans#


In the compiler, set dump_base_name to:

Given -dumpbase ddir/dbase: ddir/dbase
otherwise, given -dumpdir ddir and -dumpbase dbase: ddir/dbase
otherwise, given -dumpbase dbase: dbase

and copy aux_base_name from dump_base_name, but if it ends in .iext,
drop the extension.

The resulting behavior (aux_base_name, dump_base_name)

compiling without -o: (ibase, ibase.iext)  unchanged
ex $CC -c srcdir/foo.c srcdir/x/bar.c
-> foo.o foo.su foo.c.#t.original
 + bar.o bar.su bar.c.#t.original

compiling with -o: ([odir/]obase, [odir/]obase.iext)
ex $CC -c srcdir/foo.c -o objdir/foobaz.o -Dfoobaz
-> objdir/foobaz.o objdir/foobaz.su objdir/foobaz.c.#t.original

compiling multiple sources with -dumpbase: ([ddir]/dbase, [ddir/]dbase)
ex $CC -dumpbase outdir/runme.dump -c srcdir/foo.c srcdir/x/bar.c
-> foo.o outdir/runme.dump-foo.su outdir/runme.dump-foo.c.#t.original
 + bar.o outdir/runme.dump-bar.su outdir/runme.dump-bar.c.#t.original

compiling and linking with -o: (outdir/runme-ibase, outdir/runme-ibase.iext)
ex $CC -o outdir/runme srcdir/foo.c srcdir/x/bar.c
-> /tmp/temp().o outdir/runme-foo.su outdir/runme-foo.c.#t.original
 + /tmp/temp().o outdir/runme-bar.su outdir/runme-bar.c.#t.original
 + outdir/runme

lto-recompiling and linking with -o: (outdir/runme.ltrans#, outdir/runme.ltrans#)
ex $CC -o outdir/runme ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
-> /tmp/runme.temp().ltrans0.ltrans.o outdir/runme.ltrans0.su
 + outdir/runme.ltrans0.#r.expand
 + outdir/runme

lto-recompiling and linking without -o: (a.out.ltrans#, a.out.ltrans#)
ex $CC ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
-> /tmp/temp().ltrans0.ltrans.o a.out.ltrans0.su 
 + a.out.ltrans0.#r.expand
 + a.out


I'm a little hesitant, this amounts to quite significant behavior
changes.  Do these seem acceptable and desirable nevertheless?
Richard Biener Nov. 8, 2019, 8:28 a.m. UTC | #23
On Thu, 7 Nov 2019, Alexandre Oliva wrote:

> On Nov  7, 2019, Richard Biener <rguenther@suse.de> wrote:
> 
> > (also raises the question why we have both -dumpbase and -auxbase ...)
> 
> https://gcc.gnu.org/ml/gcc-patches/2002-08/msg00294.html
> 
> This was before -dumpdir, however.
> 
> Here's the current logic for aux_base_name:
> 
> -c or -S with -o [odir/]obase.oext: [odir/]obase
> otherwise, given input [idir/]ibase.iext: ibase
> 
> Whereas the current logic for dump_base_name, once aux_base_name has
> been determined as [auxdir/]auxbase, is:
> 
> given -dumpbase ddir/dbase: ddir/dbase
> otherwise, given -dumpdir ddir and -dumpbase dbase: ddir/dbase
> otherwise, given -dumpbase dbase: [auxdir/]dbase
> otherwise, given -dumpdir ddir: ddir/ibase.iext
> otherwise: [auxdir/]ibase.iext
> 
> Relevant cases to consider: (aux, dump) for each compilation with
> CC='gcc -fstack-usage -fdump-tree-original'
> 
> compiling without -o: (ibase, ibase.iext)
> ex $CC -c srcdir/foo.c srcdir/x/bar.c
> -> foo.o foo.su foo.c.#t.original
>  + bar.o bar.su bar.c.#t.original
> 
> compiling with -o: ([odir/]obase, [odir/]ibase.iext)
> ex $CC -c srcdir/foo.c -o objdir/foobaz.o -Dfoobaz
> -> objdir/foobaz.o objdir/foobaz.su objdir/foo.c.#t.original
> 
> compiling multiple sources with -dumpbase: (ibase, [ddir/]dbase)
> ex $CC -dumpbase outdir/runme.dump -c srcdir/foo.c srcdir/x/bar.c
> -> foo.o foo.su outdir/runme.dump.#t.original
>  + bar.o bar.su outdir/runme.dump.#t.original (dupe)
> 
> compiling and linking with -o: (ibase, ibase.iext)
> ex $CC -o outdir/runme srcdir/foo.c srcdir/x/bar.c
> -> /tmp/temp().o foo.su foo.c.#t.original
>  + /tmp/temp().o bar.su bar.c.#t.original
>  + outdir/runme
> 
> lto-recompiling and linking with -o: (/tmp/obase.temp().ltrans#.ltrans, odir/obase.ltrans#)
> ex $CC -o outdir/runme ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
> -> /tmp/runme.temp().ltrans0.ltrans.o /tmp/runme.temp().ltrans0.ltrans.su
>  + outdir/runme.ltrans0.#r.expand
>  + outdir/runme
> 
> lto-recompiling and linking without -o: (/tmp/temp().ltrans#.ltrans, /tmp/temp().ltrans#.o)
> ex $CC ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
> -> /tmp/temp().ltrans0.ltrans.o /tmp/temp().ltrans0.ltrans.su
>  + /tmp/temp().ltrans0.#r.expand
>  + a.out
> 
> 
> If we were to unify auxbase and dumpbase, I'd take the opportunity to
> fix the -o objdir/foobaz.o compilation to output dumps named after
> objdir/foobaz or objdir/foobaz-foo.c rather than ./foo.c; for
> outdir/runme.dump to be used as a prefix for aux and dump names, so that
> we wouldn't create and then overwrite outdir/runme.dump, and so that
> other compilations of foo.c and bar.c wouldn't overwrite the .su files,
> but rather create outdir/runme.dump-{foo,bar}.* dumps and aux files; and
> likewise use outdir/runme.ltrans0 or a.out.ltrans0 for the .su and
> .expand files.
> 
> 
> The logic I suggest is involves combining some of the -auxbase and some
> of the -dumpbase logic, namely:
> 
> In the driver:
> 
> compiling a single source idir/ibase.iext:
> 
>   -o odir/obase.oext specified: default -dumpdir odir -dumpbase obase.iext
>   -o obase.oext specified: default -dumpbase obase.iext
>   -o ibase.oext implied: default -dumpbase ibase.iext
> 
> compiling multiple sources named as ibase.iext for linking:
> 
>   -dumpbase [ddir/]dbase specified: make it -dumpbase [ddir/]dbase-ibase.iext
>   -o odir/output specified: default -dumpdir odir -dumpbase output-ibase.iext
>   -o output specified: default -dumpbase output-ibase.iext
>   -o a.out implied: default -dumpbase a.out-ibase.iext
> 
> LTO recompiling:
> 
>   same as above, with each ibase.iext set to ltrans#
> 
> 
> In the compiler, set dump_base_name to:
> 
> Given -dumpbase ddir/dbase: ddir/dbase
> otherwise, given -dumpdir ddir and -dumpbase dbase: ddir/dbase
> otherwise, given -dumpbase dbase: dbase
> 
> and copy aux_base_name from dump_base_name, but if it ends in .iext,
> drop the extension.
> 
> The resulting behavior (aux_base_name, dump_base_name)
> 
> compiling without -o: (ibase, ibase.iext)  unchanged
> ex $CC -c srcdir/foo.c srcdir/x/bar.c
> -> foo.o foo.su foo.c.#t.original
>  + bar.o bar.su bar.c.#t.original
> 
> compiling with -o: ([odir/]obase, [odir/]obase.iext)
> ex $CC -c srcdir/foo.c -o objdir/foobaz.o -Dfoobaz
> -> objdir/foobaz.o objdir/foobaz.su objdir/foobaz.c.#t.original
> 
> compiling multiple sources with -dumpbase: ([ddir]/dbase, [ddir/]dbase)
> ex $CC -dumpbase outdir/runme.dump -c srcdir/foo.c srcdir/x/bar.c
> -> foo.o outdir/runme.dump-foo.su outdir/runme.dump-foo.c.#t.original
>  + bar.o outdir/runme.dump-bar.su outdir/runme.dump-bar.c.#t.original
> 
> compiling and linking with -o: (outdir/runme-ibase, outdir/runme-ibase.iext)
> ex $CC -o outdir/runme srcdir/foo.c srcdir/x/bar.c
> -> /tmp/temp().o outdir/runme-foo.su outdir/runme-foo.c.#t.original
>  + /tmp/temp().o outdir/runme-bar.su outdir/runme-bar.c.#t.original
>  + outdir/runme
> 
> lto-recompiling and linking with -o: (outdir/runme.ltrans#, outdir/runme.ltrans#)
> ex $CC -o outdir/runme ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
> -> /tmp/runme.temp().ltrans0.ltrans.o outdir/runme.ltrans0.su
>  + outdir/runme.ltrans0.#r.expand
>  + outdir/runme
> 
> lto-recompiling and linking without -o: (a.out.ltrans#, a.out.ltrans#)
> ex $CC ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
> -> /tmp/temp().ltrans0.ltrans.o a.out.ltrans0.su 
>  + a.out.ltrans0.#r.expand
>  + a.out

Wow, thanks for the elaborate write-up!  I wonder if we can
cut&paste this into documentation somewhere appropriate, maybe
there's already a section for "auxiliary compiler outputs".

> I'm a little hesitant, this amounts to quite significant behavior
> changes.  Do these seem acceptable and desirable nevertheless?

I think the current state is somewhat of a mess and in some
cases confusing and your suggestion sounds like an overall
improvement to me (you didn't actually suggest to remove
either of the -dump{base,dir} -auxbase{-strip} options?)

Of course, others please feel free to comment (but let's not start
bikeshedding too much...).

Thanks a lot!
Richard.
Eric Gallager Nov. 8, 2019, 11:10 p.m. UTC | #24
On 11/8/19, Richard Biener <rguenther@suse.de> wrote:
> On Thu, 7 Nov 2019, Alexandre Oliva wrote:
>
>> On Nov  7, 2019, Richard Biener <rguenther@suse.de> wrote:
>>
>> > (also raises the question why we have both -dumpbase and -auxbase ...)
>>
>> https://gcc.gnu.org/ml/gcc-patches/2002-08/msg00294.html
>>
>> This was before -dumpdir, however.
>>
>> Here's the current logic for aux_base_name:
>>
>> -c or -S with -o [odir/]obase.oext: [odir/]obase
>> otherwise, given input [idir/]ibase.iext: ibase
>>
>> Whereas the current logic for dump_base_name, once aux_base_name has
>> been determined as [auxdir/]auxbase, is:
>>
>> given -dumpbase ddir/dbase: ddir/dbase
>> otherwise, given -dumpdir ddir and -dumpbase dbase: ddir/dbase
>> otherwise, given -dumpbase dbase: [auxdir/]dbase
>> otherwise, given -dumpdir ddir: ddir/ibase.iext
>> otherwise: [auxdir/]ibase.iext
>>
>> Relevant cases to consider: (aux, dump) for each compilation with
>> CC='gcc -fstack-usage -fdump-tree-original'
>>
>> compiling without -o: (ibase, ibase.iext)
>> ex $CC -c srcdir/foo.c srcdir/x/bar.c
>> -> foo.o foo.su foo.c.#t.original
>>  + bar.o bar.su bar.c.#t.original
>>
>> compiling with -o: ([odir/]obase, [odir/]ibase.iext)
>> ex $CC -c srcdir/foo.c -o objdir/foobaz.o -Dfoobaz
>> -> objdir/foobaz.o objdir/foobaz.su objdir/foo.c.#t.original
>>
>> compiling multiple sources with -dumpbase: (ibase, [ddir/]dbase)
>> ex $CC -dumpbase outdir/runme.dump -c srcdir/foo.c srcdir/x/bar.c
>> -> foo.o foo.su outdir/runme.dump.#t.original
>>  + bar.o bar.su outdir/runme.dump.#t.original (dupe)
>>
>> compiling and linking with -o: (ibase, ibase.iext)
>> ex $CC -o outdir/runme srcdir/foo.c srcdir/x/bar.c
>> -> /tmp/temp().o foo.su foo.c.#t.original
>>  + /tmp/temp().o bar.su bar.c.#t.original
>>  + outdir/runme
>>
>> lto-recompiling and linking with -o: (/tmp/obase.temp().ltrans#.ltrans,
>> odir/obase.ltrans#)
>> ex $CC -o outdir/runme ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
>> -> /tmp/runme.temp().ltrans0.ltrans.o /tmp/runme.temp().ltrans0.ltrans.su
>>  + outdir/runme.ltrans0.#r.expand
>>  + outdir/runme
>>
>> lto-recompiling and linking without -o: (/tmp/temp().ltrans#.ltrans,
>> /tmp/temp().ltrans#.o)
>> ex $CC ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
>> -> /tmp/temp().ltrans0.ltrans.o /tmp/temp().ltrans0.ltrans.su
>>  + /tmp/temp().ltrans0.#r.expand
>>  + a.out
>>
>>
>> If we were to unify auxbase and dumpbase, I'd take the opportunity to
>> fix the -o objdir/foobaz.o compilation to output dumps named after
>> objdir/foobaz or objdir/foobaz-foo.c rather than ./foo.c; for
>> outdir/runme.dump to be used as a prefix for aux and dump names, so that
>> we wouldn't create and then overwrite outdir/runme.dump, and so that
>> other compilations of foo.c and bar.c wouldn't overwrite the .su files,
>> but rather create outdir/runme.dump-{foo,bar}.* dumps and aux files; and
>> likewise use outdir/runme.ltrans0 or a.out.ltrans0 for the .su and
>> .expand files.
>>
>>
>> The logic I suggest is involves combining some of the -auxbase and some
>> of the -dumpbase logic, namely:
>>
>> In the driver:
>>
>> compiling a single source idir/ibase.iext:
>>
>>   -o odir/obase.oext specified: default -dumpdir odir -dumpbase
>> obase.iext
>>   -o obase.oext specified: default -dumpbase obase.iext
>>   -o ibase.oext implied: default -dumpbase ibase.iext
>>
>> compiling multiple sources named as ibase.iext for linking:
>>
>>   -dumpbase [ddir/]dbase specified: make it -dumpbase
>> [ddir/]dbase-ibase.iext
>>   -o odir/output specified: default -dumpdir odir -dumpbase
>> output-ibase.iext
>>   -o output specified: default -dumpbase output-ibase.iext
>>   -o a.out implied: default -dumpbase a.out-ibase.iext
>>
>> LTO recompiling:
>>
>>   same as above, with each ibase.iext set to ltrans#
>>
>>
>> In the compiler, set dump_base_name to:
>>
>> Given -dumpbase ddir/dbase: ddir/dbase
>> otherwise, given -dumpdir ddir and -dumpbase dbase: ddir/dbase
>> otherwise, given -dumpbase dbase: dbase
>>
>> and copy aux_base_name from dump_base_name, but if it ends in .iext,
>> drop the extension.
>>
>> The resulting behavior (aux_base_name, dump_base_name)
>>
>> compiling without -o: (ibase, ibase.iext)  unchanged
>> ex $CC -c srcdir/foo.c srcdir/x/bar.c
>> -> foo.o foo.su foo.c.#t.original
>>  + bar.o bar.su bar.c.#t.original
>>
>> compiling with -o: ([odir/]obase, [odir/]obase.iext)
>> ex $CC -c srcdir/foo.c -o objdir/foobaz.o -Dfoobaz
>> -> objdir/foobaz.o objdir/foobaz.su objdir/foobaz.c.#t.original
>>
>> compiling multiple sources with -dumpbase: ([ddir]/dbase, [ddir/]dbase)
>> ex $CC -dumpbase outdir/runme.dump -c srcdir/foo.c srcdir/x/bar.c
>> -> foo.o outdir/runme.dump-foo.su outdir/runme.dump-foo.c.#t.original
>>  + bar.o outdir/runme.dump-bar.su outdir/runme.dump-bar.c.#t.original
>>
>> compiling and linking with -o: (outdir/runme-ibase,
>> outdir/runme-ibase.iext)
>> ex $CC -o outdir/runme srcdir/foo.c srcdir/x/bar.c
>> -> /tmp/temp().o outdir/runme-foo.su outdir/runme-foo.c.#t.original
>>  + /tmp/temp().o outdir/runme-bar.su outdir/runme-bar.c.#t.original
>>  + outdir/runme
>>
>> lto-recompiling and linking with -o: (outdir/runme.ltrans#,
>> outdir/runme.ltrans#)
>> ex $CC -o outdir/runme ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
>> -> /tmp/runme.temp().ltrans0.ltrans.o outdir/runme.ltrans0.su
>>  + outdir/runme.ltrans0.#r.expand
>>  + outdir/runme
>>
>> lto-recompiling and linking without -o: (a.out.ltrans#, a.out.ltrans#)
>> ex $CC ltobjdir/foo.o ltobjdir/bar.o -fdump-rtl-expand
>> -> /tmp/temp().ltrans0.ltrans.o a.out.ltrans0.su
>>  + a.out.ltrans0.#r.expand
>>  + a.out
>
> Wow, thanks for the elaborate write-up!  I wonder if we can
> cut&paste this into documentation somewhere appropriate, maybe
> there's already a section for "auxiliary compiler outputs".
>
>> I'm a little hesitant, this amounts to quite significant behavior
>> changes.  Do these seem acceptable and desirable nevertheless?
>
> I think the current state is somewhat of a mess and in some
> cases confusing and your suggestion sounds like an overall
> improvement to me (you didn't actually suggest to remove
> either of the -dump{base,dir} -auxbase{-strip} options?)

If you're touching the -auxbase option... is that related to the other
options starting with -aux at all? If so, bug 26613 might be related:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=26613

>
> Of course, others please feel free to comment (but let's not start
> bikeshedding too much...).
>
> Thanks a lot!
> Richard.
>
Alexandre Oliva Nov. 15, 2019, 12:56 a.m. UTC | #25
On Nov  8, 2019, Richard Biener <rguenther@suse.de> wrote:

> Wow, thanks for the elaborate write-up!  I wonder if we can
> cut&paste this into documentation somewhere appropriate, maybe
> there's already a section for "auxiliary compiler outputs".

Sure, that makes sense.

>> I'm a little hesitant, this amounts to quite significant behavior
>> changes.  Do these seem acceptable and desirable nevertheless?

> I think the current state is somewhat of a mess and in some
> cases confusing and your suggestion sounds like an overall
> improvement to me (you didn't actually suggest to remove
> either of the -dump{base,dir} -auxbase{-strip} options?)

I was trying to narrow down the desired behavior before trying to figure
out what options we could do away with.  If what I proposed was
acceptable, I thought we could drop the internal -auxbase* options
altogether.

However, I missed one relevant case in my analysis.  I suggested the
auxbase internally derived from dumpbase would drop the dumpbase
extension iff the extension matched that of the input file name.  That
doesn't work when compilation takes an intermediate file rather than the
input, e.g., in a -save-temps compilation, in which we'll have separate
preprocessing and the actual compiler will take the saved preprocessed
input, but should still output dumps to files named after the .c input.

ex $CC -S srcdir/foo.c -o objdir/foo.s -save-temps
-> objdir/foo.i objdir/foo.s objdir/foo.su objdir/foo.c.#t.original

The compilation line would only take the .c from -dumpbase, but since
its input is .i, it wouldn't match, and we wouldn't strip the .c from
aux outputs, and would instead generate:

-> objdir/foo.i objdir/foo.s objdir/foo.c.su objdir/foo.c.#t.original
                                       ^^

(which would likely be ok for .su, but quite unexpected for .dwo)

In order to address this, I propose we add an internal option (not for
the driver), -dumpbase-ext, that names the extension to be discarded
from dumpbase to form aux output names.

-dumpdir objdir -dumpbase foo.c -dumpbase-ext .c

The new -dumpbase-ext option specifies the extension to drop from the
specified -dumpbase to form aux output names, but dump output names keep
that intermediate extension.  When absent, we take it from the main
input file.

So aux outputs end up as objdir/foo.* whereas dump outputs end up as
objdump/foo.c.*, just as expected.

We could keep -dumpbase-ext an internal option, used only when doing
separate preprocessing, but it might make sense to expose it for use
along with -dumpbase for such tools as ccache and distcc, that call the
compiler driver with internal .i files, but would still prefer dumps and
aux files to be generated just as they would have for the .c files.

Specs would change from:

%{!dumpbase:-dumpbase %B}
%{c|S:%{o*:-auxbase-strip %*}
      %{!o*:-auxbase %b}}}
%{!c:%{!S:-auxbase %b}

to

%{!dumpdir:%{o*:-dumpdir %:dirname(%*)}}
%{c|S:%{!dumpbase:%{o*:-dumpbase %:replace-extension(%:basename(%*) %:extension(%i))}
                  %{!o*:-dumpbase %b}}}
%{!c:%{!S:-dumpbase %b}

and add to separate preprocessing commands:

%{!dumpbase-ext:-dumpbase-ext %:extension(%i)}


Then we'd set up aux_base_name from dump_base_name minus the extension,
given or taken from main_input_filename.
Alexandre Oliva Nov. 15, 2019, 1:01 a.m. UTC | #26
On Nov  8, 2019, Eric Gallager <egall@gwmail.gwu.edu> wrote:

> If you're touching the -auxbase option... is that related to the other
> options starting with -aux at all?

'fraid they're entirely unrelated.  We're talking about how the compiler
names aux and dump output files, which is not related with the contents
of an explicitly-named output file as the PR you mentioned.
Alexandre Oliva Nov. 15, 2019, 5:59 a.m. UTC | #27
On Nov 14, 2019, Alexandre Oliva <oliva@adacore.com> wrote:

> %{!c:%{!S:-dumpbase %b}

Uhh, I failed to adjust this one to add the executable output name to
dumpbase.

Anyway, getting the right semantics out of specs is providing to be a
lot trickier than I had anticipated.  I'm now pondering a single spec
function to deal with all of these dumpbase possibilities.

I'm also a little uncertain about behavior change WRT .dwo files.
Though their names are built out of the .o files in the objcopy
commands, they're built from aux_base_name in dwarf2out.  Currently,
since aux_base_name is derived from the output object file name, this
ensures they have the same name and directory, but once we enable
-dumpdir to be specified to override it, that may no longer be the
case.  Ugh...
Richard Biener Nov. 15, 2019, 7:50 a.m. UTC | #28
On Fri, 15 Nov 2019, Alexandre Oliva wrote:

> On Nov 14, 2019, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > %{!c:%{!S:-dumpbase %b}
> 
> Uhh, I failed to adjust this one to add the executable output name to
> dumpbase.
> 
> Anyway, getting the right semantics out of specs is providing to be a
> lot trickier than I had anticipated.  I'm now pondering a single spec
> function to deal with all of these dumpbase possibilities.
> 
> I'm also a little uncertain about behavior change WRT .dwo files.
> Though their names are built out of the .o files in the objcopy
> commands, they're built from aux_base_name in dwarf2out.  Currently,
> since aux_base_name is derived from the output object file name, this
> ensures they have the same name and directory, but once we enable
> -dumpdir to be specified to override it, that may no longer be the
> case.  Ugh...

Hmm, -dwo-base-name to the rescue? ;)  Well, I guess the debug info
has to somewhere encode the full/relative path to the .dwo files
so all that is needed is to keep that consistent?

Richard.
Alexandre Oliva Nov. 15, 2019, 10:22 p.m. UTC | #29
On Nov 15, 2019, Richard Biener <rguenther@suse.de> wrote:

> Hmm, -dwo-base-name to the rescue? ;)

I'd rather have less rather than more complexity.  I.e., make the
objcopy command match the dumpdir location, that defaults to the output
location.  The more such options we have, the harder it is to document,
understand, and implement correctly.

> so all that is needed is to keep that consistent?

*nod*
Alexandre Oliva Nov. 20, 2019, 4:34 a.m. UTC | #30
On Nov  6, 2019, Alexandre Oliva <oliva@adacore.com> wrote:

> 	(CALLEE_FROM_CGRAPH_P): New.
> 	(dump_final_callee_vcg, dump_final_node_vcg): New.

I goofed in the testing of this last-minute change.  It only works with
optimization disabled.  With any optimization enabled,
pass_remove_cgraph_callee_edges runs first thing in
pass_all_optimizations{,_g} without a subsequent
pass_rebuild_cgraph_edges.  This release takes place long before we'd
even know which calls make to expand, and thus to the callgraph-info
expected output.

It has just occurred to me that I could retain the logic but make it
conditional on !optimize, but that would be error prone (AFAICT there's
no reason why we don't release callees early without optimization) and
probably not worth it.


drop attempt to reuse cgraph callees for -fcallgraph-info

The information in cgraph callees is released long before we get to
the point in which -fcallgraph-info edges are dumped, or even
expanded.  It doesn't make sense to retain it longer: the edges
created for -fcallgraph-info are much smaller, and they don't even
coexist, so not even peak use grows.

Regstrapped on x86_64-linux-gnu.  Ok to install?


for  gcc/ChangeLog

	* function.h (CALLEE_FROM_CGRAPH_P): Remove.
	* function.c (record_final_call): Record even calls that might
	have been in the cgraph.
	* toplev.c (dump_final_node_vcg): Skip iteration over cgraph
	callees.
---
 gcc/function.c |    3 ---
 gcc/function.h |    5 +----
 gcc/toplev.c   |    8 --------
 3 files changed, 1 insertion(+), 15 deletions(-)

diff --git a/gcc/function.c b/gcc/function.c
index 1fe956b..2534c92 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -6406,9 +6406,6 @@ rest_of_handle_thread_prologue_and_epilogue (void)
 void
 record_final_call (tree callee, location_t location)
 {
-  if (!callee || CALLEE_FROM_CGRAPH_P (callee))
-    return;
-
   struct callinfo_callee datum = { location, callee };
   vec_safe_push (cfun->su->callees, datum);
 }
diff --git a/gcc/function.h b/gcc/function.h
index 14794c4..beb5c7d 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -192,15 +192,12 @@ public:
   poly_int64 length;
 };
 
-/* Describe emitted builtin calls for -fcallgraph-info.  Those that
-   are not builtin are taken from cgraph edges.  */
+/* Describe emitted calls for -fcallgraph-info.  */
 struct GTY(()) callinfo_callee
 {
   location_t location;
   tree decl;
 };
-#define CALLEE_FROM_CGRAPH_P(T)				\
-  (!fndecl_built_in_p (T) && !DECL_IS_BUILTIN (T))
 
 /* Describe dynamic allocation for -fcallgraph-info=da.  */
 struct GTY(()) callinfo_dalloc
diff --git a/gcc/toplev.c b/gcc/toplev.c
index d4583ba..3b9f9ee 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1093,14 +1093,6 @@ dump_final_node_vcg (FILE *f)
     dump_final_callee_vcg (f, c->location, c->decl);
   vec_free (cfun->su->callees);
   cfun->su->callees = NULL;
-
-  cgraph_node *cnode = cgraph_node::get (current_function_decl);
-  for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
-    if (CALLEE_FROM_CGRAPH_P (e->callee->decl))
-      dump_final_callee_vcg (f, gimple_location (e->call_stmt),
-			     e->callee->decl);
-  for (cgraph_edge *e = cnode->indirect_calls; e; e = e->next_callee)
-    dump_final_callee_vcg (f, gimple_location (e->call_stmt), NULL);
 }
 
 /* Output stack usage and callgraph info, as requested.  */
Richard Biener Nov. 20, 2019, 8:57 a.m. UTC | #31
On Wed, 20 Nov 2019, Alexandre Oliva wrote:

> On Nov  6, 2019, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > 	(CALLEE_FROM_CGRAPH_P): New.
> > 	(dump_final_callee_vcg, dump_final_node_vcg): New.
> 
> I goofed in the testing of this last-minute change.  It only works with
> optimization disabled.  With any optimization enabled,
> pass_remove_cgraph_callee_edges runs first thing in
> pass_all_optimizations{,_g} without a subsequent
> pass_rebuild_cgraph_edges.  This release takes place long before we'd
> even know which calls make to expand, and thus to the callgraph-info
> expected output.
> 
> It has just occurred to me that I could retain the logic but make it
> conditional on !optimize, but that would be error prone (AFAICT there's
> no reason why we don't release callees early without optimization) and
> probably not worth it.
> 
> 
> drop attempt to reuse cgraph callees for -fcallgraph-info
> 
> The information in cgraph callees is released long before we get to
> the point in which -fcallgraph-info edges are dumped, or even
> expanded.  It doesn't make sense to retain it longer: the edges
> created for -fcallgraph-info are much smaller, and they don't even
> coexist, so not even peak use grows.
> 
> Regstrapped on x86_64-linux-gnu.  Ok to install?

OK.

Richard.

> 
> for  gcc/ChangeLog
> 
> 	* function.h (CALLEE_FROM_CGRAPH_P): Remove.
> 	* function.c (record_final_call): Record even calls that might
> 	have been in the cgraph.
> 	* toplev.c (dump_final_node_vcg): Skip iteration over cgraph
> 	callees.
> ---
>  gcc/function.c |    3 ---
>  gcc/function.h |    5 +----
>  gcc/toplev.c   |    8 --------
>  3 files changed, 1 insertion(+), 15 deletions(-)
> 
> diff --git a/gcc/function.c b/gcc/function.c
> index 1fe956b..2534c92 100644
> --- a/gcc/function.c
> +++ b/gcc/function.c
> @@ -6406,9 +6406,6 @@ rest_of_handle_thread_prologue_and_epilogue (void)
>  void
>  record_final_call (tree callee, location_t location)
>  {
> -  if (!callee || CALLEE_FROM_CGRAPH_P (callee))
> -    return;
> -
>    struct callinfo_callee datum = { location, callee };
>    vec_safe_push (cfun->su->callees, datum);
>  }
> diff --git a/gcc/function.h b/gcc/function.h
> index 14794c4..beb5c7d 100644
> --- a/gcc/function.h
> +++ b/gcc/function.h
> @@ -192,15 +192,12 @@ public:
>    poly_int64 length;
>  };
>  
> -/* Describe emitted builtin calls for -fcallgraph-info.  Those that
> -   are not builtin are taken from cgraph edges.  */
> +/* Describe emitted calls for -fcallgraph-info.  */
>  struct GTY(()) callinfo_callee
>  {
>    location_t location;
>    tree decl;
>  };
> -#define CALLEE_FROM_CGRAPH_P(T)				\
> -  (!fndecl_built_in_p (T) && !DECL_IS_BUILTIN (T))
>  
>  /* Describe dynamic allocation for -fcallgraph-info=da.  */
>  struct GTY(()) callinfo_dalloc
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index d4583ba..3b9f9ee 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -1093,14 +1093,6 @@ dump_final_node_vcg (FILE *f)
>      dump_final_callee_vcg (f, c->location, c->decl);
>    vec_free (cfun->su->callees);
>    cfun->su->callees = NULL;
> -
> -  cgraph_node *cnode = cgraph_node::get (current_function_decl);
> -  for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
> -    if (CALLEE_FROM_CGRAPH_P (e->callee->decl))
> -      dump_final_callee_vcg (f, gimple_location (e->call_stmt),
> -			     e->callee->decl);
> -  for (cgraph_edge *e = cnode->indirect_calls; e; e = e->next_callee)
> -    dump_final_callee_vcg (f, gimple_location (e->call_stmt), NULL);
>  }
>  
>  /* Output stack usage and callgraph info, as requested.  */
> 
> 
> 
> 
>
Alexandre Oliva Dec. 3, 2019, 10:43 p.m. UTC | #32
On Nov 14, 2019, Alexandre Oliva <oliva@adacore.com> wrote:

> In order to address this, I propose we add an internal option (not for
> the driver), -dumpbase-ext, that names the extension to be discarded
> from dumpbase to form aux output names.

Here's a WIP patch that implements much of the desired semantics.

I'm still struggling a bit with -gdwarf-split and -save-temps; -dumpbase
and multiple inputs, -dumpdir as a prefix, and -flto + -dump*.

-gdwarf-split uses %b to strip debug info into the .dwo file, so it
lands in the same location as the .o, rather than in a named -dumpdir as
specified in the .o debug info skeleton.  I'm thinking of arranging for
-dump* flags to affect %b and %B, just like -save-temps does.  I've
reviewed all uses of %b and %B, and it looks like this would enable us
to fix the .dwo naming mismatch without significant complication.

Which brings us to the next issue.  This would cause -dumpdir to
override the -save-temps location.  This is arguably an improvement.  It
might conflict with -save-temps=cwd, however.

I'm considering rejecting command lines that specify both an explicit
-dumpdir and -save-temps=cwd, and in the absence of an explicit
-dumpdir, arranging for -save-temps=cwd or -save-temps=obj to override
what would otherwise be the default -dumpdir.

Or, for the sake of simplifying and bringing more sanity to the logic of
naming extra output files, we could just discontinue -save-temps=*, and
require -dumpdir ./ along with plain -save-temps to get the effects of
-save-temps=cwd.


When compiling multiple inputs with a single -dumpbase, the current
implementation arranges for each compilation to take an adjusted
-dumpbase appending -<input> to the given dumpbase, minus extension.  An
alternative would be to reject such compilations, just as we reject
multiple compilations with a single object file named as output.  That
feels excessive for -dumpbase, however.  OTOH, adjusting -dumpbase only
when there are multiple inputs causes different behavior comparing:

  gcc -c foo.c -dumpbase foobar && gcc -c bar.c -dumpbase foobar

and

  gcc -c foo.c bar.c -dumpbase foobar

The latter will name outputs after foobar-foo and foobar-bar,
respectively, whereas the former will overwrite outputs named foobar
when compiling bar.c.  Under the proposal to modify %b according to
-dump*, even object files would be named after an explicit -dumpbase,
when -o is not explicitly specified.


Yet another thing I'm not so sure about is -dumpdir as a prefix, e.g.,
in cases we're compiling multiple files and then linking them together,
say 'gcc foo.c bar.c -o foobar', the proposal was to name dumps of the
compilations after foobar-foo and foobar-bar, respectively.

If we use -dumpdir as a prefix to dump names, as we historically have,
if it doesn't end with a slash (or any dir separator) then it could be
used to specify the prefix for multiple outputs, as in the above.  So
gcc -dumpdir foobar- foo.c bar.c -o foobar *could* be equivalent to the
above.  I.e., an executable output name would affect the -dumpdir, but
not the -dumpbase passed to the compiler, whereas -dumpbase would be
derived from an asm or obj output or from input.

In the end, they're pasted together one way or the other, the difference
is the ability to override one or the other.  E.g.,

  gcc -dumpbase foobar foo.c bar.c -c

could then be rejected, just as -o foo+bar.o would be, or foobar could
be appended to the implicit -dumpdir and then override -dumpbase to
foo.c or bar.c in each compilation, to get foobar-foo.o and foobar-bar.o
outputs, getting the same as:

  gcc -dumpdir foobar- foo.c bar.c -c

and then

  gcc -dumpdir temp/foobar- foo.c bar.c -o foo+bar -save-temps

would still create and preserve .o (and .i and .s) named after
foobar-foo and foobar-bar within temp, rather than foo+bar-foo and
foo+bar-bar.

Now, the implementation in the patch below places the link output name,
implicit or not, in the default -dumpbase rather than -dumpdir, so the
last command above would create temp/foobar-foo+bar-foo.o and
temp/foobar-foo+bar-bar.o.  It's this ability to override the
executable-name prefix we're adding to outputs separately from -dumpbase
that I find somewhat appealing, in that it enables even the effect of
such prefixing to be canceled out with e.g. -dumpdir ./

Any thoughts for or against (or requests for clarification on :-) any of
the above proposed changes?


As for -flto + -dump*, the problem is that lto-wrapper doesn't take any
-dump* flags into account, it just overrides them all as if none had
been specified, which is undesirable.  That's fixable, it's just that
I haven't got to it yet.

I haven't brought in the design/documentation into a .texi file yet.
Please refer to posts upthread for the proposal.


Here's the WIP patch, FTR:

---
 gcc/ada/gcc-interface/lang-specs.h |    7 +
 gcc/ada/switch.adb                 |    4 -
 gcc/common.opt                     |   19 ++-
 gcc/dwarf2out.c                    |    3 -
 gcc/fortran/options.c              |    4 -
 gcc/gcc.c                          |  213 ++++++++++++++++++++++--------------
 gcc/lto-wrapper.c                  |   38 +++++-
 gcc/opts.c                         |   35 ------
 gcc/toplev.c                       |   36 +++++-
 9 files changed, 211 insertions(+), 148 deletions(-)

diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
index 374fc1e..344fe64 100644
--- a/gcc/ada/gcc-interface/lang-specs.h
+++ b/gcc/ada/gcc-interface/lang-specs.h
@@ -34,11 +34,10 @@
  %{!S:%{!c:%e-c or -S required for Ada}}\
  gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
-    %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b) -gnatd_A} \
-    %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}}} \
-    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} \
+    %{fcompare-debug-second:-gnatd_A} \
+    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps() \
     %{coverage:-fprofile-arcs -ftest-coverage} "
+/* -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}} */
 #if defined(TARGET_VXWORKS_RTP)
    "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
 #endif
diff --git a/gcc/ada/switch.adb b/gcc/ada/switch.adb
index 7cdaa196..b6f4e00 100644
--- a/gcc/ada/switch.adb
+++ b/gcc/ada/switch.adb
@@ -163,9 +163,9 @@ package body Switch is
       return Is_Switch (Switch_Chars)
         and then
           (Switch_Chars (First .. Last) = "-param"        or else
+           Switch_Chars (First .. Last) = "dumpdir"       or else
            Switch_Chars (First .. Last) = "dumpbase"      or else
-           Switch_Chars (First .. Last) = "auxbase-strip" or else
-           Switch_Chars (First .. Last) = "auxbase");
+           Switch_Chars (First .. Last) = "dumpbase-ext");
    end Is_Internal_GCC_Switch;
 
    ---------------
diff --git a/gcc/common.opt b/gcc/common.opt
index 404b6aa..e37e324 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -188,6 +188,12 @@ const char *main_input_basename
 Variable
 int main_input_baselength
 
+; The base name used for auxiliary output files.
+; dump_base_name minus dump_base_ext.
+
+Variable
+const char *aux_base_name
+
 ; Which options have been printed by --help.
 Variable
 char *help_printed
@@ -254,6 +260,9 @@ Common Joined Alias(d)
 -dumpbase
 Common Separate Alias(dumpbase)
 
+-dumpbase-ext
+Common Separate Alias(dumpbase-ext)
+
 -dumpdir
 Common Separate Alias(dumpdir)
 
@@ -840,12 +849,6 @@ Common Separate Var(aux_info_file_name)
 aux-info=
 Common Joined Alias(aux-info)
 
-auxbase
-Common Separate RejectDriver Var(aux_base_name)
-
-auxbase-strip
-Common Separate RejectDriver
-
 coverage
 Driver
 
@@ -860,6 +863,10 @@ dumpbase
 Common Separate Var(dump_base_name)
 -dumpbase <file>	Set the file basename to be used for dumps.
 
+dumpbase-ext
+Common Separate Var(dump_base_ext)
+-dumpbase-ext .<ext>    Drop a trailing .<ext> from the dump basename to name auxiliary output files.
+
 dumpdir
 Common Separate Var(dump_dir_name)
 -dumpdir <dir>	Set the directory name to be used for dumps.
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 6fb345b..06154d9 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -24466,9 +24466,8 @@ gen_producer_string (void)
       case OPT_o:
       case OPT_d:
       case OPT_dumpbase:
+      case OPT_dumpbase_ext:
       case OPT_dumpdir:
-      case OPT_auxbase:
-      case OPT_auxbase_strip:
       case OPT_quiet:
       case OPT_version:
       case OPT_v:
diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
index f7a5299c..6a4b9eb 100644
--- a/gcc/fortran/options.c
+++ b/gcc/fortran/options.c
@@ -833,8 +833,8 @@ gfc_get_option_string (void)
         case OPT_o:
         case OPT_d:
         case OPT_dumpbase:
+        case OPT_dumpbase_ext:
         case OPT_dumpdir:
-        case OPT_auxbase:
         case OPT_quiet:
         case OPT_version:
         case OPT_fintrinsic_modules_path:
@@ -859,8 +859,8 @@ gfc_get_option_string (void)
         case OPT_o:
         case OPT_d:
         case OPT_dumpbase:
+        case OPT_dumpbase_ext:
         case OPT_dumpdir:
-        case OPT_auxbase:
         case OPT_quiet:
         case OPT_version:
         case OPT_fintrinsic_modules_path:
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 4428d50..b284842 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -402,8 +402,8 @@ static const char *find_plugindir_spec_function (int, const char **);
 static const char *print_asm_header_spec_function (int, const char **);
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
-static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
 static const char *pass_through_libs_spec_func (int, const char **);
+static const char *dumps_spec_func (int, const char **);
 static const char *replace_extension_spec_func (int, const char **);
 static const char *greater_than_spec_func (int, const char **);
 static const char *debug_level_greater_than_spec_func (int, const char **);
@@ -642,7 +642,7 @@ proper position among the other output files.  */
   "%{gsplit-dwarf: \n\
        objcopy --extract-dwo \
 	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
-	 %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
+	 %{c:%{o*:%.dwo%*}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
        objcopy --strip-dwo \
 	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
     }"
@@ -1145,9 +1145,7 @@ static const char *cpp_debug_options = "%{d*}";
 static const char *cc1_options =
 "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
  %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
- %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
- %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
- %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
+ %1 %{!Q:-quiet} %{d*} %{m*} %{aux-info*} %:dumps()\
  %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
  %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
  %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
@@ -1642,9 +1640,8 @@ static const struct spec_function static_spec_functions[] =
   { "print-asm-header",		print_asm_header_spec_function },
   { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
-  { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
   { "pass-through-libs",	pass_through_libs_spec_func },
-  { "replace-extension",	replace_extension_spec_func },
+  { "dumps",                    dumps_spec_func },
   { "gt",			greater_than_spec_func },
   { "debug-level-gt",		debug_level_greater_than_spec_func },
   { "fortran-preinclude-file",	find_fortran_preinclude_file},
@@ -9787,8 +9784,6 @@ compare_debug_dump_opt_spec_function (int arg,
   return ret;
 }
 
-static const char *debug_auxbase_opt;
-
 /* %:compare-debug-self-opt spec function.  Expands to the options
     that are to be passed in the second compilation of
     compare-debug.  */
@@ -9807,13 +9802,6 @@ compare_debug_self_opt_spec_function (int arg,
   do_spec_2 ("%{c|S:%{o*:%*}}", NULL);
   do_spec_1 (" ", 0, NULL);
 
-  if (argbuf.length () > 0)
-    debug_auxbase_opt = concat ("-auxbase-strip ",
-				argbuf.last (),
-				NULL);
-  else
-    debug_auxbase_opt = NULL;
-
   return concat ("\
 %<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
 %<fdump-final-insns=* -w -S -o %j \
@@ -9821,50 +9809,6 @@ compare_debug_self_opt_spec_function (int arg,
 ", compare_debug_opt, NULL);
 }
 
-/* %:compare-debug-auxbase-opt spec function.  Expands to the auxbase
-    options that are to be passed in the second compilation of
-    compare-debug.  It expects, as an argument, the basename of the
-    current input file name, with the .gk suffix appended to it.  */
-
-static const char *
-compare_debug_auxbase_opt_spec_function (int arg,
-					 const char **argv)
-{
-  char *name;
-  int len;
-
-  if (arg == 0)
-    fatal_error (input_location,
-		 "too few arguments to %%:compare-debug-auxbase-opt");
-
-  if (arg != 1)
-    fatal_error (input_location,
-		 "too many arguments to %%:compare-debug-auxbase-opt");
-
-  if (compare_debug >= 0)
-    return NULL;
-
-  len = strlen (argv[0]);
-  if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
-    fatal_error (input_location, "argument to %%:compare-debug-auxbase-opt "
-		 "does not end in %<.gk%>");
-
-  if (debug_auxbase_opt)
-    return debug_auxbase_opt;
-
-#define OPT "-auxbase "
-
-  len -= 3;
-  name = (char*) xmalloc (sizeof (OPT) + len);
-  memcpy (name, OPT, sizeof (OPT) - 1);
-  memcpy (name + sizeof (OPT) - 1, argv[0], len);
-  name[sizeof (OPT) - 1 + len] = '\0';
-
-#undef OPT
-
-  return name;
-}
-
 /* %:pass-through-libs spec function.  Finds all -l options and input
    file names in the lib spec passed to it, and makes a list of them
    prepended with the plugin option to cause them to be passed through
@@ -9908,34 +9852,143 @@ pass_through_libs_spec_func (int argc, const char **argv)
   return prepended;
 }
 
-/* %:replace-extension spec function.  Replaces the extension of the
-   first argument with the second argument.  */
+static bool
+not_actual_file_p (const char *name)
+{
+  return (strcmp (name, "-") == 0
+	  || strcmp (output_file, HOST_BIT_BUCKET) == 0);
+}
 
+/* %:dumps spec function.  Take no arguments.
+    Return -dumpdir, -dumpbase and -dumpbase-ext, if needed.  */
 const char *
-replace_extension_spec_func (int argc, const char **argv)
+dumps_spec_func (int argc, const char **argv)
 {
-  char *name;
-  char *p;
-  char *result;
+  bool found_dumpdir = false;
+  const char *found_dumpbase = NULL;
+  bool found_dumpext = false;
+  bool found_cS = false;
+  const char *oname = NULL;
   int i;
 
-  if (argc != 2)
-    fatal_error (input_location, "too few arguments to %%:replace-extension");
+  char *args[3] = { NULL, NULL, NULL };
+  int nargs = 0;
 
-  name = xstrdup (argv[0]);
+  if (argc != 0)
+    fatal_error (input_location, "too few arguments for %%:dumps");
 
-  for (i = strlen (name) - 1; i >= 0; i--)
-    if (IS_DIR_SEPARATOR (name[i]))
-      break;
+  for (i = 0; i < n_switches; i++)
+    {
+      const char *s = switches[i].part1;
+      switch (s[0])
+	{
+	case 'c':
+	  if (!s[1] && check_live_switch (i, 1))
+	    found_cS = true;
+	  break;
 
-  p = strrchr (name + i + 1, '.');
-  if (p != NULL)
-      *p = '\0';
+	case 'S':
+	  if (!s[1] && check_live_switch (i, 1))
+	    found_cS = true;
+	  break;
 
-  result = concat (name, argv[1], NULL);
+	case 'o':
+	  if (!s[1] && check_live_switch (i, 1))
+	    oname = switches[i].args[0];
+	  break;
 
-  free (name);
-  return result;
+	case 'd':
+	  if (strncmp (s, "dump", 4) != 0)
+	    break;
+	  switch (s[4])
+	    {
+	    case 'd':
+	      if (strcmp (s + 4, "dir") == 0
+		  && check_live_switch (i, 7))
+		found_dumpdir = true;
+	      break;
+
+	    case 'b':
+	      if (strncmp (s + 4, "base", 4) == 0
+		  && check_live_switch (i, 8))
+		{
+		  if (!s[8])
+		    found_dumpbase = switches[i].args[0];
+		  else if (strcmp (s + 8, "-ext") == 0)
+		    found_dumpext = true;
+		}
+	      break;
+
+	    default:
+	      break;
+	    }
+
+	default:
+	  break;
+	}
+    }
+
+  if (oname && not_actual_file_p (oname))
+    oname = NULL;
+
+  char *dir = NULL;
+  if (oname)
+    {
+      for (i = strlen (oname) - 1; i >= 0; i--)
+	if (IS_DIR_SEPARATOR (oname[i]))
+	  break;
+
+      if (!found_dumpdir && i >= 0)
+	{
+	  dir = xstrdup (oname);
+	  int j = i + 1;
+
+	  do
+	    dir[j] = '\0';
+	  while (j > 0 && IS_DIR_SEPARATOR (oname[j]));
+	}
+
+      oname += i + 1;
+    }
+
+  /* A "./" would be redundant, so omit -dumpdir for NULL dir.  */
+  if (!found_dumpdir && dir)
+    args[nargs++] = concat (" -dumpdir ",
+			    dir ? convert_white_space (dir) : "./",
+			    NULL);
+  free (dir);
+
+  char *ext = xstrdup (input_basename + basename_length);
+
+  if (!found_dumpbase || n_infiles > 1)
+    {
+      char *base = xstrdup (found_dumpbase ? found_dumpbase
+			    : oname ? oname : found_cS ? input_basename : "a");
+      char *p = *base ? strrchr (base + 1, '.') : NULL;
+      if (p)
+	*p = '\0';
+
+      if (!found_dumpbase && found_cS)
+	p = concat (base, ext, NULL);
+      else
+	p = concat (base, "-", input_basename, NULL);
+
+      free (base);
+      base = p;
+
+      args[nargs++] = concat (" -dumpbase ", convert_white_space (base), NULL);
+      free (base);
+    }
+
+  if (!found_dumpext && *ext)
+    args[nargs++] = concat (" -dumpbase-ext ", convert_white_space (ext), NULL);
+  free (ext);
+
+  const char *ret = concat (args[0], args[1], args[2], NULL);
+  while (nargs > 0)
+    free (args[--nargs]);
+
+  return ret;
 }
 
 /* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
@@ -10085,7 +10138,7 @@ convert_white_space (char *orig)
 	}
       free (orig);
       return new_spec;
-  }
+    }
   else
     return orig;
 }
@@ -10264,8 +10317,6 @@ driver::finalize ()
   mdswitches = NULL;
   n_mdswitches = 0;
 
-  debug_auxbase_opt = NULL;
-
   used_arg.finalize ();
 }
 
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index 9a7bbd0..7099e6b 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -1250,6 +1250,7 @@ run_gcc (unsigned argc, char *argv[])
   const char **argv_ptr;
   char *list_option_full = NULL;
   const char *linker_output = NULL;
+  const char *linker_output_or_a = "a";
   const char *collect_gcc, *collect_gcc_options;
   int parallel = 0;
   int jobserver = 0;
@@ -1462,6 +1463,21 @@ run_gcc (unsigned argc, char *argv[])
 	  obstack_ptr_grow (&argv_obstack, output_dir);
 	}
 
+      obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+      obstack_ptr_grow (&argv_obstack, ".");
+
+      obstack_ptr_grow (&argv_obstack, "-dumpbase");
+      linker_output_or_a = linker_output;
+    }
+  else
+    {
+      static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
+      obstack_ptr_grow (&argv_obstack, "-dumpdir");
+      obstack_ptr_grow (&argv_obstack, current_dir);
+
+      obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+      obstack_ptr_grow (&argv_obstack, ".");
+
       obstack_ptr_grow (&argv_obstack, "-dumpbase");
     }
 
@@ -1578,7 +1594,7 @@ cont1:
 	  strcat (flto_out, ".lto.o");
 	}
       else
-	flto_out = make_temp_file (".lto.o");
+	flto_out = make_temp_file_with_prefix ("a.", ".lto.o");
       obstack_ptr_grow (&argv_obstack, "-o");
       obstack_ptr_grow (&argv_obstack, flto_out);
     }
@@ -1588,11 +1604,11 @@ cont1:
       size_t list_option_len = strlen (list_option);
       char *tmp;
 
-      if (linker_output)
+      if (linker_output_or_a)
 	{
-	  char *dumpbase = (char *) xmalloc (strlen (linker_output)
+	  char *dumpbase = (char *) xmalloc (strlen (linker_output_or_a)
 					     + sizeof (".wpa") + 1);
-	  strcpy (dumpbase, linker_output);
+	  strcpy (dumpbase, linker_output_or_a);
 	  strcat (dumpbase, ".wpa");
 	  obstack_ptr_grow (&argv_obstack, dumpbase);
 	}
@@ -1607,10 +1623,10 @@ cont1:
       else
 	{
 	  char *prefix = NULL;
-	  if (linker_output)
+	  if (linker_output_or_a)
 	    {
-	      prefix = (char *) xmalloc (strlen (linker_output) + 2);
-	      strcpy (prefix, linker_output);
+	      prefix = (char *) xmalloc (strlen (linker_output_or_a) + 2);
+	      strcpy (prefix, linker_output_or_a);
 	      strcat (prefix, ".");
 	    }
 
@@ -1781,14 +1797,14 @@ cont:
 	  output_name = XOBFINISH (&env_obstack, char *);
 
 	  /* Adjust the dumpbase if the linker output file was seen.  */
-	  if (linker_output)
+	  if (linker_output_or_a)
 	    {
 	      char *dumpbase
-		  = (char *) xmalloc (strlen (linker_output)
+		  = (char *) xmalloc (strlen (linker_output_or_a)
 				      + sizeof (DUMPBASE_SUFFIX) + 1);
 	      snprintf (dumpbase,
-			strlen (linker_output) + sizeof (DUMPBASE_SUFFIX),
-			"%s.ltrans%u", linker_output, i);
+			strlen (linker_output_or_a) + sizeof (DUMPBASE_SUFFIX),
+			"%s.ltrans%u", linker_output_or_a, i);
 	      argv_ptr[0] = dumpbase;
 	    }
 
diff --git a/gcc/opts.c b/gcc/opts.c
index 3c53fbe..411652c 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -845,30 +845,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	/* We have a DUMP_DIR_NAME, prepend that.  */
 	opts->x_dump_base_name = opts_concat (opts->x_dump_dir_name,
 					      opts->x_dump_base_name, NULL);
-      else if (opts->x_aux_base_name
-	       && strcmp (opts->x_aux_base_name, HOST_BIT_BUCKET) != 0)
-	/* AUX_BASE_NAME is set and is not the bit bucket.  If it
-	   contains a directory component, prepend those directories.
-	   Typically this places things in the same directory as the
-	   object file.  */
-	{
-	  const char *aux_base;
-
-	  base_of_path (opts->x_aux_base_name, &aux_base);
-	  if (opts->x_aux_base_name != aux_base)
-	    {
-	      int dir_len = aux_base - opts->x_aux_base_name;
-	      char *new_dump_base_name
-		= XOBNEWVEC (&opts_obstack, char,
-			     strlen (opts->x_dump_base_name) + dir_len + 1);
-
-	      /* Copy directory component from OPTS->X_AUX_BASE_NAME.  */
-	      memcpy (new_dump_base_name, opts->x_aux_base_name, dir_len);
-	      /* Append existing OPTS->X_DUMP_BASE_NAME.  */
-	      strcpy (new_dump_base_name + dir_len, opts->x_dump_base_name);
-	      opts->x_dump_base_name = new_dump_base_name;
-	    }
-	}
 
       /* It is definitely prefixed now.  */
       opts->x_dump_base_name_prefixed = true;
@@ -2314,17 +2290,6 @@ common_handle_option (struct gcc_options *opts,
       opts->x_flag_gen_aux_info = 1;
       break;
 
-    case OPT_auxbase_strip:
-      {
-	char *tmp = xstrdup (arg);
-	strip_off_ending (tmp, strlen (tmp));
-	if (tmp[0])
-	  opts->x_aux_base_name = tmp;
-	else
-	  free (tmp);
-      }
-      break;
-
     case OPT_d:
       decode_d_option (arg, opts, loc, dc);
       break;
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 059046f..0c6e096 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -796,8 +796,8 @@ print_switch_values (print_switch_fn_type print_fn)
 	case OPT_o:
 	case OPT_d:
 	case OPT_dumpbase:
+	case OPT_dumpbase_ext:
 	case OPT_dumpdir:
-	case OPT_auxbase:
 	case OPT_quiet:
 	case OPT_version:
 	  /* Ignore these.  */
@@ -1401,18 +1401,44 @@ process_options (void)
   if (flag_short_enums == 2)
     flag_short_enums = targetm.default_short_enums ();
 
+  if (dump_base_ext)
+    ;
+  else if (main_input_filename)
+    {
+      const char *name = lbasename (main_input_filename);
+      const char *ext = strrchr (name, '.');
+      if (ext)
+	dump_base_ext = ext;
+      else
+	dump_base_ext = "";
+    }
+  else
+    dump_base_ext = "";
+
   /* Set aux_base_name if not already set.  */
   if (aux_base_name)
     ;
-  else if (main_input_filename)
+  else if (dump_base_name)
     {
-      char *name = xstrdup (lbasename (main_input_filename));
+      const char *name = dump_base_name;
+      int nlen, len;
+
+      if (dump_base_ext && (len = strlen (dump_base_ext))
+	  && (nlen = strlen (name)) && nlen > len
+	  && strcmp (name + nlen - len, dump_base_ext) == 0)
+	{
+	  char *p = xstrdup (name);
+	  p[nlen - len] = '\0';
+	  name = (const char *) xrealloc (p, nlen - len + 1);
+	}
 
-      strip_off_ending (name, strlen (name));
       aux_base_name = name;
     }
   else
-    aux_base_name = "gccaux";
+    {
+      if (dump_dir_name)
+      aux_base_name = "gccaux";
+    }
 
 #ifndef HAVE_isl
   if (flag_graphite
Richard Biener Dec. 9, 2019, 9:41 a.m. UTC | #33
On Tue, 3 Dec 2019, Alexandre Oliva wrote:

> On Nov 14, 2019, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > In order to address this, I propose we add an internal option (not for
> > the driver), -dumpbase-ext, that names the extension to be discarded
> > from dumpbase to form aux output names.
> 
> Here's a WIP patch that implements much of the desired semantics.
> 
> I'm still struggling a bit with -gdwarf-split and -save-temps; -dumpbase
> and multiple inputs, -dumpdir as a prefix, and -flto + -dump*.
> 
> -gdwarf-split uses %b to strip debug info into the .dwo file, so it
> lands in the same location as the .o, rather than in a named -dumpdir as
> specified in the .o debug info skeleton.  I'm thinking of arranging for
> -dump* flags to affect %b and %B, just like -save-temps does.  I've
> reviewed all uses of %b and %B, and it looks like this would enable us
> to fix the .dwo naming mismatch without significant complication.
> 
> Which brings us to the next issue.  This would cause -dumpdir to
> override the -save-temps location.  This is arguably an improvement.  It
> might conflict with -save-temps=cwd, however.
> 
> I'm considering rejecting command lines that specify both an explicit
> -dumpdir and -save-temps=cwd, and in the absence of an explicit
> -dumpdir, arranging for -save-temps=cwd or -save-temps=obj to override
> what would otherwise be the default -dumpdir.
> 
> Or, for the sake of simplifying and bringing more sanity to the logic of
> naming extra output files, we could just discontinue -save-temps=*, and
> require -dumpdir ./ along with plain -save-temps to get the effects of
> -save-temps=cwd.

Making -save-temps=cwd essentially a short-cut to -save-temps -dumpdir ./
is fine I guess (we usually do not start to reject previously accepted
options).  Auto-magically splitting this via the 'Alias' mechanism
isn't (yet) supported I think (split one option into two others).

> 
> When compiling multiple inputs with a single -dumpbase, the current
> implementation arranges for each compilation to take an adjusted
> -dumpbase appending -<input> to the given dumpbase, minus extension.  An
> alternative would be to reject such compilations, just as we reject
> multiple compilations with a single object file named as output.  That
> feels excessive for -dumpbase, however.  OTOH, adjusting -dumpbase only
> when there are multiple inputs causes different behavior comparing:
> 
>   gcc -c foo.c -dumpbase foobar && gcc -c bar.c -dumpbase foobar
> 
> and
> 
>   gcc -c foo.c bar.c -dumpbase foobar
> 
> The latter will name outputs after foobar-foo and foobar-bar,
> respectively, whereas the former will overwrite outputs named foobar
> when compiling bar.c.  Under the proposal to modify %b according to
> -dump*, even object files would be named after an explicit -dumpbase,
> when -o is not explicitly specified.

I think rejecting option combinations that do not make much sense
or would introduce inconsistencies like this is better than trying
to invent creative things second-guessing what the user meant.

> Yet another thing I'm not so sure about is -dumpdir as a prefix, e.g.,
> in cases we're compiling multiple files and then linking them together,
> say 'gcc foo.c bar.c -o foobar', the proposal was to name dumps of the
> compilations after foobar-foo and foobar-bar, respectively.
> 
> If we use -dumpdir as a prefix to dump names, as we historically have,
> if it doesn't end with a slash (or any dir separator) then it could be
> used to specify the prefix for multiple outputs, as in the above.  So
> gcc -dumpdir foobar- foo.c bar.c -o foobar *could* be equivalent to the
> above.  I.e., an executable output name would affect the -dumpdir, but
> not the -dumpbase passed to the compiler, whereas -dumpbase would be
> derived from an asm or obj output or from input.
> 
> In the end, they're pasted together one way or the other, the difference
> is the ability to override one or the other.  E.g.,
> 
>   gcc -dumpbase foobar foo.c bar.c -c
> 
> could then be rejected, just as -o foo+bar.o would be, or foobar could
> be appended to the implicit -dumpdir and then override -dumpbase to
> foo.c or bar.c in each compilation, to get foobar-foo.o and foobar-bar.o
> outputs, getting the same as:
> 
>   gcc -dumpdir foobar- foo.c bar.c -c
> 
> and then
> 
>   gcc -dumpdir temp/foobar- foo.c bar.c -o foo+bar -save-temps
> 
> would still create and preserve .o (and .i and .s) named after
> foobar-foo and foobar-bar within temp, rather than foo+bar-foo and
> foo+bar-bar.

Hum.  I didn't notice -dumpdir is just a prefix and I wouldn't object
to make it errorneous if it doesn't specify an acutal directory.

I also note that neither -dumpdir nor -dumpbase are documented
in invoke.texi (as opposed to -auxbase and -auxbase-strip which
are not user-accessible as they are rejected by the driver).
Not sure if all this means we should document the altered behavior
or if we should take it as a hint we can alter behavior at will
(in future) ;)

> Now, the implementation in the patch below places the link output name,
> implicit or not, in the default -dumpbase rather than -dumpdir, so the
> last command above would create temp/foobar-foo+bar-foo.o and
> temp/foobar-foo+bar-bar.o.  It's this ability to override the
> executable-name prefix we're adding to outputs separately from -dumpbase
> that I find somewhat appealing, in that it enables even the effect of
> such prefixing to be canceled out with e.g. -dumpdir ./
> 
> Any thoughts for or against (or requests for clarification on :-) any of
> the above proposed changes?

I like the streamlining a lot, but yeah, looks like a quite messy area.
Thanks again for digging through all of this.

> As for -flto + -dump*, the problem is that lto-wrapper doesn't take any
> -dump* flags into account, it just overrides them all as if none had
> been specified, which is undesirable.  That's fixable, it's just that
> I haven't got to it yet.

Sure.

Thanks,
Richard.

> I haven't brought in the design/documentation into a .texi file yet.
> Please refer to posts upthread for the proposal.
>
> 
> Here's the WIP patch, FTR: 
> ---
>  gcc/ada/gcc-interface/lang-specs.h |    7 +
>  gcc/ada/switch.adb                 |    4 -
>  gcc/common.opt                     |   19 ++-
>  gcc/dwarf2out.c                    |    3 -
>  gcc/fortran/options.c              |    4 -
>  gcc/gcc.c                          |  213 ++++++++++++++++++++++--------------
>  gcc/lto-wrapper.c                  |   38 +++++-
>  gcc/opts.c                         |   35 ------
>  gcc/toplev.c                       |   36 +++++-
>  9 files changed, 211 insertions(+), 148 deletions(-)
> 
> diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
> index 374fc1e..344fe64 100644
> --- a/gcc/ada/gcc-interface/lang-specs.h
> +++ b/gcc/ada/gcc-interface/lang-specs.h
> @@ -34,11 +34,10 @@
>   %{!S:%{!c:%e-c or -S required for Ada}}\
>   gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
> -    %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b) -gnatd_A} \
> -    %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}}} \
> -    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} \
> +    %{fcompare-debug-second:-gnatd_A} \
> +    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps() \
>      %{coverage:-fprofile-arcs -ftest-coverage} "
> +/* -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}} */
>  #if defined(TARGET_VXWORKS_RTP)
>     "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
>  #endif
> diff --git a/gcc/ada/switch.adb b/gcc/ada/switch.adb
> index 7cdaa196..b6f4e00 100644
> --- a/gcc/ada/switch.adb
> +++ b/gcc/ada/switch.adb
> @@ -163,9 +163,9 @@ package body Switch is
>        return Is_Switch (Switch_Chars)
>          and then
>            (Switch_Chars (First .. Last) = "-param"        or else
> +           Switch_Chars (First .. Last) = "dumpdir"       or else
>             Switch_Chars (First .. Last) = "dumpbase"      or else
> -           Switch_Chars (First .. Last) = "auxbase-strip" or else
> -           Switch_Chars (First .. Last) = "auxbase");
> +           Switch_Chars (First .. Last) = "dumpbase-ext");
>     end Is_Internal_GCC_Switch;
>  
>     ---------------
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 404b6aa..e37e324 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -188,6 +188,12 @@ const char *main_input_basename
>  Variable
>  int main_input_baselength
>  
> +; The base name used for auxiliary output files.
> +; dump_base_name minus dump_base_ext.
> +
> +Variable
> +const char *aux_base_name
> +
>  ; Which options have been printed by --help.
>  Variable
>  char *help_printed
> @@ -254,6 +260,9 @@ Common Joined Alias(d)
>  -dumpbase
>  Common Separate Alias(dumpbase)
>  
> +-dumpbase-ext
> +Common Separate Alias(dumpbase-ext)
> +
>  -dumpdir
>  Common Separate Alias(dumpdir)
>  
> @@ -840,12 +849,6 @@ Common Separate Var(aux_info_file_name)
>  aux-info=
>  Common Joined Alias(aux-info)
>  
> -auxbase
> -Common Separate RejectDriver Var(aux_base_name)
> -
> -auxbase-strip
> -Common Separate RejectDriver
> -
>  coverage
>  Driver
>  
> @@ -860,6 +863,10 @@ dumpbase
>  Common Separate Var(dump_base_name)
>  -dumpbase <file>	Set the file basename to be used for dumps.
>  
> +dumpbase-ext
> +Common Separate Var(dump_base_ext)
> +-dumpbase-ext .<ext>    Drop a trailing .<ext> from the dump basename to name auxiliary output files.
> +
>  dumpdir
>  Common Separate Var(dump_dir_name)
>  -dumpdir <dir>	Set the directory name to be used for dumps.
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index 6fb345b..06154d9 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -24466,9 +24466,8 @@ gen_producer_string (void)
>        case OPT_o:
>        case OPT_d:
>        case OPT_dumpbase:
> +      case OPT_dumpbase_ext:
>        case OPT_dumpdir:
> -      case OPT_auxbase:
> -      case OPT_auxbase_strip:
>        case OPT_quiet:
>        case OPT_version:
>        case OPT_v:
> diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
> index f7a5299c..6a4b9eb 100644
> --- a/gcc/fortran/options.c
> +++ b/gcc/fortran/options.c
> @@ -833,8 +833,8 @@ gfc_get_option_string (void)
>          case OPT_o:
>          case OPT_d:
>          case OPT_dumpbase:
> +        case OPT_dumpbase_ext:
>          case OPT_dumpdir:
> -        case OPT_auxbase:
>          case OPT_quiet:
>          case OPT_version:
>          case OPT_fintrinsic_modules_path:
> @@ -859,8 +859,8 @@ gfc_get_option_string (void)
>          case OPT_o:
>          case OPT_d:
>          case OPT_dumpbase:
> +        case OPT_dumpbase_ext:
>          case OPT_dumpdir:
> -        case OPT_auxbase:
>          case OPT_quiet:
>          case OPT_version:
>          case OPT_fintrinsic_modules_path:
> diff --git a/gcc/gcc.c b/gcc/gcc.c
> index 4428d50..b284842 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -402,8 +402,8 @@ static const char *find_plugindir_spec_function (int, const char **);
>  static const char *print_asm_header_spec_function (int, const char **);
>  static const char *compare_debug_dump_opt_spec_function (int, const char **);
>  static const char *compare_debug_self_opt_spec_function (int, const char **);
> -static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
>  static const char *pass_through_libs_spec_func (int, const char **);
> +static const char *dumps_spec_func (int, const char **);
>  static const char *replace_extension_spec_func (int, const char **);
>  static const char *greater_than_spec_func (int, const char **);
>  static const char *debug_level_greater_than_spec_func (int, const char **);
> @@ -642,7 +642,7 @@ proper position among the other output files.  */
>    "%{gsplit-dwarf: \n\
>         objcopy --extract-dwo \
>  	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> -	 %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
> +	 %{c:%{o*:%.dwo%*}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
>         objcopy --strip-dwo \
>  	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
>      }"
> @@ -1145,9 +1145,7 @@ static const char *cpp_debug_options = "%{d*}";
>  static const char *cc1_options =
>  "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
>   %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
> - %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
> - %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
> - %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
> + %1 %{!Q:-quiet} %{d*} %{m*} %{aux-info*} %:dumps()\
>   %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
>   %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
>   %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
> @@ -1642,9 +1640,8 @@ static const struct spec_function static_spec_functions[] =
>    { "print-asm-header",		print_asm_header_spec_function },
>    { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
>    { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
> -  { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
>    { "pass-through-libs",	pass_through_libs_spec_func },
> -  { "replace-extension",	replace_extension_spec_func },
> +  { "dumps",                    dumps_spec_func },
>    { "gt",			greater_than_spec_func },
>    { "debug-level-gt",		debug_level_greater_than_spec_func },
>    { "fortran-preinclude-file",	find_fortran_preinclude_file},
> @@ -9787,8 +9784,6 @@ compare_debug_dump_opt_spec_function (int arg,
>    return ret;
>  }
>  
> -static const char *debug_auxbase_opt;
> -
>  /* %:compare-debug-self-opt spec function.  Expands to the options
>      that are to be passed in the second compilation of
>      compare-debug.  */
> @@ -9807,13 +9802,6 @@ compare_debug_self_opt_spec_function (int arg,
>    do_spec_2 ("%{c|S:%{o*:%*}}", NULL);
>    do_spec_1 (" ", 0, NULL);
>  
> -  if (argbuf.length () > 0)
> -    debug_auxbase_opt = concat ("-auxbase-strip ",
> -				argbuf.last (),
> -				NULL);
> -  else
> -    debug_auxbase_opt = NULL;
> -
>    return concat ("\
>  %<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
>  %<fdump-final-insns=* -w -S -o %j \
> @@ -9821,50 +9809,6 @@ compare_debug_self_opt_spec_function (int arg,
>  ", compare_debug_opt, NULL);
>  }
>  
> -/* %:compare-debug-auxbase-opt spec function.  Expands to the auxbase
> -    options that are to be passed in the second compilation of
> -    compare-debug.  It expects, as an argument, the basename of the
> -    current input file name, with the .gk suffix appended to it.  */
> -
> -static const char *
> -compare_debug_auxbase_opt_spec_function (int arg,
> -					 const char **argv)
> -{
> -  char *name;
> -  int len;
> -
> -  if (arg == 0)
> -    fatal_error (input_location,
> -		 "too few arguments to %%:compare-debug-auxbase-opt");
> -
> -  if (arg != 1)
> -    fatal_error (input_location,
> -		 "too many arguments to %%:compare-debug-auxbase-opt");
> -
> -  if (compare_debug >= 0)
> -    return NULL;
> -
> -  len = strlen (argv[0]);
> -  if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
> -    fatal_error (input_location, "argument to %%:compare-debug-auxbase-opt "
> -		 "does not end in %<.gk%>");
> -
> -  if (debug_auxbase_opt)
> -    return debug_auxbase_opt;
> -
> -#define OPT "-auxbase "
> -
> -  len -= 3;
> -  name = (char*) xmalloc (sizeof (OPT) + len);
> -  memcpy (name, OPT, sizeof (OPT) - 1);
> -  memcpy (name + sizeof (OPT) - 1, argv[0], len);
> -  name[sizeof (OPT) - 1 + len] = '\0';
> -
> -#undef OPT
> -
> -  return name;
> -}
> -
>  /* %:pass-through-libs spec function.  Finds all -l options and input
>     file names in the lib spec passed to it, and makes a list of them
>     prepended with the plugin option to cause them to be passed through
> @@ -9908,34 +9852,143 @@ pass_through_libs_spec_func (int argc, const char **argv)
>    return prepended;
>  }
>  
> -/* %:replace-extension spec function.  Replaces the extension of the
> -   first argument with the second argument.  */
> +static bool
> +not_actual_file_p (const char *name)
> +{
> +  return (strcmp (name, "-") == 0
> +	  || strcmp (output_file, HOST_BIT_BUCKET) == 0);
> +}
>  
> +/* %:dumps spec function.  Take no arguments.
> +    Return -dumpdir, -dumpbase and -dumpbase-ext, if needed.  */
>  const char *
> -replace_extension_spec_func (int argc, const char **argv)
> +dumps_spec_func (int argc, const char **argv)
>  {
> -  char *name;
> -  char *p;
> -  char *result;
> +  bool found_dumpdir = false;
> +  const char *found_dumpbase = NULL;
> +  bool found_dumpext = false;
> +  bool found_cS = false;
> +  const char *oname = NULL;
>    int i;
>  
> -  if (argc != 2)
> -    fatal_error (input_location, "too few arguments to %%:replace-extension");
> +  char *args[3] = { NULL, NULL, NULL };
> +  int nargs = 0;
>  
> -  name = xstrdup (argv[0]);
> +  if (argc != 0)
> +    fatal_error (input_location, "too few arguments for %%:dumps");
>  
> -  for (i = strlen (name) - 1; i >= 0; i--)
> -    if (IS_DIR_SEPARATOR (name[i]))
> -      break;
> +  for (i = 0; i < n_switches; i++)
> +    {
> +      const char *s = switches[i].part1;
> +      switch (s[0])
> +	{
> +	case 'c':
> +	  if (!s[1] && check_live_switch (i, 1))
> +	    found_cS = true;
> +	  break;
>  
> -  p = strrchr (name + i + 1, '.');
> -  if (p != NULL)
> -      *p = '\0';
> +	case 'S':
> +	  if (!s[1] && check_live_switch (i, 1))
> +	    found_cS = true;
> +	  break;
>  
> -  result = concat (name, argv[1], NULL);
> +	case 'o':
> +	  if (!s[1] && check_live_switch (i, 1))
> +	    oname = switches[i].args[0];
> +	  break;
>  
> -  free (name);
> -  return result;
> +	case 'd':
> +	  if (strncmp (s, "dump", 4) != 0)
> +	    break;
> +	  switch (s[4])
> +	    {
> +	    case 'd':
> +	      if (strcmp (s + 4, "dir") == 0
> +		  && check_live_switch (i, 7))
> +		found_dumpdir = true;
> +	      break;
> +
> +	    case 'b':
> +	      if (strncmp (s + 4, "base", 4) == 0
> +		  && check_live_switch (i, 8))
> +		{
> +		  if (!s[8])
> +		    found_dumpbase = switches[i].args[0];
> +		  else if (strcmp (s + 8, "-ext") == 0)
> +		    found_dumpext = true;
> +		}
> +	      break;
> +
> +	    default:
> +	      break;
> +	    }
> +
> +	default:
> +	  break;
> +	}
> +    }
> +
> +  if (oname && not_actual_file_p (oname))
> +    oname = NULL;
> +
> +  char *dir = NULL;
> +  if (oname)
> +    {
> +      for (i = strlen (oname) - 1; i >= 0; i--)
> +	if (IS_DIR_SEPARATOR (oname[i]))
> +	  break;
> +
> +      if (!found_dumpdir && i >= 0)
> +	{
> +	  dir = xstrdup (oname);
> +	  int j = i + 1;
> +
> +	  do
> +	    dir[j] = '\0';
> +	  while (j > 0 && IS_DIR_SEPARATOR (oname[j]));
> +	}
> +
> +      oname += i + 1;
> +    }
> +
> +  /* A "./" would be redundant, so omit -dumpdir for NULL dir.  */
> +  if (!found_dumpdir && dir)
> +    args[nargs++] = concat (" -dumpdir ",
> +			    dir ? convert_white_space (dir) : "./",
> +			    NULL);
> +  free (dir);
> +
> +  char *ext = xstrdup (input_basename + basename_length);
> +
> +  if (!found_dumpbase || n_infiles > 1)
> +    {
> +      char *base = xstrdup (found_dumpbase ? found_dumpbase
> +			    : oname ? oname : found_cS ? input_basename : "a");
> +      char *p = *base ? strrchr (base + 1, '.') : NULL;
> +      if (p)
> +	*p = '\0';
> +
> +      if (!found_dumpbase && found_cS)
> +	p = concat (base, ext, NULL);
> +      else
> +	p = concat (base, "-", input_basename, NULL);
> +
> +      free (base);
> +      base = p;
> +
> +      args[nargs++] = concat (" -dumpbase ", convert_white_space (base), NULL);
> +      free (base);
> +    }
> +
> +  if (!found_dumpext && *ext)
> +    args[nargs++] = concat (" -dumpbase-ext ", convert_white_space (ext), NULL);
> +  free (ext);
> +
> +  const char *ret = concat (args[0], args[1], args[2], NULL);
> +  while (nargs > 0)
> +    free (args[--nargs]);
> +
> +  return ret;
>  }
>  
>  /* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
> @@ -10085,7 +10138,7 @@ convert_white_space (char *orig)
>  	}
>        free (orig);
>        return new_spec;
> -  }
> +    }
>    else
>      return orig;
>  }
> @@ -10264,8 +10317,6 @@ driver::finalize ()
>    mdswitches = NULL;
>    n_mdswitches = 0;
>  
> -  debug_auxbase_opt = NULL;
> -
>    used_arg.finalize ();
>  }
>  
> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> index 9a7bbd0..7099e6b 100644
> --- a/gcc/lto-wrapper.c
> +++ b/gcc/lto-wrapper.c
> @@ -1250,6 +1250,7 @@ run_gcc (unsigned argc, char *argv[])
>    const char **argv_ptr;
>    char *list_option_full = NULL;
>    const char *linker_output = NULL;
> +  const char *linker_output_or_a = "a";
>    const char *collect_gcc, *collect_gcc_options;
>    int parallel = 0;
>    int jobserver = 0;
> @@ -1462,6 +1463,21 @@ run_gcc (unsigned argc, char *argv[])
>  	  obstack_ptr_grow (&argv_obstack, output_dir);
>  	}
>  
> +      obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +      obstack_ptr_grow (&argv_obstack, ".");
> +
> +      obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +      linker_output_or_a = linker_output;
> +    }
> +  else
> +    {
> +      static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
> +      obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +      obstack_ptr_grow (&argv_obstack, current_dir);
> +
> +      obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +      obstack_ptr_grow (&argv_obstack, ".");
> +
>        obstack_ptr_grow (&argv_obstack, "-dumpbase");
>      }
>  
> @@ -1578,7 +1594,7 @@ cont1:
>  	  strcat (flto_out, ".lto.o");
>  	}
>        else
> -	flto_out = make_temp_file (".lto.o");
> +	flto_out = make_temp_file_with_prefix ("a.", ".lto.o");
>        obstack_ptr_grow (&argv_obstack, "-o");
>        obstack_ptr_grow (&argv_obstack, flto_out);
>      }
> @@ -1588,11 +1604,11 @@ cont1:
>        size_t list_option_len = strlen (list_option);
>        char *tmp;
>  
> -      if (linker_output)
> +      if (linker_output_or_a)
>  	{
> -	  char *dumpbase = (char *) xmalloc (strlen (linker_output)
> +	  char *dumpbase = (char *) xmalloc (strlen (linker_output_or_a)
>  					     + sizeof (".wpa") + 1);
> -	  strcpy (dumpbase, linker_output);
> +	  strcpy (dumpbase, linker_output_or_a);
>  	  strcat (dumpbase, ".wpa");
>  	  obstack_ptr_grow (&argv_obstack, dumpbase);
>  	}
> @@ -1607,10 +1623,10 @@ cont1:
>        else
>  	{
>  	  char *prefix = NULL;
> -	  if (linker_output)
> +	  if (linker_output_or_a)
>  	    {
> -	      prefix = (char *) xmalloc (strlen (linker_output) + 2);
> -	      strcpy (prefix, linker_output);
> +	      prefix = (char *) xmalloc (strlen (linker_output_or_a) + 2);
> +	      strcpy (prefix, linker_output_or_a);
>  	      strcat (prefix, ".");
>  	    }
>  
> @@ -1781,14 +1797,14 @@ cont:
>  	  output_name = XOBFINISH (&env_obstack, char *);
>  
>  	  /* Adjust the dumpbase if the linker output file was seen.  */
> -	  if (linker_output)
> +	  if (linker_output_or_a)
>  	    {
>  	      char *dumpbase
> -		  = (char *) xmalloc (strlen (linker_output)
> +		  = (char *) xmalloc (strlen (linker_output_or_a)
>  				      + sizeof (DUMPBASE_SUFFIX) + 1);
>  	      snprintf (dumpbase,
> -			strlen (linker_output) + sizeof (DUMPBASE_SUFFIX),
> -			"%s.ltrans%u", linker_output, i);
> +			strlen (linker_output_or_a) + sizeof (DUMPBASE_SUFFIX),
> +			"%s.ltrans%u", linker_output_or_a, i);
>  	      argv_ptr[0] = dumpbase;
>  	    }
>  
> diff --git a/gcc/opts.c b/gcc/opts.c
> index 3c53fbe..411652c 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -845,30 +845,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>  	/* We have a DUMP_DIR_NAME, prepend that.  */
>  	opts->x_dump_base_name = opts_concat (opts->x_dump_dir_name,
>  					      opts->x_dump_base_name, NULL);
> -      else if (opts->x_aux_base_name
> -	       && strcmp (opts->x_aux_base_name, HOST_BIT_BUCKET) != 0)
> -	/* AUX_BASE_NAME is set and is not the bit bucket.  If it
> -	   contains a directory component, prepend those directories.
> -	   Typically this places things in the same directory as the
> -	   object file.  */
> -	{
> -	  const char *aux_base;
> -
> -	  base_of_path (opts->x_aux_base_name, &aux_base);
> -	  if (opts->x_aux_base_name != aux_base)
> -	    {
> -	      int dir_len = aux_base - opts->x_aux_base_name;
> -	      char *new_dump_base_name
> -		= XOBNEWVEC (&opts_obstack, char,
> -			     strlen (opts->x_dump_base_name) + dir_len + 1);
> -
> -	      /* Copy directory component from OPTS->X_AUX_BASE_NAME.  */
> -	      memcpy (new_dump_base_name, opts->x_aux_base_name, dir_len);
> -	      /* Append existing OPTS->X_DUMP_BASE_NAME.  */
> -	      strcpy (new_dump_base_name + dir_len, opts->x_dump_base_name);
> -	      opts->x_dump_base_name = new_dump_base_name;
> -	    }
> -	}
>  
>        /* It is definitely prefixed now.  */
>        opts->x_dump_base_name_prefixed = true;
> @@ -2314,17 +2290,6 @@ common_handle_option (struct gcc_options *opts,
>        opts->x_flag_gen_aux_info = 1;
>        break;
>  
> -    case OPT_auxbase_strip:
> -      {
> -	char *tmp = xstrdup (arg);
> -	strip_off_ending (tmp, strlen (tmp));
> -	if (tmp[0])
> -	  opts->x_aux_base_name = tmp;
> -	else
> -	  free (tmp);
> -      }
> -      break;
> -
>      case OPT_d:
>        decode_d_option (arg, opts, loc, dc);
>        break;
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index 059046f..0c6e096 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -796,8 +796,8 @@ print_switch_values (print_switch_fn_type print_fn)
>  	case OPT_o:
>  	case OPT_d:
>  	case OPT_dumpbase:
> +	case OPT_dumpbase_ext:
>  	case OPT_dumpdir:
> -	case OPT_auxbase:
>  	case OPT_quiet:
>  	case OPT_version:
>  	  /* Ignore these.  */
> @@ -1401,18 +1401,44 @@ process_options (void)
>    if (flag_short_enums == 2)
>      flag_short_enums = targetm.default_short_enums ();
>  
> +  if (dump_base_ext)
> +    ;
> +  else if (main_input_filename)
> +    {
> +      const char *name = lbasename (main_input_filename);
> +      const char *ext = strrchr (name, '.');
> +      if (ext)
> +	dump_base_ext = ext;
> +      else
> +	dump_base_ext = "";
> +    }
> +  else
> +    dump_base_ext = "";
> +
>    /* Set aux_base_name if not already set.  */
>    if (aux_base_name)
>      ;
> -  else if (main_input_filename)
> +  else if (dump_base_name)
>      {
> -      char *name = xstrdup (lbasename (main_input_filename));
> +      const char *name = dump_base_name;
> +      int nlen, len;
> +
> +      if (dump_base_ext && (len = strlen (dump_base_ext))
> +	  && (nlen = strlen (name)) && nlen > len
> +	  && strcmp (name + nlen - len, dump_base_ext) == 0)
> +	{
> +	  char *p = xstrdup (name);
> +	  p[nlen - len] = '\0';
> +	  name = (const char *) xrealloc (p, nlen - len + 1);
> +	}
>  
> -      strip_off_ending (name, strlen (name));
>        aux_base_name = name;
>      }
>    else
> -    aux_base_name = "gccaux";
> +    {
> +      if (dump_dir_name)
> +      aux_base_name = "gccaux";
> +    }
>  
>  #ifndef HAVE_isl
>    if (flag_graphite
> 
> 
> 
>
Alexandre Oliva Dec. 12, 2019, 1:13 a.m. UTC | #34
On Dec  9, 2019, Richard Biener <rguenther@suse.de> wrote:

> On Tue, 3 Dec 2019, Alexandre Oliva wrote:

>> I'm considering rejecting command lines that specify both an explicit
>> -dumpdir and -save-temps=cwd, and in the absence of an explicit
>> -dumpdir, arranging for -save-temps=cwd or -save-temps=obj to override
>> what would otherwise be the default -dumpdir.

> Making -save-temps=cwd essentially a short-cut to -save-temps -dumpdir ./
> is fine I guess (we usually do not start to reject previously accepted
> options).

What if -save-temps=* and -dumpdir both set the same underlying aux
output dir, with the latest one in the command line prevailing, rather
than being rejected?

>> gcc -c foo.c -dumpbase foobar && gcc -c bar.c -dumpbase foobar
>> 
>> and
>> 
>> gcc -c foo.c bar.c -dumpbase foobar
>> 
>> The latter will name outputs after foobar-foo and foobar-bar,
>> respectively, whereas the former will overwrite outputs named foobar
>> when compiling bar.c.  Under the proposal to modify %b according to
>> -dump*, even object files would be named after an explicit -dumpbase,
>> when -o is not explicitly specified.

> I think rejecting option combinations that do not make much sense
> or would introduce inconsistencies like this is better than trying
> to invent creative things second-guessing what the user meant.

Hmm, I sense conflicting recommendations here vs the previous block ;-)
A single -dumpbase when compiling multiple sources used to be accepted,
after all, it just overrode aux outputs so only the last one prevailed.


> Hum.  I didn't notice -dumpdir is just a prefix and I wouldn't object
> to make it errorneous if it doesn't specify an acutal directory.

But would you object to retaining the ability to use it as a prefix?

> I also note that neither -dumpdir nor -dumpbase are documented
> in invoke.texi

*nod*

> Not sure if all this means we should document the altered behavior
> or if we should take it as a hint we can alter behavior at will
> (in future) ;)

I suppose we have more leeway in changing what's not even documented.


Thanks again for the feedback!
Alexandre Oliva Dec. 25, 2019, 9:20 a.m. UTC | #35
On Nov  7, 2019, Alexandre Oliva <oliva@adacore.com> wrote:

> compiling a single source idir/ibase.iext:

>   -o odir/obase.oext specified: default -dumpdir odir -dumpbase obase.iext
>   -o obase.oext specified: default -dumpbase obase.iext
>   -o ibase.oext implied: default -dumpbase ibase.iext

> compiling multiple sources named as ibase.iext for linking:

>   -dumpbase [ddir/]dbase specified: make it -dumpbase [ddir/]dbase-ibase.iext
>   -o odir/output specified: default -dumpdir odir -dumpbase output-ibase.iext
>   -o output specified: default -dumpbase output-ibase.iext
>   -o a.out implied: default -dumpbase a.out-ibase.iext

> LTO recompiling:

>   same as above, with each ibase.iext set to ltrans#


> The resulting behavior (aux_base_name, dump_base_name)

> compiling and linking with -o: (outdir/runme-ibase, outdir/runme-ibase.iext)
> ex $CC -o outdir/runme srcdir/foo.c srcdir/x/bar.c
> -> /tmp/temp().o outdir/runme-foo.su outdir/runme-foo.c.#t.original
>  + /tmp/temp().o outdir/runme-bar.su outdir/runme-bar.c.#t.original
>  + outdir/runme

I've implemented this so that, even with a single source file, the
executable name is prepended to the aux outputs in the case above.  This
causes thousands of testsuite failures, as dump files generated by tests
that undergo linking were no longer found: since we compile
foo.ext -o foo.exe, dumps end up named foo-foo.ext.* rather than
foo.ext.*.

Although it doesn't seem too hard to fix the testsuite logic, I'm a
little hesitant at imposing this change onto such a common case that
might hit other tools that use gcc underneath.  I'm considering other
alternatives, such as:

1. do not take the executable name into account when naming aux outputs
of compilations, just like we do today.  this makes aux outputs for the
same input file overwrite each other.

2. do not take the executable name into account when there is a single
input file.  same problem as above

3. do not take the executable name into account when it shares the
basename with an input file; combine executable basename with input name
otherwise.  this makes gcc -o foo[.exe] -g -gsplit-dwarf foo.c output
foo.dwo rather than foo-foo.dwo, which is nice, but then dwo files
compiled for use with foo won't all match foo-*.dwo; it seems more
desirable that they all do

4. same as above, but only when there is only one input file, so that
after adding bar.c to the command above, you'd get foo-foo.dwo and
foo-bar.dwo

5. when there is a single input file, take the basename of the
executable alone, rather than combine it with the basename of the input
file, to name aux outputs, but still use the extension of the input
file, so gcc -o foo foo.c will generate foo.dwo and foo.c.* dumps

I dislike the asymmetry in 3., but I would be happy to implement any
other, including the testsuite change to accommodate foo-foo.* dumps.
Any preferences?  Me, I'm leaning towards 5.
Alexandre Oliva Dec. 26, 2019, 1:41 p.m. UTC | #36
On Dec 25, 2019, Alexandre Oliva <oliva@adacore.com> wrote:

> 3. do not take the executable name into account when it shares the
> basename with an input file; combine executable basename with input name
> otherwise.  this makes gcc -o foo[.exe] -g -gsplit-dwarf foo.c output
> foo.dwo rather than foo-foo.dwo, which is nice, but then dwo files
> compiled for use with foo won't all match foo-*.dwo; it seems more
> desirable that they all do

> 4. same as above, but only when there is only one input file, so that
> after adding bar.c to the command above, you'd get foo-foo.dwo and
> foo-bar.dwo

> Me, I'm leaning towards 5.

And yet I ended up implementing 4 after some more thinking, because the
point was to reduce gratuitous and unnecessary changes.


Here's my first cut at documenting all of the various complex
interactions between -o, -dumpbase, -dumpbase-ext, -dumpdir, and
save-temps=*

Is this too cryptic, to the point of requiring lots of examples to make
it understandable, or is this usable enough?


@@ -1561,6 +1563,89 @@ assembler file in @file{@var{source}.s}, a precompiled header file in
 @file{@var{source}.@var{suffix}.gch}, and all preprocessed C source on
 standard output.
 
+
+@item -dumpbase @var{dumpbase}
+@opindex dumpbase
+This option sets the base name for auxiliary and dump output files.  It
+does not affect the name of the main output file, implied or specified
+with @option{-o}.  It may affect intermediate outputs, however:
+
+@smallexample
+gcc -save-temps -S foo.c&
+@end smallexample
+
+saves the (no longer) temporary preprocessed file in @file{foo.i}, and
+then compiles to the (implied) output file @file{foo.s}, whereas:
+
+@smallexample
+gcc -save-temps -dumpbase save-foo -c foo.c&
+@end smallexample
+
+preprocesses to in @file{save-foo.i}, compiles to @file{save-foo.s} (now
+an intermediate, thus auxiliary output), and then assembles to the
+(implied) output file @file{foo.o}.
+
+If absent, dump and aux files their names from the input file, or from
+the (non-linker) output file, if one is explicitly specified: dump
+output files (e.g. those requested by -fdump-* options) with the input
+name suffix, and aux output files (those requested by other non-dump
+options, e.g.  @code{-save-temps}, @code{-gsplit-dwarf},
+@code{-fcallgraph-info}) without it.  
+
+Similar suffix differentiation of dump and aux outputs can be attained
+for explicitly-given @option{-dumpbase basename.suf} by also specifying
+@option{-dumpbase-ext .suf}.
+
+If @var{dumpbase} is explicitly specified with any directory component,
+@option{-dumpdir} and other @var{dumppfx}-setting @option{-save-temps=*}
+options are ignored, and instead of appending to it, @var{dumpbase}
+fully overrides it.
+
+When @option{-dumpbase} is specified in a command that compiles multiple
+inputs, or that compiles and then links, it may be combined with
+@var{dumppfx}, as specified under @option{-dumpdir}, and each input file
+is then compiled using the combined @var{dumppfx}, and default values
+for @var{dumpbase} and @var{auxdropsuf} computed for each input file.
+
+
+@item -dumpbase-ext @var{auxdropsuf}
+@opindex dumpbase-ext
+When forming the name of an auxiliary (but not a dump) output file, drop
+trailing @var{auxdropsuf} from @var{dumpbase} before appending any
+suffixes.  If not specified, this option defaults to the suffix of the
+input file, including the period.
+
+
+@item -dumpdir @var{dumppfx}
+@opindex dumpdir
+When forming the name of an auxiliary or dump output file, use
+@var{dumppfx} as a prefix.  If it is to be used as a directory name, it
+must end with a directory separator.
+
+It defaults to the location of the output file; options
+@option{-save-temps=cwd} and @option{-save-temps=obj} override this
+default, just like an explicit @option{-dumpdir} option.  In case
+multiple such options are given, the last one prevails.
+
+When compiling from multiple input files, if @option{-dumpbase} is
+specified, @var{dumpbase}, minus a @var{auxdropsuf} suffix, and a dash
+are appended to (or override, if containing any directory components) an
+explicit or defaulted @var{dumppfx}, so that each of the multiple
+compilations gets differently-named aux and dump outputs.
+
+When compiling and then linking from multiple input files, a defaulted
+or explicitly specified @var{dumppfx} also undergoes the @var{dumpbase}-
+transformation above.  If neither @option{-dumpdir} nor
+@option{-dumpbase} are given, the linker output base name, minus the
+executable suffix, plus a dash is appended to the default @var{dumppfx}
+instead.
+
+When compiling and then linking from a single input file, the linker
+output base name will only be appended to the default @var{dumppfx} as
+above if it does not share the base name with the single input file
+name.
+
+
 @item -v
 @opindex v
 Print (on standard error output) the commands executed to run the stages
Richard Biener Jan. 9, 2020, 1:30 p.m. UTC | #37
On Thu, 26 Dec 2019, Alexandre Oliva wrote:

> On Dec 25, 2019, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > 3. do not take the executable name into account when it shares the
> > basename with an input file; combine executable basename with input name
> > otherwise.  this makes gcc -o foo[.exe] -g -gsplit-dwarf foo.c output
> > foo.dwo rather than foo-foo.dwo, which is nice, but then dwo files
> > compiled for use with foo won't all match foo-*.dwo; it seems more
> > desirable that they all do
> 
> > 4. same as above, but only when there is only one input file, so that
> > after adding bar.c to the command above, you'd get foo-foo.dwo and
> > foo-bar.dwo
> 
> > Me, I'm leaning towards 5.
> 
> And yet I ended up implementing 4 after some more thinking, because the
> point was to reduce gratuitous and unnecessary changes.
> 
> 
> Here's my first cut at documenting all of the various complex
> interactions between -o, -dumpbase, -dumpbase-ext, -dumpdir, and
> save-temps=*
> 
> Is this too cryptic, to the point of requiring lots of examples to make
> it understandable, or is this usable enough?

It's understandable and indeed also very helpful.  So I agree to go
forward with this (variant 4).

Did I miss the actual (non-documentation) patch?

Thanks,
Richard.

> 
> @@ -1561,6 +1563,89 @@ assembler file in @file{@var{source}.s}, a precompiled header file in
>  @file{@var{source}.@var{suffix}.gch}, and all preprocessed C source on
>  standard output.
>  
> +
> +@item -dumpbase @var{dumpbase}
> +@opindex dumpbase
> +This option sets the base name for auxiliary and dump output files.  It
> +does not affect the name of the main output file, implied or specified
> +with @option{-o}.  It may affect intermediate outputs, however:
> +
> +@smallexample
> +gcc -save-temps -S foo.c&
> +@end smallexample
> +
> +saves the (no longer) temporary preprocessed file in @file{foo.i}, and
> +then compiles to the (implied) output file @file{foo.s}, whereas:
> +
> +@smallexample
> +gcc -save-temps -dumpbase save-foo -c foo.c&
> +@end smallexample
> +
> +preprocesses to in @file{save-foo.i}, compiles to @file{save-foo.s} (now
> +an intermediate, thus auxiliary output), and then assembles to the
> +(implied) output file @file{foo.o}.
> +
> +If absent, dump and aux files their names from the input file, or from
> +the (non-linker) output file, if one is explicitly specified: dump
> +output files (e.g. those requested by -fdump-* options) with the input
> +name suffix, and aux output files (those requested by other non-dump
> +options, e.g.  @code{-save-temps}, @code{-gsplit-dwarf},
> +@code{-fcallgraph-info}) without it.  
> +
> +Similar suffix differentiation of dump and aux outputs can be attained
> +for explicitly-given @option{-dumpbase basename.suf} by also specifying
> +@option{-dumpbase-ext .suf}.
> +
> +If @var{dumpbase} is explicitly specified with any directory component,
> +@option{-dumpdir} and other @var{dumppfx}-setting @option{-save-temps=*}
> +options are ignored, and instead of appending to it, @var{dumpbase}
> +fully overrides it.
> +
> +When @option{-dumpbase} is specified in a command that compiles multiple
> +inputs, or that compiles and then links, it may be combined with
> +@var{dumppfx}, as specified under @option{-dumpdir}, and each input file
> +is then compiled using the combined @var{dumppfx}, and default values
> +for @var{dumpbase} and @var{auxdropsuf} computed for each input file.
> +
> +
> +@item -dumpbase-ext @var{auxdropsuf}
> +@opindex dumpbase-ext
> +When forming the name of an auxiliary (but not a dump) output file, drop
> +trailing @var{auxdropsuf} from @var{dumpbase} before appending any
> +suffixes.  If not specified, this option defaults to the suffix of the
> +input file, including the period.
> +
> +
> +@item -dumpdir @var{dumppfx}
> +@opindex dumpdir
> +When forming the name of an auxiliary or dump output file, use
> +@var{dumppfx} as a prefix.  If it is to be used as a directory name, it
> +must end with a directory separator.
> +
> +It defaults to the location of the output file; options
> +@option{-save-temps=cwd} and @option{-save-temps=obj} override this
> +default, just like an explicit @option{-dumpdir} option.  In case
> +multiple such options are given, the last one prevails.
> +
> +When compiling from multiple input files, if @option{-dumpbase} is
> +specified, @var{dumpbase}, minus a @var{auxdropsuf} suffix, and a dash
> +are appended to (or override, if containing any directory components) an
> +explicit or defaulted @var{dumppfx}, so that each of the multiple
> +compilations gets differently-named aux and dump outputs.
> +
> +When compiling and then linking from multiple input files, a defaulted
> +or explicitly specified @var{dumppfx} also undergoes the @var{dumpbase}-
> +transformation above.  If neither @option{-dumpdir} nor
> +@option{-dumpbase} are given, the linker output base name, minus the
> +executable suffix, plus a dash is appended to the default @var{dumppfx}
> +instead.
> +
> +When compiling and then linking from a single input file, the linker
> +output base name will only be appended to the default @var{dumppfx} as
> +above if it does not share the base name with the single input file
> +name.
> +
> +
>  @item -v
>  @opindex v
>  Print (on standard error output) the commands executed to run the stages
> 
> 
>
Alexandre Oliva Jan. 9, 2020, 5:35 p.m. UTC | #38
On Jan  9, 2020, Richard Biener <rguenther@suse.de> wrote:

> Did I miss the actual (non-documentation) patch?

No, I didn't post it.  It's kind of big, and only yesterday did I get it
to work as expected and now extensively documented, passing all of the
extensive testsuite I wrote for it.

Alas, some of the latest tweaks to driver and lto-wrapper to update lto
dumps to the new semantics ended up regressing a handful of tests in the
testsuite.  I'm still looking for some simple work-around, and I'm not
very happy with the naming of wpa dumps.

commit c34c1f54a8e4c92a0fca101a0f732c5e29c44643 currently in
aoliva/testme in the git repo is the latest I tested; I pushed other
minor cleanups over that one, but other changes I might make and push
later today might be more disruptive in terms of test results.
Alexandre Oliva Jan. 16, 2020, 10:02 a.m. UTC | #39
On Jan  9, 2020, Alexandre Oliva <oliva@adacore.com> wrote:

> On Jan  9, 2020, Richard Biener <rguenther@suse.de> wrote:
>> Did I miss the actual (non-documentation) patch?

> No, I didn't post it.  It's kind of big, and only yesterday did I get it
> to work as expected and now extensively documented, passing all of the
> extensive testsuite I wrote for it.

Here it is, at last, regstrapped on x86_64-linux-gnu.  Ok to install?


revamp dump and aux output names

This patch simplifies (!!!) the logic governing the naming of dump
files and auxiliary output files in the driver, in the compiler, and
in the LTO wrapper.  No changes are made to the naming of primary
outputs, there are often ways to restore past behavior, and a number
of inconsistencies are fixed.  Some internal options are removed
(-auxbase and -auxbase-strip), sensible existing uses of -dumpdir and
-dumpbase options remain unchanged, additional useful cases are added,
making for what is still admittedly quite complex.  Extensive
documentation and testcases provide numerous examples, from normal to
corner cases.

The most visible changes are:

- aux and dump files now always go in the same directory, that
defaults to the directory of the primary output, but that can be
overridden with -dumpdir, -save-temps=*, or, preserving past behavior,
with a -dumpbase with a directory component.

- driver and compiler now have the same notion of naming of auxiliary
outputs, e.g. .dwo files will no longer be in one location while the
debug info suggests they are elsewhere, and -save-temps and .dwo
auxiliary outputs now go in the same location as .su, .ci and
coverage data, with consistent naming.

- explicitly-specified primary output names guide not only the
location of aux and dump outputs: the output base name is also used in
their base name, as a prefix when also linking (e.g. foo.c bar.c -o
foobar creates foobar-foo.dwo and foobar-bar.dwo with -gsplit-dwarf),
or as the base name instead of the input name (foo.c -c -o whatever.o
creates whatever.su rather than foo.su with -fstack-usage).  The
preference for the input file base name, quite useful for our
testsuite, can be restored with -dumpbase "".

- naming a -dumpbase when compiling multiple sources used to cause
dumps from later compiles to overwrite those of earlier ones; it is
now used as a prefix when compiling multiple sources, like an
executable name above.

- the dumpbase, explicitly specified or computed from output or input
names, now also governs the naming of aux outputs; since aux outputs
usually replaced the suffix from the input name, while dump outputs
append their own additional suffixes, a -dumpbase-ext option is
introduced to enable a chosen suffix to be dropped from dumpbase to
form aux output names.

- LTO dump and aux outputs were quite a mess, sometimes leaking
temporary output names into -save-temps output names, sometimes
conversely generating desirable aux outputs in temporary locations.
They now obey the same logic of compiler aux and dump outputs, landing
in the expected location and taking the linker output name or an
explicit dumpbase overrider into account.

- Naming of -fdump-final-insns outputs now follows the dump file
naming logic for the .gkd files, and the .gk dump files generated in
the second -fcompare-debug compilation get the .gk inserted before the
suffix that -dumpbase-ext drops in aux outputs.


for  gcc/ChangeLog

	* common.opt (aux_base_name): Define.
	(dumpbase, dumpdir): Mark as Driver options.
	(-dumpbase, -dumpdir): Likewise.
	(dumpbase-ext, -dumpbase-ext): New.
	(auxbase, auxbase-strip): Drop.
	* doc/invoke.texi (-dumpbase, -dumpbase-ext, -dumpdir):
	Document.
	(-o): Introduce the notion of primary output, mention it
	influences auxiliary and dump output names as well, add
	examples.
	(-save-temps): Adjust, move examples into -dump*.
	(-save-temps=cwd, -save-temps=obj): Likewise.
	(-fdump-final-insns): Adjust.
	* dwarf2out.c (gen_producer_string): Drop auxbase and
	auxbase_strip; add dumpbase_ext.
	* gcc.c (enum save_temps): Add SAVE_TEMPS_DUMP.
	(save_temps_prefix, save_temps_length): Drop.
	(save_temps_overrides_dumpdir): New.
	(dumpdir, dumpbase, dumpbase_ext): New.
	(dumpdir_length, dumpdir_trailing_dash_added): New.
	(outbase, outbase_length): New.
	(The Specs Language): Introduce %".  Adjust %b and %B.
	(ASM_FINAL_SPEC): Use %b.dwo for an aux output name always.
	Precede object file with %w when it's the primary output.
	(cpp_debug_options): Do not pass on incoming -dumpdir,
	-dumpbase and -dumpbase-ext options; recompute them with
	%:dumps.
	(cc1_options): Drop auxbase with and without compare-debug;
	use cpp_debug_options instead of dumpbase.  Mark asm output
	with %w when it's the primary output.
	(static_spec_functions): Drop %:compare-debug-auxbase-opt and
	%:replace-exception.  Add %:dumps.
	(driver_handle_option): Implement -save-temps=*/-dumpdir
	mutual overriding logic.  Save dumpdir, dumpbase and
	dumpbase-ext options.  Do not save output_file in
	save_temps_prefix.
	(adds_single_suffix_p): New.
	(single_input_file_index): New.
	(process_command): Combine output dir, output base name, and
	dumpbase into dumpdir and outbase.
	(set_collect_gcc_options): Pass a possibly-adjusted -dumpdir.
	(do_spec_1): Optionally dumpdir instead of save_temps_prefix,
	and outbase instead of input_basename in %b, %B and in
	-save-temps aux files.  Handle empty argument %".
	(driver::maybe_run_linker): Adjust dumpdir and auxbase.
	(compare_debug_dump_opt_spec_function): Adjust gkd dump file
	naming.  Spec-quote the computed -fdump-final-insns file name.
	(debug_auxbase_opt): Drop.
	(compare_debug_self_opt_spec_function): Drop auxbase-strip
	computation.
	(compare_debug_auxbase_opt_spec_function): Drop.
	(not_actual_file_p): New.
	(replace_extension_spec_func): Drop.
	(dumps_spec_func): New.
	(convert_white_space): Split-out parts into...
	(quote_string, whitespace_to_convert_p): ... these.  New.
	(quote_spec_char_p, quote_spec, quote_spec_arg): New.
	(driver::finalize): Release and reset new variables; drop
	removed ones.
	* lto-wrapper.c (DUMPBASE_SUFFIX): Drop leading period.
	(debug_objcopy): Use concat.
	(run_gcc): Recognize -save-temps=* as -save-temps too.  Obey
	-dumpdir.  Pass on empty dumpdir and dumpbase with a directory
	component.  Simplify temp file names.
	* opts.c (finish_options): Drop aux base name handling.
	(common_handle_option): Drop auxbase-strip handling.
	* toplev.c (print_switch_values): Drop auxbase, add
	dumpbase-ext.
	(process_options): Derive aux_base_name from dump_base_name
	and dump_base_ext.
	(lang_dependent_init): Compute dump_base_ext along with
	dump_base_name.  Disable stack usage and callgraph-info	during
	lto generation and compare-debug recompilation.

for  gcc/fortran/ChangeLog

	* options.c (gfc_get_option_string): Drop auxbase, add
	dumpbase_ext.

for  gcc/ada/ChangeLog

	* gcc-interface/lang-specs.h: Drop auxbase and auxbase-strip.
	Use %:dumps instead of -dumpbase.  Add %w for implicit .s
	primary output.
	* switch.adb (Is_Internal_GCC_Switch): Recognize dumpdir and
	dumpbase-ext.  Drop auxbase and auxbase-strip.

for  lto-plugin/ChangeLog

	* lto-plugin.c (skip_in_suffix): New.
	(exec_lto_wrapper): Use skip_in_suffix and concat to build
	non-temporary output names.
	(onload): Look for -dumpdir in COLLECT_GCC_OPTIONS, and
	override link_output_name with it.

for  contrib/ChangeLog

	* compare-debug: Adjust for .gkd files named as dump files,
	with the source suffix rather than the object suffix.

for  gcc/testsuite/ChangeLog

	* gcc.misc-tests/outputs.exp: New.
	* gcc.misc-tests/outputs-0.c: New.
	* gcc.misc-tests/outputs-1.c: New.
	* gcc.misc-tests/outputs-2.c: New.
	* lib/gcc-defs.exp (dg-additional-files-options): Pass
	-dumpbase "" when there are additional sources.
	* lib/profopt.exp (profopt-execute): Pass the executable
	suffix with -dumpbase-ext.
	* lib/scandump.exp (dump-base): Mention -dumpbase "" use.
	* lib/scanltranstree.exp: Adjust dump suffix expectation.
	* lib/scanwpaipa.exp: Likewise.
---
 contrib/compare-debug                    |   26 +
 gcc/ada/gcc-interface/lang-specs.h       |   16 -
 gcc/ada/switch.adb                       |    4 
 gcc/common.opt                           |   27 +
 gcc/doc/invoke.texi                      |  385 +++++++++++-
 gcc/dwarf2out.c                          |    3 
 gcc/fortran/options.c                    |    4 
 gcc/gcc.c                                |  938 ++++++++++++++++++++++++------
 gcc/lto-wrapper.c                        |  153 ++---
 gcc/opts.c                               |   35 -
 gcc/testsuite/gcc.misc-tests/outputs-0.c |    1 
 gcc/testsuite/gcc.misc-tests/outputs-1.c |    4 
 gcc/testsuite/gcc.misc-tests/outputs-2.c |    2 
 gcc/testsuite/gcc.misc-tests/outputs.exp |  655 +++++++++++++++++++++
 gcc/testsuite/lib/gcc-defs.exp           |    4 
 gcc/testsuite/lib/profopt.exp            |   10 
 gcc/testsuite/lib/scandump.exp           |    3 
 gcc/testsuite/lib/scanltranstree.exp     |   20 -
 gcc/testsuite/lib/scanwpaipa.exp         |   20 -
 gcc/toplev.c                             |   62 +-
 lto-plugin/lto-plugin.c                  |   87 +++
 21 files changed, 2040 insertions(+), 419 deletions(-)
 create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-0.c
 create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-1.c
 create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-2.c
 create mode 100644 gcc/testsuite/gcc.misc-tests/outputs.exp

diff --git a/contrib/compare-debug b/contrib/compare-debug
index 22870cf..cf80ae3 100755
--- a/contrib/compare-debug
+++ b/contrib/compare-debug
@@ -2,7 +2,7 @@
 
 # Compare stripped copies of two given object files.
 
-# Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation
+# Copyright (C) 2007, 2008, 2009, 2010, 2012, 2020 Free Software Foundation
 # Originally by Alexandre Oliva <aoliva@redhat.com>
 
 # This file is part of GCC.
@@ -183,8 +183,28 @@ $rm "$1.$suf1" "$2.$suf2"
 
 trap "exit $status; exit" 0 1 2 15
 
-if test -f "$1".gkd || test -f "$2".gkd; then
-  if cmp "$1".gkd "$2".gkd; then
+# Replace the suffix in $1 and $2 with .*.gkd, compare them if a
+# single file is found by the globbing.
+base1=`echo "$1" | sed '$s,\.[^.]*$,,'` gkd1=
+for f in "$base1".*.gkd; do
+  if test "x$gkd1" != x; then
+    gkd1=
+    break
+  elif test -f "$f"; then
+    gkd1=$f
+  fi
+done
+base2=`echo "$2" | sed '$s,\.[^.]*$,,'` gkd2=
+for f in "$base2".*.gkd; do
+  if test "x$gkd2" != x; then
+    gkd2=
+    break
+  elif test -f "$f"; then
+    gkd2=$f
+  fi
+done
+if test "x$gkd1" != x || test "x$gkd2" != x; then
+  if cmp "${gkd1-/dev/null}" "${gkd2-/dev/null}"; then
     :
   else
     status=$?
diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
index 374fc1e..5e65cf98 100644
--- a/gcc/ada/gcc-interface/lang-specs.h
+++ b/gcc/ada/gcc-interface/lang-specs.h
@@ -34,17 +34,15 @@
  %{!S:%{!c:%e-c or -S required for Ada}}\
  gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
-    %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b) -gnatd_A} \
-    %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}}} \
-    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} \
+    %{fcompare-debug-second:-gnatd_A} \
+    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
     %{coverage:-fprofile-arcs -ftest-coverage} "
 #if defined(TARGET_VXWORKS_RTP)
    "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
 #endif
    "%{gnatea:-gnatez} %{g*&m*&f*} "
    "%1 %{!S:%{o*:%w%*-gnatO}} \
-    %i %{S:%W{o*}%{!o*:-o %b.s}} \
+    %i %{S:%W{o*}%{!o*:-o %w%b.s}} \
     %{gnatc*|gnats*: -o %j} %{-param*} \
     %{!gnatc*:%{!gnats*:%(invoke_as)}}", 0, 0, 0},
 
@@ -53,9 +51,7 @@
  %{!c:%e-c required for gnat2why}\
  gnat1why %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
-    %{o*:-auxbase-strip %*}%{!o*:-auxbase %b} \
-    %{a} %{d*} \
+    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
     %{gnatea:-gnatez} %{g*&m*&f*} \
     %1 %{o*:%w%*-gnatO} \
     %i \
@@ -66,9 +62,7 @@
  %{!c:%e-c required for gnat2scil}\
  gnat1scil %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
-    %{o*:-auxbase-strip %*}%{!o*:-auxbase %b} \
-    %{a} %{d*} \
+    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
     %{gnatea:-gnatez} %{g*&m*&f*} \
     %1 %{o*:%w%*-gnatO} \
     %i \
diff --git a/gcc/ada/switch.adb b/gcc/ada/switch.adb
index 7cdaa196..b6f4e00 100644
--- a/gcc/ada/switch.adb
+++ b/gcc/ada/switch.adb
@@ -163,9 +163,9 @@ package body Switch is
       return Is_Switch (Switch_Chars)
         and then
           (Switch_Chars (First .. Last) = "-param"        or else
+           Switch_Chars (First .. Last) = "dumpdir"       or else
            Switch_Chars (First .. Last) = "dumpbase"      or else
-           Switch_Chars (First .. Last) = "auxbase-strip" or else
-           Switch_Chars (First .. Last) = "auxbase");
+           Switch_Chars (First .. Last) = "dumpbase-ext");
    end Is_Internal_GCC_Switch;
 
    ---------------
diff --git a/gcc/common.opt b/gcc/common.opt
index e9b29fb..9c299cc 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -188,6 +188,12 @@ const char *main_input_basename
 Variable
 int main_input_baselength
 
+; The base name used for auxiliary output files.
+; dump_base_name minus dump_base_ext.
+
+Variable
+const char *aux_base_name
+
 ; Which options have been printed by --help.
 Variable
 char *help_printed
@@ -252,10 +258,13 @@ Common Separate Alias(d)
 Common Joined Alias(d)
 
 -dumpbase
-Common Separate Alias(dumpbase)
+Driver Common Separate Alias(dumpbase)
+
+-dumpbase-ext
+Driver Common Separate Alias(dumpbase-ext)
 
 -dumpdir
-Common Separate Alias(dumpdir)
+Driver Common Separate Alias(dumpdir)
 
 -entry
 Driver Separate Alias(e)
@@ -840,12 +849,6 @@ Common Separate Var(aux_info_file_name)
 aux-info=
 Common Joined Alias(aux-info)
 
-auxbase
-Common Separate RejectDriver Var(aux_base_name)
-
-auxbase-strip
-Common Separate RejectDriver
-
 coverage
 Driver
 
@@ -857,11 +860,15 @@ Common Joined
 -d<letters>	Enable dumps from specific passes of the compiler.
 
 dumpbase
-Common Separate Var(dump_base_name)
+Driver Common Separate Var(dump_base_name)
 -dumpbase <file>	Set the file basename to be used for dumps.
 
+dumpbase-ext
+Driver Common Separate Var(dump_base_ext)
+-dumpbase-ext .<ext>    Drop a trailing .<ext> from the dump basename to name auxiliary output files.
+
 dumpdir
-Common Separate Var(dump_dir_name)
+Driver Common Separate Var(dump_dir_name)
 -dumpdir <dir>	Set the directory name to be used for dumps.
 
 dumpmachine
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f2c805c..c679cdf 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -184,7 +184,9 @@ in the following sections.
 @table @emph
 @item Overall Options
 @xref{Overall Options,,Options Controlling the Kind of Output}.
-@gccoptlist{-c  -S  -E  -o @var{file}  -x @var{language}  @gol
+@gccoptlist{-c  -S  -E  -o @var{file} @gol
+-dumpbase @var{dumpbase}  -dumpbase-ext @var{auxdropsuf} @gol
+-dumpdir @var{dumppfx}  -x @var{language}  @gol
 -v  -###  --help@r{[}=@var{class}@r{[},@dots{}@r{]]}  --target-help  --version @gol
 -pass-exit-codes  -pipe  -specs=@var{file}  -wrapper  @gol
 @@@var{file}  -ffile-prefix-map=@var{old}=@var{new}  @gol
@@ -1552,9 +1554,9 @@ Input files that don't require preprocessing are ignored.
 @cindex output file option
 @item -o @var{file}
 @opindex o
-Place output in file @var{file}.  This applies to whatever
-sort of output is being produced, whether it be an executable file,
-an object file, an assembler file or preprocessed C code.
+Place the primary output in file @var{file}.  This applies to whatever
+sort of output is being produced, whether it be an executable file, an
+object file, an assembler file or preprocessed C code.
 
 If @option{-o} is not specified, the default is to put an executable
 file in @file{a.out}, the object file for
@@ -1563,6 +1565,314 @@ assembler file in @file{@var{source}.s}, a precompiled header file in
 @file{@var{source}.@var{suffix}.gch}, and all preprocessed C source on
 standard output.
 
+Though @option{-o} names only the primary output, it also affects the
+naming of auxiliary and dump outputs.  See the examples below.  Unless
+overridden, both auxiliary outputs and dump outputs are placed in the
+same directory as the primary output.  In auxiliary outputs, the suffix
+of the input file is replaced with that of the auxiliary output file
+type; in dump outputs, the suffix of the dump file is appended to the
+input file suffix.  In compilation commands, the base name of both
+auxiliary and dump outputs is that of the primary output; in compile and
+link commands, the primary output name, minus the executable suffix, is
+combined with the input file name.  If both share the same base name,
+disregarding the suffix, the result of the combination is that base
+name, otherwise, they are concatenated, separated by a dash.
+
+@smallexample
+gcc -c foo.c ...
+@end smallexample
+
+will use @file{foo.o} as the primary output, and place aux outputs and
+dumps next to it, e.g., aux file @file{foo.dwo} for
+@option{-gsplit-dwarf}, and dump file @file{foo.c.???r.final} for
+@option{-fdump-rtl-final}.
+
+If a non-linker output file is explicitly specified, aux and dump files
+by default take the same base name:
+
+@smallexample
+gcc -c foo.c -o dir/foobar.o ...
+@end smallexample
+
+will name aux outputs @file{dir/foobar.*} and dump outputs
+@file{dir/foobar.c.*}.
+
+A linker output will instead prefix aux and dump outputs:
+
+@smallexample
+gcc foo.c bar.c -o dir/foobar ...
+@end smallexample
+
+will generally name aux outputs @file{dir/foobar-foo.*} and
+@file{dir/foobar-bar.*}, and dump outputs @file{dir/foobar-foo.c.*} and
+@file{dir/foobar-bar.c.*}.
+
+The one exception to the above is when the executable shares the base
+name with the single input:
+
+@smallexample
+gcc foo.c -o dir/foo ...
+@end smallexample
+
+in which case aux outputs are named @file{dir/foo.*} and dump outputs
+named @file{dir/foo.c.*}.
+
+The location and the names of auxiliary and dump outputs can be adjusted
+by the options @option{-dumpbase}, @option{-dumpbase-ext},
+@option{-dumpdir}, @option{-save-temps=cwd}, and
+@option{-save-temps=obj}.
+
+
+@item -dumpbase @var{dumpbase}
+@opindex dumpbase
+This option sets the base name for auxiliary and dump output files.  It
+does not affect the name of the primary output file.  Intermediate
+outputs, when preserved, are not regarded as primary outputs, but as
+auxiliary outputs:
+
+@smallexample
+gcc -save-temps -S foo.c
+@end smallexample
+
+saves the (no longer) temporary preprocessed file in @file{foo.i}, and
+then compiles to the (implied) output file @file{foo.s}, whereas:
+
+@smallexample
+gcc -save-temps -dumpbase save-foo -c foo.c
+@end smallexample
+
+preprocesses to in @file{save-foo.i}, compiles to @file{save-foo.s} (now
+an intermediate, thus auxiliary output), and then assembles to the
+(implied) output file @file{foo.o}.
+
+Absent this option, dump and aux files take their names from the input
+file, or from the (non-linker) output file, if one is explicitly
+specified: dump output files (e.g. those requested by @option{-fdump-*}
+options) with the input name suffix, and aux output files (those
+requested by other non-dump options, e.g. @code{-save-temps},
+@code{-gsplit-dwarf}, @code{-fcallgraph-info}) without it.
+
+Similar suffix differentiation of dump and aux outputs can be attained
+for explicitly-given @option{-dumpbase basename.suf} by also specifying
+@option{-dumpbase-ext .suf}.
+
+If @var{dumpbase} is explicitly specified with any directory component,
+any @var{dumppfx} specification (e.g. @option{-dumpdir} or
+@option{-save-temps=*}) is ignored, and instead of appending to it,
+@var{dumpbase} fully overrides it:
+
+@smallexample
+gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
+  -dumpdir pfx- -save-temps=cwd ...
+@end smallexample
+
+creates auxiliary and dump outputs named @file{alt/foo.*}, disregarding
+@file{dir/} in @option{-o}, the @file{./} prefix implied by
+@option{-save-temps=cwd}, and @file{pfx-} in @option{-dumpdir}.
+
+When @option{-dumpbase} is specified in a command that compiles multiple
+inputs, or that compiles and then links, it may be combined with
+@var{dumppfx}, as specified under @option{-dumpdir}.  Then, each input
+file is compiled using the combined @var{dumppfx}, and default values
+for @var{dumpbase} and @var{auxdropsuf} are computed for each input
+file:
+
+@smallexample
+gcc foo.c bar.c -c -dumpbase main ...
+@end smallexample
+
+creates @file{foo.o} and @file{bar.o} as primary outputs, and avoids
+overwriting the auxiliary and dump outputs by using the @var{dumpbase}
+as a prefix, creating auxiliary and dump outputs named @file{main-foo.*}
+and @file{main-bar.*}.
+
+An empty string specified as @var{dumpbase} avoids the influence of the
+output basename in the naming of auxiliary and dump outputs during
+compilation, computing default values :
+
+@smallexample
+gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
+@end smallexample
+
+will name aux outputs @file{dir/foo.*} and dump outputs
+@file{dir/foo.c.*}.  Note how their basenames are taken from the input
+name, but the directory still defaults to that of the output.
+
+The empty-string dumpbase does not prevent the use of the output
+basename for outputs during linking:
+
+@smallexample
+gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
+@end smallexample
+
+The compilation of the source files will name auxiliary outputs
+@file{dir/foo.*} and @file{dir/bar.*}, and dump outputs
+@file{dir/foo.c.*} and @file{dir/bar.c.*}.  LTO recompilation during
+linking will use @file{dir/foobar.} as the prefix for dumps and
+auxiliary files.
+
+
+@item -dumpbase-ext @var{auxdropsuf}
+@opindex dumpbase-ext
+When forming the name of an auxiliary (but not a dump) output file, drop
+trailing @var{auxdropsuf} from @var{dumpbase} before appending any
+suffixes.  If not specified, this option defaults to the suffix of a
+default @var{dumpbase}, i.e., the suffix of the input file when
+@option{-dumpbase} is not present in the command line, or @var{dumpbase}
+is combined with @var{dumppfx}.
+
+@smallexample
+gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
+@end smallexample
+
+creates @file{dir/foo.o} as the main output, and generates auxiliary
+outputs in @file{dir/x-foo.*}, taking the location of the primary
+output, and dropping the @file{.c} suffix from the @var{dumpbase}.  Dump
+outputs retain the suffix: @file{dir/x-foo.c.*}.
+
+This option is disregarded if it does not match the suffix of a
+specified @var{dumpbase}, except as an alternative to the executable
+suffix when appending the linker output base name to @var{dumppfx}, as
+specified below:
+
+@smallexample
+gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
+@end smallexample
+
+creates @file{main.out} as the primary output, and avoids overwriting
+the auxiliary and dump outputs by using the executable name minus
+@var{auxdropsuf} as a prefix, creating auxiliary outputs named
+@file{main-foo.*} and @file{main-bar.*} and dump outputs named
+@file{main-foo.c.*} and @file{main-bar.c.*}.
+
+
+@item -dumpdir @var{dumppfx}
+@opindex dumpdir
+When forming the name of an auxiliary or dump output file, use
+@var{dumppfx} as a prefix:
+
+@smallexample
+gcc -dumpdir pfx- -c foo.c ...
+@end smallexample
+
+creates @file{foo.o} as the primary output, and auxiliary outputs named
+@file{pfx-foo.*}, combining the given @var{dumppfx} with the default
+@var{dumpbase} derived from the default primary output, derived in turn
+from the input name.  Dump outputs also take the input name suffix:
+@file{pfx-foo.c.*}.
+
+If @var{dumppfx} is to be used as a directory name, it must end with a
+directory separator:
+
+@smallexample
+gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
+@end smallexample
+
+creates @file{obj/bar.o} as the primary output, and auxiliary outputs
+named @file{dir/bar.*}, combining the given @var{dumppfx} with the
+default @var{dumpbase} derived from the primary output name.  Dump
+outputs also take the input name suffix: @file{dir/bar.c.*}.
+
+It defaults to the location of the output file; options
+@option{-save-temps=cwd} and @option{-save-temps=obj} override this
+default, just like an explicit @option{-dumpdir} option.  In case
+multiple such options are given, the last one prevails:
+
+@smallexample
+gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
+@end smallexample
+
+outputs @file{foo.o}, with auxiliary outputs named @file{foo.*} because
+@option{-save-temps=*} overrides the @var{dumppfx} given by the earlier
+@option{-dumpdir} option.  It does not matter that @option{=obj} is the
+default for @option{-save-temps}, nor that the output directory is
+implicitly the current directory.  Dump outputs are named
+@file{foo.c.*}.
+
+When compiling from multiple input files, if @option{-dumpbase} is
+specified, @var{dumpbase}, minus a @var{auxdropsuf} suffix, and a dash
+are appended to (or override, if containing any directory components) an
+explicit or defaulted @var{dumppfx}, so that each of the multiple
+compilations gets differently-named aux and dump outputs.
+
+@smallexample
+gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
+@end smallexample
+
+outputs auxiliary dumps to @file{dir/pfx-main-foo.*} and
+@file{dir/pfx-main-bar.*}, appending @var{dumpbase}- to @var{dumppfx}.
+Dump outputs retain the input file suffix: @file{dir/pfx-main-foo.c.*}
+and @file{dir/pfx-main-bar.c.*}, respectively.  Contrast with the
+single-input compilation:
+
+@smallexample
+gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
+@end smallexample
+
+that, applying @option{-dumpbase} to a single source, does not compute
+and append a separate @var{dumpbase} per input file.  Its auxiliary and
+dump outputs go in @file{dir/pfx-main.*}.
+
+When compiling and then linking from multiple input files, a defaulted
+or explicitly specified @var{dumppfx} also undergoes the @var{dumpbase}-
+transformation above (e.g. the compilation of @file{foo.c} and
+@file{bar.c} above, but without @option{-c}).  If neither
+@option{-dumpdir} nor @option{-dumpbase} are given, the linker output
+base name, minus @var{auxdropsuf}, if specified, or the executable
+suffix otherwise, plus a dash is appended to the default @var{dumppfx}
+instead.  Note, however, that unlike earlier cases of linking:
+
+@smallexample
+gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
+@end smallexample
+
+does not append the output name @file{main} to @var{dumppfx}, because
+@option{-dumpdir} is explicitly specified.  The goal is that the
+explicitly-specified @var{dumppfx} may contain the specified output name
+as part of the prefix, if desired; only an explicitly-specified
+@option{-dumpbase} would be combined with it, in order to avoid simply
+discarding a meaningful option.
+
+When compiling and then linking from a single input file, the linker
+output base name will only be appended to the default @var{dumppfx} as
+above if it does not share the base name with the single input file
+name.  This has been covered in single-input linking cases above, but
+not with an explicit @option{-dumpdir} that inhibits the combination,
+even if overridden by @option{-save-temps=*}:
+
+@smallexample
+gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
+@end smallexample
+
+Auxiliary outputs are named @file{foo.*}, and dump outputs
+@file{foo.c.*}, in the current working directory as ultimately requested
+by @option{-save-temps=cwd}.
+
+Summing it all up for an intuitive though slightly imprecise data flow:
+the primary output name is broken into a directory part and a basename
+part; @var{dumppfx} is set to the former, unless overridden by
+@option{-dumpdir} or @option{-save-temps=*}, and @var{dumpbase} is set
+to the latter, unless overriden by @option{-dumpbase}.  If there are
+multiple inputs or linking, this @var{dumpbase} may be combined with
+@var{dumppfx} and taken from each input file.  Auxiliary output names
+for each input are formed by combining @var{dumppfx}, @var{dumpbase}
+minus suffix, and the auxiliary output suffix; dump output names are
+only different in that the suffix from @var{dumpbase} is retained.
+
+When it comes to auxiliary and dump outputs created during LTO
+recompilation, a combination of @var{dumppfx} and @var{dumpbase}, as
+given or as derived from the linker output name but not from inputs,
+even in cases in which this combination would not otherwise be used as
+such, is passed down with a trailing period replacing the compiler-added
+dash, if any, as a @option{-dumpdir} option to @command{lto-wrapper};
+being involved in linking, this program does not normally get any
+@option{-dumpbase} and @option{-dumpbase-ext}, and it ignores them.
+
+When running sub-compilers, @command{lto-wrapper} appends LTO stage
+names to the received @var{dumppfx}, ensures it contains a directory
+component so that it overrides any @option{-dumpdir}, and passes that as
+@option{-dumpbase} to sub-compilers.
+
 @item -v
 @opindex v
 Print (on standard error output) the commands executed to run the stages
@@ -15644,54 +15954,28 @@ computing CRC32).
 The @var{string} should be different for every file you compile.
 
 @item -save-temps
-@itemx -save-temps=cwd
 @opindex save-temps
-Store the usual ``temporary'' intermediate files permanently; place them
-in the current directory and name them based on the source file.  Thus,
-compiling @file{foo.c} with @option{-c -save-temps} produces files
-@file{foo.i} and @file{foo.s}, as well as @file{foo.o}.  This creates a
-preprocessed @file{foo.i} output file even though the compiler now
-normally uses an integrated preprocessor.
+Store the usual ``temporary'' intermediate files permanently; name them
+as auxiliary output files, as specified described under
+@option{-dumpbase} and @option{-dumpdir}.
 
 When used in combination with the @option{-x} command-line option,
-@option{-save-temps} is sensible enough to avoid over writing an
+@option{-save-temps} is sensible enough to avoid overwriting an
 input source file with the same extension as an intermediate file.
 The corresponding intermediate file may be obtained by renaming the
 source file before using @option{-save-temps}.
 
-If you invoke GCC in parallel, compiling several different source
-files that share a common base name in different subdirectories or the
-same source file compiled for multiple output destinations, it is
-likely that the different parallel compilers will interfere with each
-other, and overwrite the temporary files.  For instance:
-
-@smallexample
-gcc -save-temps -o outdir1/foo.o indir1/foo.c&
-gcc -save-temps -o outdir2/foo.o indir2/foo.c&
-@end smallexample
-
-may result in @file{foo.i} and @file{foo.o} being written to
-simultaneously by both compilers.
+@item -save-temps=cwd
+@opindex save-temps=cwd
+Equivalent to @option{-save-temps -dumpdir ./}.
 
 @item -save-temps=obj
 @opindex save-temps=obj
-Store the usual ``temporary'' intermediate files permanently.  If the
-@option{-o} option is used, the temporary files are based on the
-object file.  If the @option{-o} option is not used, the
-@option{-save-temps=obj} switch behaves like @option{-save-temps}.
-
-For example:
-
-@smallexample
-gcc -save-temps=obj -c foo.c
-gcc -save-temps=obj -c bar.c -o dir/xbar.o
-gcc -save-temps=obj foobar.c -o dir2/yfoobar
-@end smallexample
-
-@noindent
-creates @file{foo.i}, @file{foo.s}, @file{dir/xbar.i},
-@file{dir/xbar.s}, @file{dir2/yfoobar.i}, @file{dir2/yfoobar.s}, and
-@file{dir2/yfoobar.o}.
+Equivalent to @option{-save-temps -dumpdir @file{outdir/}}, where
+@file{outdir/} is the directory of the output file specified after the
+@option{-o} option, including any directory separators.  If the
+@option{-o} option is not used, the @option{-save-temps=obj} switch
+behaves like @option{-save-temps=cwd}.
 
 @item -time@r{[}=@var{file}@r{]}
 @opindex time
@@ -15728,7 +16012,7 @@ can later tell what file was being compiled, and with which options.
 Dump the final internal representation (RTL) to @var{file}.  If the
 optional argument is omitted (or if @var{file} is @code{.}), the name
 of the dump file is determined by appending @code{.gkd} to the
-compilation output file name.
+dump base name, see @option{-dumpbase}.
 
 @item -fcompare-debug@r{[}=@var{opts}@r{]}
 @opindex fcompare-debug
@@ -29903,17 +30187,24 @@ together or combine them with constant text in a single argument.
 @item %%
 Substitute one @samp{%} into the program name or argument.
 
+@item %"
+Substitute an empty argument.
+
 @item %i
 Substitute the name of the input file being processed.
 
 @item %b
-Substitute the basename of the input file being processed.
-This is the substring up to (and not including) the last period
-and not including the directory.
+Substitute the basename for outputs related with the input file being
+processed.  This is often the substring up to (and not including) the
+last period and not including the directory but, unless %w is active, it
+expands to the basename for auxiliary outputs, which may be influenced
+by an explicit output name, and by various other options that control
+how auxiliary outputs are named.
 
 @item %B
 This is the same as @samp{%b}, but include the file suffix (text after
-the last period).
+the last period).  Without %w, it expands to the basename for dump
+outputs.
 
 @item %d
 Marks the argument containing or following the @samp{%d} as a
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 70b3fad..1882116 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -24333,9 +24333,8 @@ gen_producer_string (void)
       case OPT_o:
       case OPT_d:
       case OPT_dumpbase:
+      case OPT_dumpbase_ext:
       case OPT_dumpdir:
-      case OPT_auxbase:
-      case OPT_auxbase_strip:
       case OPT_quiet:
       case OPT_version:
       case OPT_v:
diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
index 4cc8a90..d844fa9 100644
--- a/gcc/fortran/options.c
+++ b/gcc/fortran/options.c
@@ -838,8 +838,8 @@ gfc_get_option_string (void)
         case OPT_o:
         case OPT_d:
         case OPT_dumpbase:
+        case OPT_dumpbase_ext:
         case OPT_dumpdir:
-        case OPT_auxbase:
         case OPT_quiet:
         case OPT_version:
         case OPT_fintrinsic_modules_path:
@@ -864,8 +864,8 @@ gfc_get_option_string (void)
         case OPT_o:
         case OPT_d:
         case OPT_dumpbase:
+        case OPT_dumpbase_ext:
         case OPT_dumpdir:
-        case OPT_auxbase:
         case OPT_quiet:
         case OPT_version:
         case OPT_fintrinsic_modules_path:
diff --git a/gcc/gcc.c b/gcc/gcc.c
index effc384f..cc04a20 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -270,12 +270,36 @@ static const char *target_sysroot_hdrs_suffix = 0;
 static enum save_temps {
   SAVE_TEMPS_NONE,		/* no -save-temps */
   SAVE_TEMPS_CWD,		/* -save-temps in current directory */
+  SAVE_TEMPS_DUMP,              /* -save-temps in dumpdir */
   SAVE_TEMPS_OBJ		/* -save-temps in object directory */
 } save_temps_flag;
 
-/* Output file to use to get the object directory for -save-temps=obj  */
-static char *save_temps_prefix = 0;
-static size_t save_temps_length = 0;
+/* Set this iff the dumppfx implied by a -save-temps=* option is to
+   override a -dumpdir option, if any.  */
+static bool save_temps_overrides_dumpdir = false;
+
+/* -dumpdir, -dumpbase and -dumpbase-ext flags passed in, possibly
+   rearranged as they are to be passed down, e.g., dumpbase and
+   dumpbase_ext may be cleared if integrated with dumpdir or
+   dropped.  */
+static char *dumpdir, *dumpbase, *dumpbase_ext;
+
+/* Usually the length of the string in dumpdir.  However, during
+   linking, it may be shortened to omit a driver-added trailing dash,
+   by then replaced with a trailing period, that is still to be passed
+   to sub-processes in -dumpdir, but not to be generally used in spec
+   filename expansions.  See maybe_run_linker.  */
+static size_t dumpdir_length = 0;
+
+/* Set if the last character in dumpdir is (or was) a dash that the
+   driver added to dumpdir after dumpbase or linker output name.  */
+static bool dumpdir_trailing_dash_added = false;
+
+/* Basename of dump and aux outputs, computed from dumpbase (given or
+   derived from output name), to override input_basename in non-%w %b
+   et al.  */
+static char *outbase;
+static size_t outbase_length = 0;
 
 /* The compiler version.  */
 
@@ -402,13 +426,16 @@ static const char *find_plugindir_spec_function (int, const char **);
 static const char *print_asm_header_spec_function (int, const char **);
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
-static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
 static const char *pass_through_libs_spec_func (int, const char **);
-static const char *replace_extension_spec_func (int, const char **);
+static const char *dumps_spec_func (int, const char **);
 static const char *greater_than_spec_func (int, const char **);
 static const char *debug_level_greater_than_spec_func (int, const char **);
 static const char *find_fortran_preinclude_file (int, const char **);
 static char *convert_white_space (char *);
+static char *quote_spec (char *);
+static char *quote_spec_arg (char *);
+static bool not_actual_file_p (const char *);
+
 
 /* The Specs Language
 
@@ -426,12 +453,19 @@ expanding these sequences; therefore, you can concatenate them together
 or with constant text in a single argument.
 
  %%	substitute one % into the program name or argument.
+ %"     substitute an empty argument.
  %i     substitute the name of the input file being processed.
- %b     substitute the basename of the input file being processed.
-	This is the substring up to (and not including) the last period
-	and not including the directory unless -save-temps was specified
-	to put temporaries in a different location.
- %B	same as %b, but include the file suffix (text after the last period).
+ %b     substitute the basename for outputs related with the input file
+	being processed.  This is often a substring of the input file name,
+	up to (and not including) the last period but, unless %w is active,
+	it is affected by the directory selected by -save-temps=*, by
+	-dumpdir, and, in case of multiple compilations, even by -dumpbase
+	and -dumpbase-ext and, in case of linking, by the linker output
+	name.  When %w is active, it derives the main output name only from
+	the input file base name; when it is not, it names aux/dump output
+	file.
+ %B	same as %b, but include the input file suffix (text after the last
+	period).
  %gSUFFIX
 	substitute a file name that has suffix SUFFIX and is chosen
 	once per compilation, and mark the argument a la %d.  To reduce
@@ -641,10 +675,10 @@ proper position among the other output files.  */
 #define ASM_FINAL_SPEC \
   "%{gsplit-dwarf: \n\
        objcopy --extract-dwo \
-	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
-	 %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
+	 %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
+	 %b.dwo \n\
        objcopy --strip-dwo \
-	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+	 %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
     }"
 #endif
 
@@ -1139,22 +1173,20 @@ static const char *cpp_options =
 
 /* This contains cpp options which are not passed when the preprocessor
    output will be used by another program.  */
-static const char *cpp_debug_options = "%{d*}";
+static const char *cpp_debug_options = "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps()";
 
 /* NB: This is shared amongst all front-ends, except for Ada.  */
 static const char *cc1_options =
 "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
  %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
- %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
- %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
- %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
+ %1 %{!Q:-quiet} %(cpp_debug_options) %{m*} %{aux-info*}\
  %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
  %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
  %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
  %{-target-help:--target-help}\
  %{-version:--version}\
  %{-help=*:--help=%*}\
- %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
+ %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}}\
  %{fsyntax-only:-o %j} %{-param*}\
  %{coverage:-fprofile-arcs -ftest-coverage}\
  %{fprofile-arcs|fprofile-generate*|coverage:\
@@ -1642,9 +1674,8 @@ static const struct spec_function static_spec_functions[] =
   { "print-asm-header",		print_asm_header_spec_function },
   { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
-  { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
   { "pass-through-libs",	pass_through_libs_spec_func },
-  { "replace-extension",	replace_extension_spec_func },
+  { "dumps",                    dumps_spec_func },
   { "gt",			greater_than_spec_func },
   { "debug-level-gt",		debug_level_greater_than_spec_func },
   { "fortran-preinclude-file",	find_fortran_preinclude_file},
@@ -4140,7 +4171,8 @@ driver_handle_option (struct gcc_options *opts,
       return true;
 
     case OPT_save_temps:
-      save_temps_flag = SAVE_TEMPS_CWD;
+      if (!save_temps_flag)
+	save_temps_flag = SAVE_TEMPS_DUMP;
       validated = true;
       break;
 
@@ -4153,6 +4185,23 @@ driver_handle_option (struct gcc_options *opts,
       else
 	fatal_error (input_location, "%qs is an unknown %<-save-temps%> option",
 		     decoded->orig_option_with_args_text);
+      save_temps_overrides_dumpdir = true;
+      break;
+
+    case OPT_dumpdir:
+      free (dumpdir);
+      dumpdir = xstrdup (arg);
+      save_temps_overrides_dumpdir = false;
+      break;
+
+    case OPT_dumpbase:
+      free (dumpbase);
+      dumpbase = xstrdup (arg);
+      break;
+
+    case OPT_dumpbase_ext:
+      free (dumpbase_ext);
+      dumpbase_ext = xstrdup (arg);
       break;
 
     case OPT_no_canonical_prefixes:
@@ -4259,8 +4308,6 @@ driver_handle_option (struct gcc_options *opts,
       arg = convert_filename (arg, ! have_c, 0);
 #endif
       output_file = arg;
-      /* Save the output name in case -save-temps=obj was used.  */
-      save_temps_prefix = xstrdup (arg);
       /* On some systems, ld cannot handle "-o" without a space.  So
 	 split the option from its argument.  */
       save_switch ("-o", 1, &arg, validated, true);
@@ -4303,6 +4350,19 @@ driver_handle_option (struct gcc_options *opts,
   return true;
 }
 
+/* Return true if F2 is F1 followed by a single suffix, i.e., by a
+   period and additional characters other than a period.  */
+
+static inline bool
+adds_single_suffix_p (const char *f2, const char *f1)
+{
+  size_t len = strlen (f1);
+
+  return (strncmp (f1, f2, len) == 0
+	  && f2[len] == '.'
+	  && strchr (f2 + len + 1, '.') == NULL);
+}
+
 /* Put the driver's standard set of option handlers in *HANDLERS.  */
 
 static void
@@ -4319,6 +4379,32 @@ set_option_handlers (struct cl_option_handlers *handlers)
   handlers->handlers[2].mask = CL_TARGET;
 }
 
+
+/* Return the index into infiles for the single non-library
+   non-lto-wpa input file, -1 if there isn't any, or -2 if there is
+   more than one.  */
+static inline int
+single_input_file_index ()
+{
+  int ret = -1;
+
+  for (int i = 0; i < n_infiles; i++)
+    {
+      if (infiles[i].language
+	  && (infiles[i].language[0] == '*'
+	      || (flag_wpa
+		  && strcmp (infiles[i].language, "lto") == 0)))
+	continue;
+
+      if (ret != -1)
+	return -2;
+
+      ret = i;
+    }
+
+  return ret;
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
@@ -4631,23 +4717,371 @@ process_command (unsigned int decoded_options_count,
   if (output_file != NULL && output_file[0] == '\0')
     fatal_error (input_location, "output filename may not be empty");
 
+  /* -dumpdir and -save-temps=* both specify the location of aux/dump
+     outputs; the one that appears last prevails.  When compiling
+     multiple sources, an explicit dumpbase (minus -ext) may be
+     combined with an explicit or implicit dumpdir, whereas when
+     linking, a specified or implied link output name (minus
+     extension) may be combined with a prevailing -save-temps=* or an
+     otherwise implied dumpdir, but not override a prevailing
+     -dumpdir.  Primary outputs (e.g., linker output when linking
+     without -o, or .i, .s or .o outputs when processing multiple
+     inputs with -E, -S or -c, respectively) are NOT affected by these
+     -save-temps=/-dump* options, always landing in the current
+     directory and with the same basename as the input when an output
+     name is not given, but when they're intermediate outputs, they
+     are named like other aux outputs, so the options affect their
+     location and name.
+
+     Here are some examples.  There are several more in the
+     documentation of -o and -dump*, and some quite exhaustive tests
+     in gcc.misc-tests/outputs.exp.
+
+     When compiling any number of sources, no -dump* nor
+     -save-temps=*, all outputs in cwd without prefix:
+
+     # gcc -c b.c -gsplit-dwarf
+     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
+
+     # gcc -c b.c d.c -gsplit-dwarf
+     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
+     && cc1 [-dumpdir ./] -dumpbase d.c -dumpbase-ext .c # d.o d.dwo
+
+     When compiling and linking, no -dump* nor -save-temps=*, .o
+     outputs are temporary, aux outputs land in the dir of the output,
+     prefixed with the basename of the linker output:
+
+     # gcc b.c d.c -o ab -gsplit-dwarf
+     -> cc1 -dumpdir ab- -dumpbase b.c -dumpbase-ext .c # ab-b.dwo
+     && cc1 -dumpdir ab- -dumpbase d.c -dumpbase-ext .c # ab-d.dwo
+     && link ... -o ab
+
+     # gcc b.c d.c [-o a.out] -gsplit-dwarf
+     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.dwo
+     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.dwo
+     && link ... [-o a.out]
+
+     When compiling and linking, a prevailing -dumpdir fully overrides
+     the prefix of aux outputs given by the output name:
+
+     # gcc -dumpdir f b.c d.c -gsplit-dwarf [-o [dir/]whatever]
+     -> cc1 -dumpdir f -dumpbase b.c -dumpbase-ext .c # fb.dwo
+     && cc1 -dumpdir f -dumpbase d.c -dumpbase-ext .c # fd.dwo
+     && link ... [-o whatever]
+
+     When compiling multiple inputs, an explicit -dumpbase is combined
+     with -dumpdir, affecting aux outputs, but not the .o outputs:
+
+     # gcc -dumpdir f -dumpbase g- b.c d.c -gsplit-dwarf -c
+     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # b.o fg-b.dwo
+     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # d.o fg-d.dwo
+
+     When compiling and linking with -save-temps, the .o outputs that
+     would have been temporary become aux outputs, so they get
+     affected by -dump* flags:
+
+     # gcc -dumpdir f -dumpbase g- -save-temps b.c d.c
+     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # fg-b.o
+     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # fg-d.o
+     && link
+
+     If -save-temps=* prevails over -dumpdir, however, the explicit
+     -dumpdir is discarded, as if it wasn't there.  The basename of
+     the implicit linker output, a.out or a.exe, becomes a- as the aux
+     output prefix for all compilations:
+
+     # gcc [-dumpdir f] -save-temps=cwd b.c d.c
+     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.o
+     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.o
+     && link
+
+     A single -dumpbase, applying to multiple inputs, overrides the
+     linker output name, implied or explicit, as the aux output prefix:
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
+     && link
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c -o dir/h.out
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
+     && link -o dir/h.out
+
+     Now, if the linker output is NOT overridden as a prefix, but
+     -save-temps=* overrides implicit or explicit -dumpdir, the
+     effective dump dir combines the dir selected by the -save-temps=*
+     option with the basename of the specified or implied link output:
+
+     # gcc [-dumpdir f] -save-temps=cwd b.c d.c -o dir/h.out
+     -> cc1 -dumpdir h- -dumpbase b.c -dumpbase-ext .c # h-b.o
+     && cc1 -dumpdir h- -dumpbase d.c -dumpbase-ext .c # h-d.o
+     && link -o dir/h.out
+
+     # gcc [-dumpdir f] -save-temps=obj b.c d.c -o dir/h.out
+     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
+     && cc1 -dumpdir dir/h- -dumpbase d.c -dumpbase-ext .c # dir/h-d.o
+     && link -o dir/h.out
+
+     But then again, a single -dumpbase applying to multiple inputs
+     gets used instead of the linker output basename in the combined
+     dumpdir:
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=obj b.c d.c -o dir/h.out
+     -> cc1 -dumpdir dir/g- -dumpbase b.c -dumpbase-ext .c # dir/g-b.o
+     && cc1 -dumpdir dir/g- -dumpbase d.c -dumpbase-ext .c # dir/g-d.o
+     && link -o dir/h.out
+
+     With a single input being compiled, the output basename does NOT
+     affect the dumpdir prefix.
+
+     # gcc -save-temps=obj b.c -gsplit-dwarf -c -o dir/b.o
+     -> cc1 -dumpdir dir/ -dumpbase b.c -dumpbase-ext .c # dir/b.o dir/b.dwo
+
+     but when compiling and linking even a single file, it does:
+
+     # gcc -save-temps=obj b.c -o dir/h.out
+     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
+
+     unless an explicit -dumpdir prevails:
+
+     # gcc -save-temps[=obj] -dumpdir g- b.c -o dir/h.out
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+
+  */
+
+  bool explicit_dumpdir = dumpdir;
+
+  if (!save_temps_overrides_dumpdir && explicit_dumpdir)
+    {
+      /* Do nothing.  */
+    }
+
   /* If -save-temps=obj and -o name, create the prefix to use for %b.
      Otherwise just make -save-temps=obj the same as -save-temps=cwd.  */
-  if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL)
+  else if (save_temps_flag != SAVE_TEMPS_CWD && output_file != NULL)
+    {
+      free (dumpdir);
+      dumpdir = NULL;
+      temp = lbasename (output_file);
+      if (temp != output_file)
+	dumpdir = xstrndup (output_file,
+			    strlen (output_file) - strlen (temp));
+    }
+  else if (dumpdir)
+    {
+      free (dumpdir);
+      dumpdir = NULL;
+    }
+
+  if (save_temps_flag)
+    save_temps_flag = SAVE_TEMPS_DUMP;
+
+  /* If there is any pathname component in an explicit -dumpbase, it
+     overrides dumpdir entirely, so discard it right away.  Although
+     the presence of an explicit -dumpdir matters for the driver, it
+     shouldn't matter for other processes, that get all that's needed
+     from the -dumpdir and -dumpbase always passed to them.  */
+  if (dumpdir && dumpbase && lbasename (dumpbase) != dumpbase)
+    {
+      free (dumpdir);
+      dumpdir = NULL;
+    }
+
+  /* Check that dumpbase_ext matches the end of dumpbase, drop it
+     otherwise.  */
+  if (dumpbase_ext && dumpbase && *dumpbase)
+    {
+      int lendb = strlen (dumpbase);
+      int lendbx = strlen (dumpbase_ext);
+
+      if (lendbx >= lendb
+	  || strcmp (dumpbase + lendb - lendbx, dumpbase_ext) != 0)
+	{
+	  free (dumpbase_ext);
+	  dumpbase_ext = NULL;
+	}
+    }
+
+  /* -dumpbase with multiple sources goes into dumpdir.  With a single
+     source, it does only if linking and if dumpdir was not explicitly
+     specified.  */
+  if (dumpbase && *dumpbase
+      && (single_input_file_index () == -2
+	  || (!have_c && !explicit_dumpdir)))
+    {
+      char *prefix;
+
+      if (dumpbase_ext)
+	/* We checked that they match above.  */
+	dumpbase[strlen (dumpbase) - strlen (dumpbase_ext)] = '\0';
+
+      if (dumpdir)
+	prefix = concat (dumpdir, dumpbase, "-", NULL);
+      else
+	prefix = concat (dumpbase, "-", NULL);
+
+      free (dumpdir);
+      free (dumpbase);
+      free (dumpbase_ext);
+      dumpbase = dumpbase_ext = NULL;
+      dumpdir = prefix;
+      dumpdir_trailing_dash_added = true;
+    }
+
+  /* If dumpbase was not brought into dumpdir but we're linking, bring
+     output_file into dumpdir unless dumpdir was explicitly specified.
+     The test for !explicit_dumpdir is further below, because we want
+     to use the obase computation for a ghost outbase, passed to
+     GCC_COLLECT_OPTIONS.  */
+  else if (!have_c && (!explicit_dumpdir || (dumpbase && !*dumpbase)))
+    {
+      /* If we get here, we know dumpbase was not specified, or it was
+	 specified as an empty string.  If it was anything else, it
+	 would have combined with dumpdir above, because the condition
+	 for dumpbase to be used when present is broader than the
+	 condition that gets us here.  */
+      gcc_assert (!dumpbase || !*dumpbase);
+
+      const char *obase;
+      char *tofree = NULL;
+      if (!output_file || not_actual_file_p (output_file))
+	obase = "a";
+      else
+	{
+	  obase = lbasename (output_file);
+	  size_t blen = strlen (obase), xlen;
+	  /* Drop the suffix if it's dumpbase_ext, if given,
+	     otherwise .exe or the target executable suffix, or if the
+	     output was explicitly named a.out, but not otherwise.  */
+	  if (dumpbase_ext
+	      ? (blen > (xlen = strlen (dumpbase_ext))
+		 && strcmp ((temp = (obase + blen - xlen)),
+			    dumpbase_ext) == 0)
+	      : ((temp = strrchr (obase + 1, '.'))
+		 && (xlen = strlen (temp))
+		 && (strcmp (temp, ".exe") == 0
+#if HAVE_TARGET_EXECUTABLE_SUFFIX
+		     || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
+#endif
+		     || strcmp (obase, "a.out") == 0)))
+	    {
+	      tofree = xstrndup (obase, blen - xlen);
+	      obase = tofree;
+	    }
+	}
+
+      /* We wish to save this basename to the -dumpdir passed through
+	 GCC_COLLECT_OPTIONS within maybe_run_linker, for e.g. LTO,
+	 but we do NOT wish to add it to e.g. %b, so we keep
+	 outbase_length as zero.  */
+      gcc_assert (!outbase);
+      outbase_length = 0;
+
+      /* If we're building [dir1/]foo[.exe] out of a single input
+	 [dir2/]foo.c that shares the same basename, dump to
+	 [dir2/]foo.c.* rather than duplicating the basename into
+	 [dir2/]foo-foo.c.*.  */
+      int idxin;
+      if (dumpbase
+	  || ((idxin = single_input_file_index ()) >= 0
+	      && adds_single_suffix_p (lbasename (infiles[idxin].name),
+				       obase)))
+	{
+	  if (obase == tofree)
+	    outbase = tofree;
+	  else
+	    {
+	      outbase = xstrdup (obase);
+	      free (tofree);
+	    }
+	  obase = tofree = NULL;
+	}
+      else
+	{
+	  if (dumpdir)
+	    {
+	      char *p = concat (dumpdir, obase, "-", NULL);
+	      free (dumpdir);
+	      dumpdir = p;
+	    }
+	  else
+	    dumpdir = concat (obase, "-", NULL);
+
+	  dumpdir_trailing_dash_added = true;
+
+	  free (tofree);
+	  obase = tofree = NULL;
+	}
+
+      if (!explicit_dumpdir || dumpbase)
+	{
+	  /* Absent -dumpbase and present -dumpbase-ext have been applied
+	     to the linker output name, so compute fresh defaults for each
+	     compilation.  */
+	  free (dumpbase_ext);
+	  dumpbase_ext = NULL;
+	}
+    }
+
+  /* Now, if we're compiling, or if we haven't used the dumpbase
+     above, then outbase (%B) is derived from dumpbase, if given, or
+     from the output name, given or implied.  We can't precompute
+     implied output names, but that's ok, since they're derived from
+     input names.  Just make sure we skip this if dumpbase is the
+     empty string: we want to use input names then, so don't set
+     outbase.  */
+  if ((dumpbase || have_c)
+      && !(dumpbase && !*dumpbase))
     {
-      save_temps_length = strlen (save_temps_prefix);
-      temp = strrchr (lbasename (save_temps_prefix), '.');
-      if (temp)
+      gcc_assert (!outbase);
+
+      if (dumpbase)
+	{
+	  gcc_assert (single_input_file_index () != -2);
+	  /* We do not want lbasename here; dumpbase with dirnames
+	     overrides dumpdir entirely, even if dumpdir is
+	     specified.  */
+	  if (dumpbase_ext)
+	    /* We've already checked above that the suffix matches.  */
+	    outbase = xstrndup (dumpbase,
+				strlen (dumpbase) - strlen (dumpbase_ext));
+	  else
+	    outbase = xstrdup (dumpbase);
+	}
+      else if (output_file && !not_actual_file_p (output_file))
 	{
-	  save_temps_length -= strlen (temp);
-	  save_temps_prefix[save_temps_length] = '\0';
+	  outbase = xstrdup (lbasename (output_file));
+	  char *p = strrchr (outbase + 1, '.');
+	  if (p)
+	    *p = '\0';
 	}
 
+      if (outbase)
+	outbase_length = strlen (outbase);
     }
-  else if (save_temps_prefix != NULL)
+
+  /* If there is any pathname component in an explicit -dumpbase, do
+     not use dumpdir, but retain it to pass it on to the compiler.  */
+  if (dumpdir)
+    dumpdir_length = strlen (dumpdir);
+  else
+    dumpdir_length = 0;
+
+  /* Check that dumpbase_ext, if still present, still matches the end
+     of dumpbase, if present, and drop it otherwise.  We only retained
+     it above when dumpbase was absent to maybe use it to drop the
+     extension from output_name before combining it with dumpdir.  */
+  if (dumpbase_ext)
     {
-      free (save_temps_prefix);
-      save_temps_prefix = NULL;
+      if (!dumpbase)
+	{
+	  free (dumpbase_ext);
+	  dumpbase_ext = NULL;
+	}
+      else
+	gcc_assert (strcmp (dumpbase + strlen (dumpbase)
+			    - strlen (dumpbase_ext), dumpbase_ext) == 0);
     }
 
   if (save_temps_flag && use_pipes)
@@ -4843,6 +5277,28 @@ set_collect_gcc_options (void)
 	  obstack_grow (&collect_obstack, "'", 1);
 	}
     }
+
+  if (dumpdir)
+    {
+      if (!first_time)
+	obstack_grow (&collect_obstack, " ", 1);
+      first_time = FALSE;
+
+      obstack_grow (&collect_obstack, "'-dumpdir' '", 12);
+      const char *p, *q;
+
+      q = dumpdir;
+      while ((p = strchr (q, '\'')))
+	{
+	  obstack_grow (&collect_obstack, q, p - q);
+	  obstack_grow (&collect_obstack, "'\\''", 4);
+	  q = ++p;
+	}
+      obstack_grow (&collect_obstack, q, strlen (q));
+
+      obstack_grow (&collect_obstack, "'", 1);
+    }
+
   obstack_grow (&collect_obstack, "\0", 1);
   xputenv (XOBFINISH (&collect_obstack, char *));
 }
@@ -5333,22 +5789,33 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 	    fatal_error (input_location, "spec %qs invalid", spec);
 
 	  case 'b':
-	    if (save_temps_length)
-	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
-	    else
+	    /* Don't use %b in the linker command.  */
+	    gcc_assert (suffixed_basename_length);
+	    if (!this_is_output_file && dumpdir_length)
+	      obstack_grow (&obstack, dumpdir, dumpdir_length);
+	    if (this_is_output_file || !outbase_length)
 	      obstack_grow (&obstack, input_basename, basename_length);
+	    else
+	      obstack_grow (&obstack, outbase, outbase_length);
 	    if (compare_debug < 0)
 	      obstack_grow (&obstack, ".gk", 3);
 	    arg_going = 1;
 	    break;
 
 	  case 'B':
-	    if (save_temps_length)
-	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
+	    /* Don't use %B in the linker command.  */
+	    gcc_assert (suffixed_basename_length);
+	    if (!this_is_output_file && dumpdir_length)
+	      obstack_grow (&obstack, dumpdir, dumpdir_length);
+	    if (this_is_output_file || !outbase_length)
+	      obstack_grow (&obstack, input_basename, basename_length);
 	    else
-	      obstack_grow (&obstack, input_basename, suffixed_basename_length);
+	      obstack_grow (&obstack, outbase, outbase_length);
 	    if (compare_debug < 0)
 	      obstack_grow (&obstack, ".gk", 3);
+	    obstack_grow (&obstack, input_basename + basename_length,
+			  suffixed_basename_length - basename_length);
+
 	    arg_going = 1;
 	    break;
 
@@ -5501,42 +5968,44 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 		    suffix_length += 3;
 		  }
 
-		/* If -save-temps=obj and -o were specified, use that for the
+		/* If -save-temps was specified, use that for the
 		   temp file.  */
-		if (save_temps_length)
-		  {
-		    char *tmp;
-		    temp_filename_length
-		      = save_temps_length + suffix_length + 1;
-		    tmp = (char *) alloca (temp_filename_length);
-		    memcpy (tmp, save_temps_prefix, save_temps_length);
-		    memcpy (tmp + save_temps_length, suffix, suffix_length);
-		    tmp[save_temps_length + suffix_length] = '\0';
-		    temp_filename = save_string (tmp, save_temps_length
-						      + suffix_length);
-		    obstack_grow (&obstack, temp_filename,
-				  temp_filename_length);
-		    arg_going = 1;
-		    delete_this_arg = 0;
-		    break;
-		  }
-
-		/* If the gcc_input_filename has the same suffix specified
-		   for the %g, %u, or %U, and -save-temps is specified,
-		   we could end up using that file as an intermediate
-		   thus clobbering the user's source file (.e.g.,
-		   gcc -save-temps foo.s would clobber foo.s with the
-		   output of cpp0).  So check for this condition and
-		   generate a temp file as the intermediate.  */
-
 		if (save_temps_flag)
 		  {
 		    char *tmp;
-		    temp_filename_length = basename_length + suffix_length + 1;
+		    bool adjusted_suffix = false;
+		    if (suffix_length
+			&& !outbase_length && !basename_length
+			&& !dumpdir_trailing_dash_added)
+		      {
+			adjusted_suffix = true;
+			suffix++;
+			suffix_length--;
+		      }
+		    temp_filename_length
+		      = dumpdir_length + suffix_length + 1;
+		    if (!outbase_length)
+		      temp_filename_length += basename_length;
+		    else
+		      temp_filename_length += outbase_length;
 		    tmp = (char *) alloca (temp_filename_length);
-		    memcpy (tmp, input_basename, basename_length);
-		    memcpy (tmp + basename_length, suffix, suffix_length);
-		    tmp[basename_length + suffix_length] = '\0';
+		    if (dumpdir_length)
+		      memcpy (tmp, dumpdir, dumpdir_length);
+		    if (!outbase_length)
+		      memcpy (tmp + dumpdir_length, input_basename,
+			      basename_length);
+		    else
+		      memcpy (tmp + dumpdir_length, outbase,
+			      outbase_length);
+		    memcpy (tmp + temp_filename_length - suffix_length - 1,
+			    suffix, suffix_length);
+		    if (adjusted_suffix)
+		      {
+			adjusted_suffix = false;
+			suffix--;
+			suffix_length++;
+		      }
+		    tmp[temp_filename_length - 1] = '\0';
 		    temp_filename = tmp;
 
 		    if (filename_cmp (temp_filename, gcc_input_filename) != 0)
@@ -6047,6 +6516,14 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 	    }
 	    break;
 
+	  case '"':
+	    /* End a previous argument, if there is one, then issue an
+	       empty argument.  */
+	    end_going_arg ();
+	    arg_going = 1;
+	    end_going_arg ();
+	    break;
+
 	  default:
 	    error ("spec failure: unrecognized spec option %qc", c);
 	    break;
@@ -6057,6 +6534,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 	/* Backslash: treat next character as ordinary.  */
 	c = *p++;
 
+	/* When adding more cases that previously matched default, make
+	   sure to adjust quote_spec_char_p as well.  */
+
 	/* Fall through.  */
       default:
 	/* Ordinary character: put it into the current argument.  */
@@ -8262,6 +8742,40 @@ driver::maybe_run_linker (const char *argv0) const
     if (explicit_link_files[i] || outfiles[i] != NULL)
       num_linker_inputs++;
 
+  /* Arrange for temporary file names created during linking to take
+     on names related with the linker output rather than with the
+     inputs when appropriate.  */
+  if (outbase && *outbase)
+    {
+      if (dumpdir)
+	{
+	  char *tofree = dumpdir;
+	  gcc_checking_assert (strlen (dumpdir) == dumpdir_length);
+	  dumpdir = concat (dumpdir, outbase, ".", NULL);
+	  free (tofree);
+	}
+      else
+	dumpdir = concat (outbase, ".", NULL);
+      dumpdir_length += strlen (outbase) + 1;
+      dumpdir_trailing_dash_added = true;
+    }
+  else if (dumpdir_trailing_dash_added)
+    {
+      gcc_assert (dumpdir[dumpdir_length - 1] == '-');
+      dumpdir[dumpdir_length - 1] = '.';
+    }
+
+  if (dumpdir_trailing_dash_added)
+    {
+      gcc_assert (dumpdir_length > 0);
+      gcc_assert (dumpdir[dumpdir_length - 1] == '.');
+      dumpdir_length--;
+    }
+
+  free (outbase);
+  input_basename = outbase = NULL;
+  outbase_length = suffixed_basename_length = basename_length = 0;
+
   /* Run ld to link all the compiler output files.  */
 
   if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
@@ -9732,7 +10246,7 @@ compare_debug_dump_opt_spec_function (int arg,
   do_spec_1 (" ", 0, NULL);
 
   if (argbuf.length () > 0
-      && strcmp (argv[argbuf.length () - 1], "."))
+      && strcmp (argv[argbuf.length () - 1], ".") != 0)
     {
       if (!compare_debug)
 	return NULL;
@@ -9742,25 +10256,22 @@ compare_debug_dump_opt_spec_function (int arg,
     }
   else
     {
-      const char *ext = NULL;
-
       if (argbuf.length () > 0)
-	{
-	  do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}", NULL);
-	  ext = ".gkd";
-	}
+	do_spec_2 ("%B.gkd", NULL);
       else if (!compare_debug)
 	return NULL;
       else
-	do_spec_2 ("%g.gkd", NULL);
+	do_spec_2 ("%{!save-temps*:%g.gkd}%{save-temps*:%B.gkd}", NULL);
 
       do_spec_1 (" ", 0, NULL);
 
       gcc_assert (argbuf.length () > 0);
 
-      name = concat (argbuf.last (), ext, NULL);
+      name = xstrdup (argbuf.last ());
 
-      ret = concat ("-fdump-final-insns=", name, NULL);
+      char *arg = quote_spec (xstrdup (name));
+      ret = concat ("-fdump-final-insns=", arg, NULL);
+      free (arg);
     }
 
   which = compare_debug < 0;
@@ -9787,8 +10298,6 @@ compare_debug_dump_opt_spec_function (int arg,
   return ret;
 }
 
-static const char *debug_auxbase_opt;
-
 /* %:compare-debug-self-opt spec function.  Expands to the options
     that are to be passed in the second compilation of
     compare-debug.  */
@@ -9804,16 +10313,6 @@ compare_debug_self_opt_spec_function (int arg,
   if (compare_debug >= 0)
     return NULL;
 
-  do_spec_2 ("%{c|S:%{o*:%*}}", NULL);
-  do_spec_1 (" ", 0, NULL);
-
-  if (argbuf.length () > 0)
-    debug_auxbase_opt = concat ("-auxbase-strip ",
-				argbuf.last (),
-				NULL);
-  else
-    debug_auxbase_opt = NULL;
-
   return concat ("\
 %<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
 %<fdump-final-insns=* -w -S -o %j \
@@ -9821,50 +10320,6 @@ compare_debug_self_opt_spec_function (int arg,
 ", compare_debug_opt, NULL);
 }
 
-/* %:compare-debug-auxbase-opt spec function.  Expands to the auxbase
-    options that are to be passed in the second compilation of
-    compare-debug.  It expects, as an argument, the basename of the
-    current input file name, with the .gk suffix appended to it.  */
-
-static const char *
-compare_debug_auxbase_opt_spec_function (int arg,
-					 const char **argv)
-{
-  char *name;
-  int len;
-
-  if (arg == 0)
-    fatal_error (input_location,
-		 "too few arguments to %%:compare-debug-auxbase-opt");
-
-  if (arg != 1)
-    fatal_error (input_location,
-		 "too many arguments to %%:compare-debug-auxbase-opt");
-
-  if (compare_debug >= 0)
-    return NULL;
-
-  len = strlen (argv[0]);
-  if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
-    fatal_error (input_location, "argument to %%:compare-debug-auxbase-opt "
-		 "does not end in %<.gk%>");
-
-  if (debug_auxbase_opt)
-    return debug_auxbase_opt;
-
-#define OPT "-auxbase "
-
-  len -= 3;
-  name = (char*) xmalloc (sizeof (OPT) + len);
-  memcpy (name, OPT, sizeof (OPT) - 1);
-  memcpy (name + sizeof (OPT) - 1, argv[0], len);
-  name[sizeof (OPT) - 1 + len] = '\0';
-
-#undef OPT
-
-  return name;
-}
-
 /* %:pass-through-libs spec function.  Finds all -l options and input
    file names in the lib spec passed to it, and makes a list of them
    prepended with the plugin option to cause them to be passed through
@@ -9908,34 +10363,105 @@ pass_through_libs_spec_func (int argc, const char **argv)
   return prepended;
 }
 
-/* %:replace-extension spec function.  Replaces the extension of the
-   first argument with the second argument.  */
+static bool
+not_actual_file_p (const char *name)
+{
+  return (strcmp (name, "-") == 0
+	  || strcmp (output_file, HOST_BIT_BUCKET) == 0);
+}
 
+/* %:dumps spec function.  Take an optional argument that overrides
+   the default extension for -dumpbase and -dumpbase-ext.
+   Return -dumpdir, -dumpbase and -dumpbase-ext, if needed.  */
 const char *
-replace_extension_spec_func (int argc, const char **argv)
+dumps_spec_func (int argc, const char **argv ATTRIBUTE_UNUSED)
 {
-  char *name;
+  const char *ext = dumpbase_ext;
   char *p;
-  char *result;
-  int i;
 
-  if (argc != 2)
-    fatal_error (input_location, "too few arguments to %%:replace-extension");
+  char *args[3] = { NULL, NULL, NULL };
+  int nargs = 0;
 
-  name = xstrdup (argv[0]);
+  /* Do not compute a default for -dumpbase-ext when -dumpbase was
+     given explicitly.  */
+  if (dumpbase && *dumpbase && !ext)
+    ext = "";
 
-  for (i = strlen (name) - 1; i >= 0; i--)
-    if (IS_DIR_SEPARATOR (name[i]))
-      break;
+  if (argc == 1)
+    {
+      /* Do not override the explicitly-specified -dumpbase-ext with
+	 the specs-provided overrider.  */
+      if (!ext)
+	ext = argv[0];
+    }
+  else if (argc != 0)
+    fatal_error (input_location, "too many arguments for %%:dumps");
 
-  p = strrchr (name + i + 1, '.');
-  if (p != NULL)
-      *p = '\0';
+  if (dumpdir)
+    {
+      p = quote_spec_arg (xstrdup (dumpdir));
+      args[nargs++] = concat (" -dumpdir ", p, NULL);
+      free (p);
+    }
 
-  result = concat (name, argv[1], NULL);
+  if (!ext)
+    ext = input_basename + basename_length;
 
-  free (name);
-  return result;
+  /* Use the precomputed outbase, or compute dumpbase from
+     input_basename, just like %b would.  */
+  char *base;
+
+  if (dumpbase && *dumpbase)
+    {
+      base = xstrdup (dumpbase);
+      p = base + outbase_length;
+      gcc_checking_assert (strncmp (base, outbase, outbase_length) == 0);
+      gcc_checking_assert (strcmp (p, ext) == 0);
+    }
+  else if (outbase_length)
+    {
+      base = xstrndup (outbase, outbase_length);
+      p = NULL;
+    }
+  else
+    {
+      base = xstrndup (input_basename, suffixed_basename_length);
+      p = base + basename_length;
+    }
+
+  if (compare_debug < 0 || !p || strcmp (p, ext) != 0)
+    {
+      if (p)
+	*p = '\0';
+
+      const char *gk;
+      if (compare_debug < 0)
+	gk = ".gk";
+      else
+	gk = "";
+
+      p = concat (base, gk, ext, NULL);
+
+      free (base);
+      base = p;
+    }
+
+  base = quote_spec_arg (base);
+  args[nargs++] = concat (" -dumpbase ", base, NULL);
+  free (base);
+
+  if (*ext)
+    {
+      p = quote_spec_arg (xstrdup (ext));
+      args[nargs++] = concat (" -dumpbase-ext ", p, NULL);
+      free (p);
+    }
+
+  const char *ret = concat (args[0], args[1], args[2], NULL);
+  while (nargs > 0)
+    free (args[--nargs]);
+
+  return ret;
 }
 
 /* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
@@ -10041,6 +10567,44 @@ find_fortran_preinclude_file (int argc, const char **argv)
   return result;
 }
 
+/* If any character in ORIG fits QUOTE_P (_, P), reallocate the string
+   so as to precede every one of them with a backslash.  Return the
+   original string or the reallocated one.  */
+
+static inline char *
+quote_string (char *orig, bool (*quote_p)(char, void *), void *p)
+{
+  int len, number_of_space = 0;
+
+  for (len = 0; orig[len]; len++)
+    if (quote_p (orig[len], p))
+      number_of_space++;
+
+  if (number_of_space)
+    {
+      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
+      int j, k;
+      for (j = 0, k = 0; j <= len; j++, k++)
+	{
+	  if (quote_p (orig[j], p))
+	    new_spec[k++] = '\\';
+	  new_spec[k] = orig[j];
+	}
+      free (orig);
+      return new_spec;
+    }
+  else
+    return orig;
+}
+
+/* Return true iff C is any of the characters convert_white_space
+   should quote.  */
+
+static inline bool
+whitespace_to_convert_p (char c, void *)
+{
+  return (c == ' ' || c == '\t');
+}
 
 /* Insert backslash before spaces in ORIG (usually a file path), to 
    avoid being broken by spec parser.
@@ -10068,26 +10632,50 @@ find_fortran_preinclude_file (int argc, const char **argv)
 static char *
 convert_white_space (char *orig)
 {
-  int len, number_of_space = 0;
+  return quote_string (orig, whitespace_to_convert_p, NULL);
+}
 
-  for (len = 0; orig[len]; len++)
-    if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
+/* Return true iff C matches any of the spec active characters.  */
+static inline bool
+quote_spec_char_p (char c, void *)
+{
+  switch (c)
+    {
+    case ' ':
+    case '\t':
+    case '\n':
+    case '|':
+    case '%':
+    case '\\':
+      return true;
 
-  if (number_of_space)
+    default:
+      return false;
+    }
+}
+
+/* Like convert_white_space, but deactivate all active spec chars by
+   quoting them.  */
+
+static inline char *
+quote_spec (char *orig)
+{
+  return quote_string (orig, quote_spec_char_p, NULL);
+}
+
+/* Like quote_spec, but also turn an empty string into the spec for an
+   empty argument.  */
+
+static inline char *
+quote_spec_arg (char *orig)
+{
+  if (!*orig)
     {
-      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
-      int j, k;
-      for (j = 0, k = 0; j <= len; j++, k++)
-	{
-	  if (orig[j] == ' ' || orig[j] == '\t')
-	    new_spec[k++] = '\\';
-	  new_spec[k] = orig[j];
-	}
       free (orig);
-      return new_spec;
-  }
-  else
-    return orig;
+      return xstrdup ("%\"");
+    }
+
+  return quote_spec (orig);
 }
 
 /* Restore all state within gcc.c to the initial state, so that the driver
@@ -10124,8 +10712,14 @@ driver::finalize ()
   target_sysroot_suffix = 0;
   target_sysroot_hdrs_suffix = 0;
   save_temps_flag = SAVE_TEMPS_NONE;
-  save_temps_prefix = 0;
-  save_temps_length = 0;
+  save_temps_overrides_dumpdir = false;
+  dumpdir_trailing_dash_added = false;
+  free (dumpdir);
+  free (dumpbase);
+  free (dumpbase_ext);
+  free (outbase);
+  dumpdir = dumpbase = dumpbase_ext = outbase = NULL;
+  dumpdir_length = outbase_length = 0;
   spec_machine = DEFAULT_TARGET_MACHINE;
   greatest_status = 1;
 
@@ -10264,8 +10858,6 @@ driver::finalize ()
   mdswitches = NULL;
   n_mdswitches = 0;
 
-  debug_auxbase_opt = NULL;
-
   used_arg.finalize ();
 }
 
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index fe8f292..ed076e3 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -125,7 +125,7 @@ maybe_unlink (const char *file)
 }
 
 /* Template of LTRANS dumpbase suffix.  */
-#define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
+#define DUMPBASE_SUFFIX "ltrans18446744073709551615"
 
 /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
    environment.  */
@@ -1081,12 +1081,7 @@ debug_objcopy (const char *infile, bool rename)
     }
 
   if (save_temps)
-    {
-      outfile = (char *) xmalloc (strlen (orig_infile)
-				  + sizeof (".debug.temp.o") + 1);
-      strcpy (outfile, orig_infile);
-      strcat (outfile, ".debug.temp.o");
-    }
+    outfile = concat (orig_infile, ".debug.temp.o", NULL);
   else
     outfile = make_temp_file (".debug.temp.o");
   errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err, rename);
@@ -1271,6 +1266,8 @@ run_gcc (unsigned argc, char *argv[])
   bool linker_output_rel = false;
   bool skip_debug = false;
   unsigned n_debugobj;
+  const char *dumppfx = NULL, *incoming_dumppfx = NULL;
+  static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
 
   /* Get the driver and options.  */
   collect_gcc = getenv ("COLLECT_GCC");
@@ -1362,6 +1359,10 @@ run_gcc (unsigned argc, char *argv[])
 	  linker_output = option->arg;
 	  break;
 
+	  /* We don't have to distinguish between -save-temps=* and
+	     -save-temps, -dumpdir already carries that
+	     information.  */
+	case OPT_save_temps_:
 	case OPT_save_temps:
 	  save_temps = 1;
 	  break;
@@ -1407,6 +1408,10 @@ run_gcc (unsigned argc, char *argv[])
 	  skip_debug = option->arg && !strcmp (option->arg, "0");
 	  break;
 
+	case OPT_dumpdir:
+	  incoming_dumppfx = dumppfx = option->arg;
+	  break;
+
 	default:
 	  break;
 	}
@@ -1439,32 +1444,50 @@ run_gcc (unsigned argc, char *argv[])
       jobserver = 1;
     }
 
-  if (linker_output)
+  if (!dumppfx)
     {
-      char *output_dir, *base, *name;
-      bool bit_bucket = strcmp (linker_output, HOST_BIT_BUCKET) == 0;
-
-      output_dir = xstrdup (linker_output);
-      base = output_dir;
-      for (name = base; *name; name++)
-	if (IS_DIR_SEPARATOR (*name))
-	  base = name + 1;
-      *base = '\0';
-
-      linker_output = &linker_output[base - output_dir];
-      if (*output_dir == '\0')
-	{
-	  static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
-	  output_dir = current_dir;
-	}
-      if (!bit_bucket)
+      if (!linker_output
+	  || strcmp (linker_output, HOST_BIT_BUCKET) == 0)
+	dumppfx = "a.";
+      else
 	{
-	  obstack_ptr_grow (&argv_obstack, "-dumpdir");
-	  obstack_ptr_grow (&argv_obstack, output_dir);
+	  const char *obase = lbasename (linker_output), *temp;
+
+	  /* Strip the executable extension.  */
+	  size_t blen = strlen (obase), xlen;
+	  if ((temp = strrchr (obase + 1, '.'))
+	      && (xlen = strlen (temp))
+	      && (strcmp (temp, ".exe") == 0
+#if HAVE_TARGET_EXECUTABLE_SUFFIX
+		  || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
+#endif
+		  || strcmp (obase, "a.out") == 0))
+	    dumppfx = xstrndup (linker_output,
+				obase - linker_output + blen - xlen + 1);
+	  else
+	    dumppfx = concat (linker_output, ".", NULL);
 	}
+    }
 
-      obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  /* If there's no directory component in the dumppfx, add one, so
+     that, when it is used as -dumpbase, it overrides any occurrence
+     of -dumpdir that might have been passed in.  */
+  if (!dumppfx || lbasename (dumppfx) == dumppfx)
+    dumppfx = concat (current_dir, dumppfx, NULL);
+
+  /* Make sure some -dumpdir is passed, so as to get predictable
+     -dumpbase overriding semantics.  If we got an incoming -dumpdir
+     argument, we'll pass it on, so don't bother with another one
+     then.  */
+  if (!incoming_dumppfx)
+    {
+      obstack_ptr_grow (&argv_obstack, "-dumpdir");
+      /* An empty string would do, if only writeargv would write it
+	 out in a way that would not be skipped by expandargv and
+	 buildargv.  */
+      obstack_ptr_grow (&argv_obstack, current_dir);
     }
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
 
   /* Remember at which point we can scrub args to re-use the commons.  */
   new_head_argc = obstack_object_size (&argv_obstack) / sizeof (void *);
@@ -1570,15 +1593,11 @@ cont1:
 
   if (lto_mode == LTO_MODE_LTO)
     {
-      if (linker_output)
-	{
-	  obstack_ptr_grow (&argv_obstack, linker_output);
-	  flto_out = (char *) xmalloc (strlen (linker_output)
-				       + sizeof (".lto.o") + 1);
-	  strcpy (flto_out, linker_output);
-	  strcat (flto_out, ".lto.o");
-	}
-      else
+      /* -dumpbase argument for LTO.  */
+      flto_out = concat (dumppfx, "lto.o", NULL);
+      obstack_ptr_grow (&argv_obstack, flto_out);
+
+      if (!save_temps)
 	flto_out = make_temp_file (".lto.o");
       obstack_ptr_grow (&argv_obstack, "-o");
       obstack_ptr_grow (&argv_obstack, flto_out);
@@ -1586,47 +1605,17 @@ cont1:
   else 
     {
       const char *list_option = "-fltrans-output-list=";
-      size_t list_option_len = strlen (list_option);
-      char *tmp;
 
-      if (linker_output)
-	{
-	  char *dumpbase = (char *) xmalloc (strlen (linker_output)
-					     + sizeof (".wpa") + 1);
-	  strcpy (dumpbase, linker_output);
-	  strcat (dumpbase, ".wpa");
-	  obstack_ptr_grow (&argv_obstack, dumpbase);
-	}
+      /* -dumpbase argument for WPA.  */
+      char *dumpbase = concat (dumppfx, "wpa", NULL);
+      obstack_ptr_grow (&argv_obstack, dumpbase);
 
-      if (linker_output && save_temps)
-	{
-	  ltrans_output_file = (char *) xmalloc (strlen (linker_output)
-						 + sizeof (".ltrans.out") + 1);
-	  strcpy (ltrans_output_file, linker_output);
-	  strcat (ltrans_output_file, ".ltrans.out");
-	}
+      if (save_temps)
+	ltrans_output_file = concat (dumppfx, "ltrans.out", NULL);
       else
-	{
-	  char *prefix = NULL;
-	  if (linker_output)
-	    {
-	      prefix = (char *) xmalloc (strlen (linker_output) + 2);
-	      strcpy (prefix, linker_output);
-	      strcat (prefix, ".");
-	    }
-
-	  ltrans_output_file = make_temp_file_with_prefix (prefix,
-							   ".ltrans.out");
-	  free (prefix);
-	}
-      list_option_full = (char *) xmalloc (sizeof (char) *
-		         (strlen (ltrans_output_file) + list_option_len + 1));
-      tmp = list_option_full;
-
-      obstack_ptr_grow (&argv_obstack, tmp);
-      strcpy (tmp, list_option);
-      tmp += list_option_len;
-      strcpy (tmp, ltrans_output_file);
+	ltrans_output_file = make_temp_file (".ltrans.out");
+      list_option_full = concat (list_option, ltrans_output_file, NULL);
+      obstack_ptr_grow (&argv_obstack, list_option_full);
 
       if (jobserver)
 	{
@@ -1782,16 +1771,10 @@ cont:
 	  output_name = XOBFINISH (&env_obstack, char *);
 
 	  /* Adjust the dumpbase if the linker output file was seen.  */
-	  if (linker_output)
-	    {
-	      char *dumpbase
-		  = (char *) xmalloc (strlen (linker_output)
-				      + sizeof (DUMPBASE_SUFFIX) + 1);
-	      snprintf (dumpbase,
-			strlen (linker_output) + sizeof (DUMPBASE_SUFFIX),
-			"%s.ltrans%u", linker_output, i);
-	      argv_ptr[0] = dumpbase;
-	    }
+	  int dumpbase_len = (strlen (dumppfx) + sizeof (DUMPBASE_SUFFIX));
+	  char *dumpbase = (char *) xmalloc (dumpbase_len + 1);
+	  snprintf (dumpbase, dumpbase_len, "%sltrans%u.ltrans", dumppfx, i);
+	  argv_ptr[0] = dumpbase;
 
 	  argv_ptr[1] = "-fltrans";
 	  argv_ptr[2] = "-o";
diff --git a/gcc/opts.c b/gcc/opts.c
index fa4804c..5b29b98 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -845,30 +845,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	/* We have a DUMP_DIR_NAME, prepend that.  */
 	opts->x_dump_base_name = opts_concat (opts->x_dump_dir_name,
 					      opts->x_dump_base_name, NULL);
-      else if (opts->x_aux_base_name
-	       && strcmp (opts->x_aux_base_name, HOST_BIT_BUCKET) != 0)
-	/* AUX_BASE_NAME is set and is not the bit bucket.  If it
-	   contains a directory component, prepend those directories.
-	   Typically this places things in the same directory as the
-	   object file.  */
-	{
-	  const char *aux_base;
-
-	  base_of_path (opts->x_aux_base_name, &aux_base);
-	  if (opts->x_aux_base_name != aux_base)
-	    {
-	      int dir_len = aux_base - opts->x_aux_base_name;
-	      char *new_dump_base_name
-		= XOBNEWVEC (&opts_obstack, char,
-			     strlen (opts->x_dump_base_name) + dir_len + 1);
-
-	      /* Copy directory component from OPTS->X_AUX_BASE_NAME.  */
-	      memcpy (new_dump_base_name, opts->x_aux_base_name, dir_len);
-	      /* Append existing OPTS->X_DUMP_BASE_NAME.  */
-	      strcpy (new_dump_base_name + dir_len, opts->x_dump_base_name);
-	      opts->x_dump_base_name = new_dump_base_name;
-	    }
-	}
 
       /* It is definitely prefixed now.  */
       opts->x_dump_base_name_prefixed = true;
@@ -2314,17 +2290,6 @@ common_handle_option (struct gcc_options *opts,
       opts->x_flag_gen_aux_info = 1;
       break;
 
-    case OPT_auxbase_strip:
-      {
-	char *tmp = xstrdup (arg);
-	strip_off_ending (tmp, strlen (tmp));
-	if (tmp[0])
-	  opts->x_aux_base_name = tmp;
-	else
-	  free (tmp);
-      }
-      break;
-
     case OPT_d:
       decode_d_option (arg, opts, loc, dc);
       break;
diff --git a/gcc/testsuite/gcc.misc-tests/outputs-0.c b/gcc/testsuite/gcc.misc-tests/outputs-0.c
new file mode 100644
index 00000000..ca2ac4a
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/outputs-0.c
@@ -0,0 +1 @@
+int main () {}
diff --git a/gcc/testsuite/gcc.misc-tests/outputs-1.c b/gcc/testsuite/gcc.misc-tests/outputs-1.c
new file mode 100644
index 00000000..35f19cf
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/outputs-1.c
@@ -0,0 +1,4 @@
+extern void f();
+int main() {
+  f();
+}
diff --git a/gcc/testsuite/gcc.misc-tests/outputs-2.c b/gcc/testsuite/gcc.misc-tests/outputs-2.c
new file mode 100644
index 00000000..109733d
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/outputs-2.c
@@ -0,0 +1,2 @@
+void f() {
+}
diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp
new file mode 100644
index 00000000..a37e978
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
@@ -0,0 +1,655 @@
+# Copyright (C) 2005-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file contains a set of test that check that options intended to
+# control the location and name of GCC outputs behave as expected.
+
+load_lib gcc-defs.exp
+
+set b "outputs"
+
+# These tests don't run runtest_file_p consistently if it
+# doesn't return the same values, so disable parallelization
+# of this *.exp file.  The first parallel runtest to reach
+# this will run all the tests serially.
+if ![gcc_parallel_test_run_p $b] {
+    return
+}
+gcc_parallel_test_enable 0
+
+# For the test named TEST, run the compiler with SOURCES and OPTS, and
+# look in DIRS for OUTPUTS.  SOURCES is a list of suffixes for source
+# files starting with $b in $srcdir/$subdir, OPTS is a string with
+# options to be passed to the compiler, DIRS and OUTPUTS are lists.
+# DIRS is a list of output directories, children before parent, and
+# for each element of DIRS, there should be a corresponding sublist in
+# OUTPUTS.  If OUTPUTS has an additional trailing sublist, that's the
+# output list for the current directory.  Each element of the sublists
+# in OUTPUT is a file name or glob pattern to be checked for; a name
+# starting with a dash or a period is taken as a suffix for $b; with a
+# double dash, or a dash followed by a period, the first dash is
+# replaced with $b-$b; names starting with "a--" or "a-." have "$b"
+# inserted after the first dash.  The glob pattern may expand to more
+# than one file, but then the test will pass when there any number of
+# matches.  So, it's safe to use for a.{out,exe}, but .{i,s,o} and
+# .[iso] will pass even if only the .o is present.
+proc outest { test sources opts dirs outputs } {
+    global b
+    global srcdir
+    global subdir
+    set src {}
+    foreach s $sources {
+	lappend src $srcdir/$subdir/$b$s
+    }
+    foreach f [glob -nocomplain -path $b -- *] {
+	file delete $f
+    }
+    foreach d $dirs {
+	file mkdir $d
+	foreach f [glob -nocomplain -path $d -- *] {
+	    file delete $d$f
+	}
+    }
+    set options ""
+    foreach opt [split $opts " "] {
+	set options "$options additional_flags=$opt"
+    }
+    set gcc_output [gcc_target_compile $src "" none "$options"]
+    set outs {}
+    foreach d $dirs olist $outputs {
+	foreach og $olist {
+	    if { [string index $og 0] == "-" } then {
+		if { [string index $og 1] == "-" || \
+			 [string index $og 1] == "." } then {
+		    set o "$b-$b[string range $og 1 end]"
+		} else {
+		    set o "$b$og"
+		}
+	    } elseif { [string index $og 0] == "." } then {
+		set o "$b$og"
+	    } elseif { [string range $og 0 2] == "a--" } then {
+		set o "a-$b-[string range $og 3 end]"
+	    } elseif { [string range $og 0 2] == "a-." } then {
+		set o "a-$b.[string range $og 3 end]"
+	    } else {
+		set o "$og"
+	    }
+	    if { [file exists $d$o] } then {
+		pass "$test: $d$o"
+		file delete $d$o
+	    } else {
+	        set ogl [glob -nocomplain -path $d -- $o]
+		if { $ogl != {} } {
+		    pass "$test: $d$o"
+		    file delete $ogl
+		} else {
+		    fail "$test: $d$o"
+		}
+	    }
+	}
+	foreach ol [glob -nocomplain -path $d$b -- *] {
+	    lappend outs $ol
+	}
+	foreach ol [glob -nocomplain -path $d -- a{-,.}*] {
+	    lappend outs $ol
+	}
+    }
+
+    foreach f $outs {
+	file delete $f
+    }
+    foreach d $dirs {
+	file delete -force $d
+    }
+
+    if { [llength $outs] == 0 } then {
+	pass "$test: extra"
+    } else {
+	fail "$test: extra $outs"
+    }
+
+    if { [string equal "$gcc_output" ""] } then {
+	pass "$test: std out"
+    } else {
+	fail "$test: std out $gcc_output"
+    }
+
+}
+
+set sing {-0.c}
+set mult {-1.c -2.c}
+
+# Driver-chosen outputs.
+outest "$b asm default 1" $sing "-S" {} {{-0.s}}
+outest "$b asm default 2" $mult "-S" {} {{-1.s -2.s}}
+
+outest "$b obj default 1" $sing "-c" {} {{-0.o}}
+outest "$b obj default 2" $mult "-c" {} {{-1.o -2.o}}
+
+outest "$b exe default 1" $sing "" {} {{a.{out,exe}}}
+outest "$b exe default 2" $mult "" {} {{a.{out,exe}}}
+
+# Driver-chosen aux outputs.
+outest "$b asm savetmp 1" $sing "-S -save-temps" {} {{-0.i -0.s}}
+outest "$b asm savetmp 2" $mult "-S -save-temps" {} {{-1.i -1.s -2.i -2.s}}
+outest "$b obj savetmp unnamed1" $sing "-c -save-temps" {} {{-0.i -0.s -0.o}}
+outest "$b obj savetmp unnamed2" $mult "-c -save-temps" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
+
+# Aux outputs computed within the driver, based on output name (and
+# input).
+outest "$b cpp savetmp named0" $sing "-E -o $b-0.i -save-temps" {} {{-0.i}}
+outest "$b asm savetmp named0" $sing "-S -o $b-0.s -save-temps" {} {{-0.i -0.s}}
+outest "$b obj savetmp named0" $sing "-c -o $b-0.o -save-temps" {} {{-0.i -0.s -0.o}}
+outest "$b cpp savetmp namedb" $sing "-E -o $b.i -save-temps" {} {{.i}}
+outest "$b asm savetmp namedb" $sing "-S -o $b.s -save-temps" {} {{.i .s}}
+outest "$b obj savetmp namedb" $sing "-c -o $b.o -save-temps" {} {{.i .s .o}}
+
+# When linking, the executable name gets prepended to aux output
+# basenames, except when executable and single input share the same
+# basename.
+outest "$b exe savetmp unnamed1" $sing "-save-temps" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
+outest "$b exe savetmp unnamed2" $mult "-save-temps" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe savetmp named0" $sing "-o $b-0.exe -save-temps" {} {{-0.i -0.s -0.o -0.exe}}
+outest "$b exe savetmp namedb" $sing "-o $b.exe -save-temps" {} {{--0.i --0.s --0.o .exe}}
+outest "$b exe savetmp named2" $mult "-o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
+
+# Setting the main output to a dir selects it as the default aux&dump
+# location.
+outest "$b cpp savetmp namedir0" $sing "-E -o o/$b-0.i -save-temps" {o/} {{-0.i} {}}
+outest "$b asm savetmp namedir0" $sing "-S -o o/$b-0.s -save-temps" {o/} {{-0.i -0.s} {}}
+outest "$b obj savetmp namedir0" $sing "-c -o o/$b-0.o -save-temps" {o/} {{-0.i -0.s -0.o} {}}
+outest "$b cpp savetmp namedir" $sing "-E -o o/$b.i -save-temps" {o/} {{.i} {}}
+outest "$b asm savetmp namedir" $sing "-S -o o/$b.s -save-temps" {o/} {{.i .s} {}}
+outest "$b obj savetmp namedir" $sing "-c -o o/$b.o -save-temps" {o/} {{.i .s .o} {}}
+outest "$b exe savetmp namedir0" $sing "-o o/$b-0.exe -save-temps" {o/} {{-0.i -0.s -0.o -0.exe} {}}
+outest "$b exe savetmp namedirb" $sing "-o o/$b.exe -save-temps" {o/} {{--0.i --0.s --0.o .exe} {}}
+outest "$b exe savetmp namedir2" $mult "-o o/$b.exe -save-temps" {o/} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe} {}}
+
+# -save-temps=cwd overrides the aux output location to the current dir.
+outest "$b obj savecwd unnamed1" $sing "-c -save-temps=cwd" {} {{-0.i -0.s -0.o}}
+outest "$b obj savecwd unnamed2" $mult "-c -save-temps=cwd" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
+outest "$b cpp savecwd named0" $sing "-E -o $b-0.i -save-temps=cwd" {} {{-0.i}}
+outest "$b asm savecwd named0" $sing "-S -o $b-0.s -save-temps=cwd" {} {{-0.i -0.s}}
+outest "$b obj savecwd named0" $sing "-c -o $b-0.o -save-temps=cwd" {} {{-0.i -0.s -0.o}}
+outest "$b cpp savecwd namedb" $sing "-E -o $b.i -save-temps=cwd" {} {{.i}}
+outest "$b asm savecwd namedb" $sing "-S -o $b.s -save-temps=cwd" {} {{.i .s}}
+outest "$b obj savecwd namedb" $sing "-c -o $b.o -save-temps=cwd" {} {{.i .s .o}}
+outest "$b exe savecwd unnamed1" $sing "-save-temps=cwd" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
+outest "$b exe savecwd unnamed2" $mult "-save-temps=cwd" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe savecwd named0" $sing "-o $b-0.exe -save-temps=cwd" {} {{-0.i -0.s -0.o -0.exe}}
+outest "$b exe savecwd namedb" $sing "-o $b.exe -save-temps=cwd" {} {{--0.i --0.s --0.o .exe}}
+outest "$b exe savecwd named2" $mult "-o $b.exe -save-temps=cwd" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
+
+outest "$b cpp savecwd namedir0" $sing "-E -o o/$b-0.i -save-temps=cwd" {o/} {{-0.i} {}}
+outest "$b asm savecwd namedir0" $sing "-S -o o/$b-0.s -save-temps=cwd" {o/} {{-0.s} {-0.i}}
+outest "$b obj savecwd namedir0" $sing "-c -o o/$b-0.o -save-temps=cwd" {o/} {{-0.o} {-0.i -0.s}}
+outest "$b cpp savecwd namedir" $sing "-E -o o/$b.i -save-temps=cwd" {o/} {{.i} {}}
+outest "$b asm savecwd namedir" $sing "-S -o o/$b.s -save-temps=cwd" {o/} {{.s} {.i}}
+outest "$b obj savecwd namedir" $sing "-c -o o/$b.o -save-temps=cwd" {o/} {{.o} {.i .s}}
+outest "$b exe savecwd namedir0" $sing "-o o/$b-0.exe -save-temps=cwd" {o/} {{-0.exe} {-0.i -0.s -0.o}}
+outest "$b exe savecwd namedirb" $sing "-o o/$b.exe -save-temps=cwd" {o/} {{.exe} {--0.i --0.s --0.o}}
+outest "$b exe savecwd namedir2" $mult "-o o/$b.exe -save-temps=cwd" {o/} {{.exe} {--1.i --1.s --1.o --2.i --2.s --2.o}}
+
+# -save-temps=obj overrides the aux output location to that of the
+# main output
+outest "$b obj saveobj unnamed1" $sing "-c -save-temps=obj" {} {{-0.i -0.s -0.o}}
+outest "$b obj saveobj unnamed2" $mult "-c -save-temps=obj" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
+outest "$b cpp saveobj named0" $sing "-E -o $b-0.i -save-temps=obj" {} {{-0.i}}
+outest "$b asm saveobj named0" $sing "-S -o $b-0.s -save-temps=obj" {} {{-0.i -0.s}}
+outest "$b obj saveobj named0" $sing "-c -o $b-0.o -save-temps=obj" {} {{-0.i -0.s -0.o}}
+outest "$b cpp saveobj namedb" $sing "-E -o $b.i -save-temps=obj" {} {{.i}}
+outest "$b asm saveobj namedb" $sing "-S -o $b.s -save-temps=obj" {} {{.i .s}}
+outest "$b obj saveobj namedb" $sing "-c -o $b.o -save-temps=obj" {} {{.i .s .o}}
+outest "$b exe saveobj unnamed1" $sing "-save-temps=obj" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
+outest "$b exe saveobj unnamed2" $mult "-save-temps=obj" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe saveobj named0" $sing "-o $b-0.exe -save-temps=obj" {} {{-0.i -0.s -0.o -0.exe}}
+outest "$b exe saveobj namedb" $sing "-o $b.exe -save-temps=obj" {} {{--0.i --0.s --0.o .exe}}
+outest "$b exe saveobj named2" $mult "-o $b.exe -save-temps=obj" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
+
+outest "$b cpp saveobj namedir0" $sing "-E -o o/$b-0.i -save-temps=obj" {o/} {{-0.i} {}}
+outest "$b asm saveobj namedir0" $sing "-S -o o/$b-0.s -save-temps=obj" {o/} {{-0.i -0.s} {}}
+outest "$b obj saveobj namedir0" $sing "-c -o o/$b-0.o -save-temps=obj" {o/} {{-0.i -0.s -0.o} {}}
+outest "$b cpp saveobj namedir" $sing "-E -o o/$b.i -save-temps=obj" {o/} {{.i} {}}
+outest "$b asm saveobj namedir" $sing "-S -o o/$b.s -save-temps=obj" {o/} {{.i .s} {}}
+outest "$b obj saveobj namedir" $sing "-c -o o/$b.o -save-temps=obj" {o/} {{.i .s .o} {}}
+outest "$b exe saveobj namedir0" $sing "-o o/$b-0.exe -save-temps=obj" {o/} {{-0.i -0.s -0.o -0.exe} {}}
+outest "$b exe saveobj namedirb" $sing "-o o/$b.exe -save-temps=obj" {o/} {{--0.i --0.s --0.o .exe} {}}
+outest "$b exe saveobj namedir2" $mult "-o o/$b.exe -save-temps=obj" {o/} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe} {}}
+
+# Check -dumpdir overriding by -save-temps=*, and -save-temps
+# non-overriding, with one catch: the presence of a given dumpdir,
+# even if ultimately overridden, still disables the prepending of the
+# executable basename to the aux&dump output basenames (or rather the
+# appending of the executable basename to the dumpdir).
+outest "$b exe sobjovr namedir0" $sing "-o o/$b-0.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-0.i -0.s -0.o -0.exe} {}}
+outest "$b exe sobjovr namedirb" $sing "-o o/$b.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-0.i -0.s -0.o .exe} {}}
+outest "$b exe sobjovr namedir2" $mult "-o o/$b.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o .exe} {}}
+outest "$b exe scwdovr namedir0" $sing "-o o/$b-0.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{-0.exe} {-0.i -0.s -0.o}}
+outest "$b exe scwdovr namedirb" $sing "-o o/$b.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{.exe} {-0.i -0.s -0.o}}
+outest "$b exe scwdovr namedir2" $mult "-o o/$b.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{.exe} {-1.i -1.s -1.o -2.i -2.s -2.o}}
+outest "$b exe ddstovr namedir0" $sing "-o $b-0.exe -dumpdir o/ -save-temps" {o/} {{-0.i -0.s -0.o} {-0.exe}}
+outest "$b exe ddstovr namedirb" $sing "-o $b.exe -dumpdir o/ -save-temps" {o/} {{-0.i -0.s -0.o} {.exe}}
+outest "$b exe ddstovr namedir2" $mult "-o $b.exe -dumpdir o/ -save-temps" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o} {.exe}}
+
+# Check -dumpdir prevailing over -save-temps*.  Even though -dumpdir
+# overrides the -save-temps=* directory selection, -save-temps remains
+# enabled.
+outest "$b exe soddovr namedir0" $sing "-o o/$b-0.exe -save-temps=obj -dumpdir ./" {o/} {{-0.exe} {-0.i -0.s -0.o}}
+outest "$b exe soddovr namedirb" $sing "-o o/$b.exe -save-temps=obj -dumpdir ./" {o/} {{.exe} {-0.i -0.s -0.o}}
+outest "$b exe soddovr namedir2" $mult "-o o/$b.exe -save-temps=obj -dumpdir ./" {o/} {{.exe} {-1.i -1.s -1.o -2.i -2.s -2.o}}
+outest "$b exe scddovr namedir0" $sing "-o o/$b-0.exe -save-temps=cwd -dumpdir o/" {o/} {{-0.i -0.s -0.o -0.exe} {}}
+outest "$b exe scddovr namedirb" $sing "-o o/$b.exe -save-temps=cwd -dumpdir o/" {o/} {{-0.i -0.s -0.o .exe} {}}
+outest "$b exe scddovr namedir2" $mult "-o o/$b.exe -save-temps=cwd -dumpdir o/" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o .exe} {}}
+outest "$b exe ddstovr namedir0" $sing "-o $b-0.exe -save-temps -dumpdir o/" {o/} {{-0.i -0.s -0.o} {-0.exe}}
+outest "$b exe ddstovr namedirb" $sing "-o $b.exe -save-temps -dumpdir o/" {o/} {{-0.i -0.s -0.o} {.exe}}
+outest "$b exe ddstovr namedir2" $mult "-o $b.exe -save-temps -dumpdir o/" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o} {.exe}}
+
+
+# Compiler- and driver-generated aux and dump outputs.
+# -fdump-rtl-final creates a .c.???r.final dump in the compiler.
+# -fstack-usage creates a .su aux output in the compiler.
+# -gsplit-dwarf extracts a .dwo aux output from the .o in the driver.
+outest "$b asm auxdump 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.s}}
+outest "$b asm auxdump 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-1.c.???r.final -1.su -1.s -2.c.???r.final -2.su -2.s}}
+outest "$b obj auxdump unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+outest "$b obj auxdump unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-1.c.???r.final -1.su -1.dwo -1.o -2.c.???r.final -2.su -2.dwo -2.o}}
+
+outest "$b cpp auxdump named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.i}}
+outest "$b asm auxdump named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.s}}
+outest "$b obj auxdump named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.i}}
+outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.c.???r.final .su .s}}
+outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.c.???r.final .su .dwo .o}}
+
+outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
+outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
+outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
+outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
+outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
+
+outest "$b cpp auxdump namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.i} {}}
+outest "$b asm auxdump namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.s} {}}
+outest "$b obj auxdump namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.o} {}}
+outest "$b cpp auxdump namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.i} {}}
+outest "$b asm auxdump namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.c.???r.final .su .s} {}}
+outest "$b obj auxdump namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.c.???r.final .su .dwo .o} {}}
+outest "$b exe auxdump namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.exe} {}}
+outest "$b exe auxdump namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{--0.c.???r.final --0.su --0.dwo .exe} {}}
+outest "$b exe auxdump namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
+
+# Check that -save-temps doesn't break compiler aux or dumps as it
+# changes temp file names.
+outest "$b asm auxdmps 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
+outest "$b asm auxdmps 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -2.i -2.c.???r.final -2.su -2.s}}
+outest "$b obj auxdmps unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
+outest "$b obj auxdmps unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -1.dwo -1.o -2.i -2.c.???r.final -2.su -2.s -2.dwo -2.o}}
+
+outest "$b cpp auxdmps named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i}}
+outest "$b asm auxdmps named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
+outest "$b obj auxdmps named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
+outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i}}
+outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
+outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
+
+outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
+outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
+outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
+outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
+outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
+
+outest "$b cpp auxdmps namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i} {}}
+outest "$b asm auxdmps namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s} {}}
+outest "$b obj auxdmps namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o} {}}
+outest "$b cpp auxdmps namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i} {}}
+outest "$b asm auxdmps namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i .c.???r.final .su .s} {}}
+outest "$b obj auxdmps namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i .c.???r.final .su .s .dwo .o} {}}
+outest "$b exe auxdmps namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe} {}}
+outest "$b exe auxdmps namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe} {}}
+outest "$b exe auxdmps namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe} {}}
+
+
+# Check that dumpdir changes the location of non-primary outputs
+outest "$b asm dumpdir 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
+outest "$b asm dumpdir 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -2.c.???r.final -2.su} {-1.s -2.s}}
+outest "$b obj dumpdir unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
+outest "$b obj dumpdir unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dumpdir named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{} {-0.i}}
+outest "$b asm dumpdir named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
+outest "$b obj dumpdir named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
+outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{} {.i}}
+outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
+outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
+
+outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
+outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
+outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
+outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
+outest "$b exe dumpdira namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dumpdira named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+outest "$b exe dumpdirb namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
+outest "$b exe dumpdirb named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+
+outest "$b cpp dumpdir namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dumpdir namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su} {-0.s} {}}
+outest "$b obj dumpdir namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.o} {}}
+outest "$b cpp dumpdir namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{} {.i} {}}
+outest "$b asm dumpdir namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su} {.s} {}}
+outest "$b obj dumpdir namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su .dwo} {.o} {}}
+outest "$b exe dumpdir namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe} {}}
+outest "$b exe dumpdir namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {.exe} {}}
+outest "$b exe dumpdir namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe} {}}
+outest "$b exe dumpdira namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
+outest "$b exe dumpdira namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+outest "$b exe dumpdirb namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
+outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+
+# Check that a -dumpbase with a dir component disregards the -dumpdir
+# prefix.  Also, start testing -dumpbase-ext to distinguish between
+# aux and dump files: only the latter retain the named extension.
+# -dumpbase-ext, if absent or used in combination with -dumpbase for
+# an executable name, defaults to the extension of the source file.
+# The specified dumpbase is combined with the dumpdir prefix when
+# processing more than one input (we couldn't use the same dumpbase
+# for them all), or when linking (the specified dumpbase is then used
+# as prefix instead of the linker output, and a new dumpbase is
+# computed per source).
+outest "$b asm dbsovrdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbsovrddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbsovrdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbsovrdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbsovrdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbsovrddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbsovrdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbsovrddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbsovrdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbsovrdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {-0.i}}
+outest "$b asm dbsovrdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbsovrdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbsovrdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {.i}}
+outest "$b asm dbsovrdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
+
+# Nit: -dumpdir affects whether the specified dumpbase is combined
+# into dumpdir or taken as the output basename, even if dumpbase will
+# ultimately override it.
+outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
+outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
+outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
+outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbsovrdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbsovrddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbsovrdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbsovrdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbsovrdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbsovrdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbsovrdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbsovrdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbsovrdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbsovrdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
+outest "$b exe dbsovrdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
+outest "$b exe dbsovrdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbsovrdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
+outest "$b exe dbsovrdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+
+
+# Check that a -dumpbase without a dir component adds to the -dumpdir
+# prefix.
+outest "$b asm dbswthdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbswthddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbswthdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbswthdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbswthdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbswthddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbswthdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbswthddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbswthdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbswthdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {-0.i}}
+outest "$b asm dbswthdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbswthdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbswthdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {.i}}
+outest "$b asm dbswthdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {.o}}
+
+# Nitty details: -dumpdir affects whether the specified dumpbase is
+# combined into dumpdir or taken as the output basename, even if
+# dumpbase will ultimately override it.
+outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
+outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
+outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
+outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbswthdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbswthddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbswthdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbswthdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbswthdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbswthdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbswthdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbswthdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbswthdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbswthdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
+outest "$b exe dbswthdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
+outest "$b exe dbswthdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbswthdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
+outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+
+
+# Check for the minor differences when -dumpbase is used without
+# -dumpdir.  The main difference between dbwoutdd and dbswthdd tests
+# is in the single-input link tests: with the dump dir/ prefix moved
+# to dumpbase, and without -dumpdir we end up using -dumpbase as the
+# executable prefix rather than as the dumpbase for the single input.
+outest "$b asm dbwoutdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbwoutddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbwoutdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbwoutdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbwoutdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbwoutddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbwoutdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbwoutddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbwoutdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbwoutdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{} {-0.i}}
+outest "$b asm dbwoutdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbwoutdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{} {.i}}
+outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
+
+outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
+outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
+outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
+outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
+outest "$b exe dbwoutdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbwoutdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dbwoutddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dbwoutdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbwoutdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbwoutdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbwoutdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbwoutdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbwoutdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbwoutdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbwoutdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe} {}}
+outest "$b exe dbwoutdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
+outest "$b exe dbwoutdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbwoutdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
+outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+
+# -fcompare-debug
+outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage -gsplit-dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
+outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage -gsplit-dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
+
+# -flto
+outest "$b lto sing unnamed" $sing "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto mult unnamed" $mult "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.c.???i.icf a--2.c.???i.icf  a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing named" $sing "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
+outest "$b lto mult named" $mult "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
+outest "$b lto sing nameddir" $sing "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
+outest "$b lto mult nameddir" $mult "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
+
+# -dumpbase without -dumpdir.  The trailing dumppfx dash after it is
+# combined with dumpbase turns into a period when passed to lto as
+# -dumpdir, because the dash is introduced by the compiler driver.
+outest "$b lto sing dumpbase unnamed" $sing "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto mult dumpbase unnamed" $mult "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing dumpbase named" $sing "-dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto mult dumpbase named" $mult "-dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto sing dumpbase namedb" $sing "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+outest "$b lto mult dumpbase namedb" $mult "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+
+# -dumpdir without -dumpbase.  The trailing dash in -dumpdir is given
+# by the user, thus not replaced with a dot.
+outest "$b lto sing dumpdir unnamed" $sing "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto mult dumpdir unnamed" $mult "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto sing dumpdir namedb" $sing "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
+outest "$b lto mult dumpdir namedb" $mult "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
+
+# -dumpdir and non-overriding -dumpbase.
+outest "$b lto dbswthdd sing unnamed" $sing "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbswthdd mult unnamed" $mult "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbswthdd sing named" $sing "-dumpdir dir/ -dumpbase $b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto dbswthdd mult named" $mult "-dumpdir dir/ -dumpbase $b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto dbswthdd sing namedb" $sing "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+outest "$b lto dbswthdd mult namedb" $mult "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+
+# -dumpdir and an overriding -dumpbase.
+outest "$b lto dbsovrdd sing unnamed" $sing "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbsovrdd mult unnamed" $mult "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbsovrdd sing named" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto dbsovrdd mult named" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto dbsovrdd sing namedb" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+outest "$b lto dbsovrdd mult namedb" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+
+# Check that -dumpbase '' gets source names as dumpbases for
+# compilation, and output name as dumpbase for linking, regardless of
+# how many source files.
+outest "$b lto sing empty dumpbase unnamed" $sing "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto mult empty dumpbase unnamed" $mult "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing empty dumpbase named" $sing "-dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.exe} {}}
+outest "$b lto mult empty dumpbase named" $mult "-dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.exe} {}}
+outest "$b lto sing empty dumpbase namedb" $sing "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
+outest "$b lto mult empty dumpbase namedb" $mult "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
+
+# Now with -dumpdir too.
+outest "$b lto sing empty dumpbase dumpdir unnamed" $sing "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto mult empty dumpbase dumpdir unnamed" $mult "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing empty dumpbase dumpdir named" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf --0.wpa.???i.icf --0.ltrans0.ltrans.???r.final --0.ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto mult empty dumpbase dumpdir named" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf --1.wpa.???i.icf --1.ltrans0.ltrans.???r.final --1.ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto sing empty dumpbase dumpdir namedb" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
+outest "$b lto mult empty dumpbase dumpdir namedb" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
+
+# And also with an empty -dumpdir.  That's equivalent to -dumpdir ./,
+# overriding any dumpdir implied by the output.
+outest "$b lto sing empty dumpdir empty dumpbase unnamed" $sing "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto mult empty dumpdir empty dumpbase unnamed" $mult "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing empty dumpdir empty dumpbase named" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.exe} {-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su}}
+outest "$b lto mult empty dumpdir empty dumpbase named" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.exe} {-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su}}
+outest "$b lto sing empty dumpdir empty dumpbase namedb" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
+outest "$b lto mult empty dumpdir empty dumpbase namedb" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
+
+# Now -flto with -save-temps, not exhaustive.
+outest "$b lto st sing empty dumpbase unnamed" $sing "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.i -0.s -0.o -0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st mult empty dumpbase unnamed" $mult "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st sing dumpdir empty dumpbase named" $sing "-dumpdir dir/ -dumpbase \"\" -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf -0.lto_wrapper_args -0.wpa.???i.icf -0.ltrans.out -0.res -0.ltrans0.o -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.ltrans0.ltrans.s -0.ltrans0.ltrans.o} {-0.exe}}
+outest "$b lto st mult dumpdir empty dumpbase named" $mult "-dumpdir dir/ -dumpbase \"\" -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf -1.lto_wrapper_args -1.wpa.???i.icf -1.ltrans.out -1.res -1.ltrans0.o -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.ltrans0.ltrans.s -1.ltrans0.ltrans.o} {-1.exe}}
+outest "$b lto st sing empty dumpbase namedb" $sing "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
+outest "$b lto st mult empty dumpbase namedb" $mult "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
+
+# lto save-temps without -dumpbase.
+outest "$b lto st sing unnamed" $sing "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.i a--0.s a--0.o a--0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st mult unnamed" $mult "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.i a--1.s a--1.o a--1.c.???i.icf a--2.i a--2.s a--2.o a--2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-0.exe}}
+outest "$b lto st mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-1.exe}}
+outest "$b lto st sing namedb" $sing "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
+outest "$b lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
+
+# Below are examples taken from the documentation.
+# They are likely redundant with earlier test,
+# but we want to make sure behavior matches the docs.
+
+# gcc -c foo.c ...
+outest "$b doc single  -c !-o" $sing "-c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+
+# gcc -c foo.c -o dir/foobar.o ...
+outest "$b doc single  -c +-o" $sing "-c -o dir/$b.o -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.c.???r.final .su .dwo .o} {}}
+
+# gcc foo.c bar.c -o dir/foobar ...
+outest "$b doc double !-c  -o" $mult "-o dir/$b.exe -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
+
+# gcc foo.c -o dir/foo ...
+outest "$b doc single !-c  -o" $sing "-o dir/$b-0 -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo -0} {}}
+
+# gcc -save-temps -S foo.c
+outest "$b doc single  -S -st" $sing "-save-temps -S" {} {{-0.i -0.s}}
+
+# gcc -save-temps -dumpbase save-foo -c foo.c
+outest "$b doc single  -c -st -db" $sing "-save-temps -dumpbase $b -c" {} {{.i .s -0.o}}
+
+# gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
+#   -dumpdir pfx- -save-temps=cwd ...
+outest "$b doc single  -c  -o -db" $sing "-c -o dir/$b.o -dumpbase alt/$b -dumpdir pfx- -save-temps=cwd -fdump-rtl-final -fstack-usage -gsplit-dwarf" {alt/ dir/} {{.i .s .???r.final .su .dwo} {.o} {}}
+
+# gcc foo.c bar.c -c -dumpbase main ...
+outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo -1.o --2.c.???r.final --2.su --2.dwo -2.o}}
+
+# gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
+outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
+
+# gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
+outest "$b doc double !-c  -o -db'' -flto" $mult "-o dir/$b.exe -dumpbase \"\" -flto -O2 -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
+
+
+# gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
+outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
+
+# gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
+outest "$b doc double !-c  -o -dbx" $mult "-o $b.out -dumpbase-ext .out -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .out}}
+
+# gcc -dumpdir pfx- -c foo.c ...
+outest "$b doc single  -c !-o -dd" $sing "-dumpdir $b- -c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--0.c.???r.final --0.su --0.dwo -0.o}}
+
+# gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
+outest "$b doc single  -c  -o -dd" $sing "-dumpdir dir/ -c -o obj/$b.o -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/ obj/} {{.c.???r.final .su .dwo} {.o} {}}
+
+# gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
+outest "$b doc single  -c  -o -dd -st=" $sing "-dumpdir $b- -c -save-temps=obj -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.i -0.s -0.o}}
+
+# gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
+outest "$b doc double  -c !-o -dd -db" $mult "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+# gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
+outest "$b doc single  -c !-o -dd -db" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
+
+# gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
+outest "$b doc double !-c  -o -dd" $mult "-dumpdir dir/ -o $b.exe -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
+
+# gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
+outest "$b doc single !-c  -o -dd -st=" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
+
+
+gcc_parallel_test_enable 1
diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
index da0d1bc..e656e27 100644
--- a/gcc/testsuite/lib/gcc-defs.exp
+++ b/gcc/testsuite/lib/gcc-defs.exp
@@ -305,6 +305,10 @@ proc dg-additional-files-options { options source } {
 	set to_download [concat $to_download $additional_sources]
 	set additional_sources_used "$additional_sources"
 	set additional_sources ""
+	# This option restores naming of aux and dump output files
+	# after input files when multiple input files are named,
+	# instead of getting them combined with the output name.
+	lappend options "additional_flags=-dumpbase \"\""
     }
     if { $additional_files != "" } then { 
 	regsub -all "^| " $additional_files " [file dirname $source]/" additional_files
diff --git a/gcc/testsuite/lib/profopt.exp b/gcc/testsuite/lib/profopt.exp
index 0b853a1..af1fd62f 100644
--- a/gcc/testsuite/lib/profopt.exp
+++ b/gcc/testsuite/lib/profopt.exp
@@ -353,6 +353,10 @@ proc profopt-execute { src } {
 
     set count 0
     foreach option $prof_option_list {
+	# We pass -dumpbase-ext ${execext}[123] to the compile&link
+	# commands so as to avoid the combination of the executable
+	# with the source name in the aux outputs.
+	set execext ".x${count}"
 	set execname1 "${executable}${count}1"
 	set execname2 "${executable}${count}2"
 	set execname3 "${executable}${count}3"
@@ -402,7 +406,7 @@ proc profopt-execute { src } {
 	# Compile for profiling.
 
 	set options "$extra_options"
-	lappend options "additional_flags=$option $extra_flags $profile_option"
+	lappend options "additional_flags=$option $extra_flags $profile_option -dumpbase-ext ${execext}1"
 	set optstr "$option $profile_option"
 	set comp_output [${tool}_target_compile "$src" "$execname1" executable $options]
 	if ![${tool}_check_compile "$testcase compilation" $optstr $execname1 $comp_output] {
@@ -491,7 +495,7 @@ proc profopt-execute { src } {
 	# Compile with feedback-directed optimizations.
 
 	set options "$extra_options"
-	lappend options "additional_flags=$option $extra_flags $feedback_option"
+	lappend options "additional_flags=$option $extra_flags $feedback_option -dumpbase-ext ${execext}2"
 	set optstr "$option $feedback_option"
 	if { [string first "-fauto-profile" $options] >= 0} {
 	    set options [regsub -- "-fauto-profile" $options "-fauto-profile=$tmpdir/$bprefix$base.$ext"]
@@ -548,7 +552,7 @@ proc profopt-execute { src } {
 	# Compile with normal optimizations.
 
 	set options "$extra_options"
-	lappend options "additional_flags=$option"
+	lappend options "additional_flags=$option -dumpbase-ext ${execext}3"
 	set optstr "$option"
 	set comp_output [${tool}_target_compile "$src" "$execname3" "executable" $options]
 	if ![${tool}_check_compile "$testcase compilation" $optstr $execname3 $comp_output] {
diff --git a/gcc/testsuite/lib/scandump.exp b/gcc/testsuite/lib/scandump.exp
index 4c7d904..b29a95a 100644
--- a/gcc/testsuite/lib/scandump.exp
+++ b/gcc/testsuite/lib/scandump.exp
@@ -32,6 +32,9 @@ proc dump-suffix { arg } {
 proc dump-base { args } {
     set src [lindex $args 0]
     set dumpbase_suf [lindex $args 1]
+    # The dump basename may vary depending on the output name, on
+    # whether there are multiple sources.  We use -dumpbase "" in
+    # gcc-defs to base compilation dumps only on the source basename.
     set dumpbase $src
     if { [string length $dumpbase_suf] != 0 } {
 	regsub {[.][^.]*$} $src $dumpbase_suf dumpbase
diff --git a/gcc/testsuite/lib/scanltranstree.exp b/gcc/testsuite/lib/scanltranstree.exp
index cff956b..6d35bef 100644
--- a/gcc/testsuite/lib/scanltranstree.exp
+++ b/gcc/testsuite/lib/scanltranstree.exp
@@ -37,11 +37,11 @@ proc scan-ltrans-tree-dump { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump "ltrans-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
+		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
 		  [lindex $args 2]
     } else {
 	scan-dump "ltrans-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
+		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
     }
 }
 
@@ -63,10 +63,10 @@ proc scan-ltrans-tree-dump-times { args } {
     if { [llength $args] >= 4 } {
 	scan-dump-times "ltrans-tree" [lindex $args 0] [lindex $args 1] \
 			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" \
-			".exe.ltrans0" [lindex $args 3]
+			".ltrans0.ltrans" [lindex $args 3]
     } else {
 	scan-dump-times "ltrans-tree" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" ".exe.ltrans0"
+			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" ".ltrans0.ltrans"
     }
 }
 
@@ -87,11 +87,11 @@ proc scan-ltrans-tree-dump-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-not "ltrans-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
+		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
 		      [lindex $args 2]
     } else {
 	scan-dump-not "ltrans-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
+		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
     }
 }
 
@@ -113,11 +113,11 @@ proc scan-ltrans-tree-dump-dem { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem "ltrans-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
+		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
 		      [lindex $args 2]
     } else {
 	scan-dump-dem "ltrans-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
+		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
     }
 }
 
@@ -139,10 +139,10 @@ proc scan-ltrans-tree-dump-dem-not { args } {
     if { [llength $args] >= 3 } {
 	scan-dump-dem-not "ltrans-tree" [lindex $args 0] \
 			  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" \
-			  ".exe.ltrans0" [lindex $args 2]
+			  ".ltrans0.ltrans" [lindex $args 2]
     } else {
 	scan-dump-dem-not "ltrans-tree" [lindex $args 0] \
 			  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" \
-			  ".exe.ltrans0"
+			  ".ltrans0.ltrans"
     }
 }
diff --git a/gcc/testsuite/lib/scanwpaipa.exp b/gcc/testsuite/lib/scanwpaipa.exp
index d00b400..39e95b8 100644
--- a/gcc/testsuite/lib/scanwpaipa.exp
+++ b/gcc/testsuite/lib/scanwpaipa.exp
@@ -37,11 +37,11 @@ proc scan-wpa-ipa-dump { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump "wpa-ipa" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
+		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
 		  [lindex $args 2]
     } else {
 	scan-dump "wpa-ipa" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
+		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
     }
 }
 
@@ -62,11 +62,11 @@ proc scan-wpa-ipa-dump-times { args } {
     }
     if { [llength $args] >= 4 } {
 	scan-dump-times "wpa-ipa" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".exe.wpa" \
+			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".wpa" \
 			[lindex $args 3]
     } else {
 	scan-dump-times "wpa-ipa" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".exe.wpa"
+			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".wpa"
     }
 }
 
@@ -87,11 +87,11 @@ proc scan-wpa-ipa-dump-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-not "wpa-ipa" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
+		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
 		      [lindex $args 2]
     } else {
 	scan-dump-not "wpa-ipa" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
+		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
     }
 }
 
@@ -113,11 +113,11 @@ proc scan-wpa-ipa-dump-dem { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem "wpa-ipa" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
+		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
 		      [lindex $args 2]
     } else {
 	scan-dump-dem "wpa-ipa" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
+		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
     }
 }
 
@@ -138,10 +138,10 @@ proc scan-wpa-ipa-dump-dem-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem-not "wpa-ipa" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
+			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
 			  [lindex $args 2]
     } else {
 	scan-dump-dem-not "wpa-ipa" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
+			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
     }
 }
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 4c8be50..04f8938 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -796,8 +796,8 @@ print_switch_values (print_switch_fn_type print_fn)
 	case OPT_o:
 	case OPT_d:
 	case OPT_dumpbase:
+	case OPT_dumpbase_ext:
 	case OPT_dumpdir:
-	case OPT_auxbase:
 	case OPT_quiet:
 	case OPT_version:
 	  /* Ignore these.  */
@@ -1410,11 +1410,19 @@ process_options (void)
   /* Set aux_base_name if not already set.  */
   if (aux_base_name)
     ;
-  else if (main_input_filename)
+  else if (dump_base_name)
     {
-      char *name = xstrdup (lbasename (main_input_filename));
+      const char *name = dump_base_name;
+      int nlen, len;
+
+      if (dump_base_ext && (len = strlen (dump_base_ext))
+	  && (nlen = strlen (name)) && nlen > len
+	  && strcmp (name + nlen - len, dump_base_ext) == 0)
+	{
+	  char *p = xstrndup (name, nlen - len);
+	  name = p;
+	}
 
-      strip_off_ending (name, strlen (name));
       aux_base_name = name;
     }
   else
@@ -1961,8 +1969,21 @@ static int
 lang_dependent_init (const char *name)
 {
   location_t save_loc = input_location;
-  if (dump_base_name == 0)
-    dump_base_name = name && name[0] ? name : "gccdump";
+  if (!dump_base_name)
+    {
+      dump_base_name = name && name[0] ? name : "gccdump";
+
+      /* We do not want to derive a non-empty dumpbase-ext from an
+	 explicit -dumpbase argument, only from a defaulted
+	 dumpbase.  */
+      if (!dump_base_ext)
+	{
+	  const char *base = lbasename (dump_base_name);
+	  const char *ext = strrchr (base, '.');
+	  if (ext)
+	    dump_base_ext = ext;
+	}
+    }
 
   /* Other front-end initialization.  */
   input_location = BUILTINS_LOCATION;
@@ -1974,20 +1995,25 @@ lang_dependent_init (const char *name)
     {
       init_asm_output (name);
 
-      /* If stack usage information is desired, open the output file.  */
-      if (flag_stack_usage && !flag_generate_lto)
-	stack_usage_file = open_auxiliary_file ("su");
-
-      /* If call graph information is desired, open the output file.  */
-      if (flag_callgraph_info && !flag_generate_lto)
+      if (!flag_generate_lto && !flag_compare_debug)
 	{
-	  callgraph_info_file = open_auxiliary_file ("ci");
-	  /* Write the file header.  */
-	  fprintf (callgraph_info_file,
-		   "graph: { title: \"%s\"\n", main_input_filename);
-	  bitmap_obstack_initialize (NULL);
-	  callgraph_info_external_printed = BITMAP_ALLOC (NULL);
+	  /* If stack usage information is desired, open the output file.  */
+	  if (flag_stack_usage)
+	    stack_usage_file = open_auxiliary_file ("su");
+
+	  /* If call graph information is desired, open the output file.  */
+	  if (flag_callgraph_info)
+	    {
+	      callgraph_info_file = open_auxiliary_file ("ci");
+	      /* Write the file header.  */
+	      fprintf (callgraph_info_file,
+		       "graph: { title: \"%s\"\n", main_input_filename);
+	      bitmap_obstack_initialize (NULL);
+	      callgraph_info_external_printed = BITMAP_ALLOC (NULL);
+	    }
 	}
+      else
+	flag_stack_usage = flag_callgraph_info = false;
     }
 
   /* This creates various _DECL nodes, so needs to be called after the
diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c
index c307fc8..30f9cca 100644
--- a/lto-plugin/lto-plugin.c
+++ b/lto-plugin/lto-plugin.c
@@ -195,6 +195,10 @@ static int linker_output_set;
 static int linker_output_known;
 static const char *link_output_name = NULL;
 
+/* This indicates link_output_name already contains the dot of the
+   suffix, so we can skip it in extensions.  */
+static int skip_in_suffix = 0;
+
 /* The version of gold being used, or -1 if not gold.  The number is
    MAJOR * 100 + MINOR.  */
 static int gold_version = -1;
@@ -567,14 +571,11 @@ exec_lto_wrapper (char *argv[])
   /* Write argv to a file to avoid a command line that is too long
      Save the file locally on save-temps.  */
   if (save_temps && link_output_name)
-    {
-      arguments_file_name = (char *) xmalloc (strlen (link_output_name)
-				  + sizeof (".lto_wrapper_args") + 1);
-      strcpy (arguments_file_name, link_output_name);
-      strcat (arguments_file_name, ".lto_wrapper_args");
-    }
+    arguments_file_name = concat (link_output_name,
+				  ".lto_wrapper_args"
+				  + skip_in_suffix, NULL);
   else
-     arguments_file_name = make_temp_file (".lto_wrapper_args");
+    arguments_file_name = make_temp_file (".lto_wrapper_args");
   check (arguments_file_name, LDPL_FATAL,
          "Failed to generate a temorary file name");
 
@@ -1312,12 +1313,82 @@ onload (struct ld_plugin_tv *tv)
       if (strstr (collect_gcc_options, "'-fno-use-linker-plugin'"))
 	return LDPS_ERR;
 
-      if ( strstr (collect_gcc_options, "'-save-temps'"))
+      if (strstr (collect_gcc_options, "'-save-temps'"))
 	save_temps = true;
 
       if (strstr (collect_gcc_options, "'-v'")
           || strstr (collect_gcc_options, "'--verbose'"))
 	verbose = true;
+
+      const char *p;
+      if ((p = strstr (collect_gcc_options, "'-dumpdir'")))
+	{
+	  p += sizeof ("'-dumpdir'");
+	  while (*p == ' ')
+	    p++;
+	  const char *start = p;
+	  int ticks = 0, escapes = 0;
+	  /* Count ticks (') and escaped (\.) characters.  Stop at the
+	     end of the options or at a blank after an even number of
+	     ticks (not counting escaped ones.  */
+	  for (p = start; *p; p++)
+	    {
+	      if (*p == '\'')
+		{
+		  ticks++;
+		  continue;
+		}
+	      else if ((ticks % 2) != 0)
+		{
+		  if (*p == ' ')
+		    break;
+		  if (*p == '\\')
+		    {
+		      if (*++p)
+			escapes++;
+		      else
+			p--;
+		    }
+		}
+	    }
+
+	  /* Now allocate a new link_output_name and decode dumpdir
+	     into it.  The loop uses the same logic, except it counts
+	     ticks and escapes backwards (so ticks is adjusted if we
+	     find an odd number of them), and it copies characters
+	     that are escaped or not otherwise skipped.  */
+	  int len = p - start - ticks - escapes + 1;
+	  char *q = xmalloc (len);
+	  link_output_name = q;
+	  int oddticks = (ticks % 2);
+	  ticks += oddticks;
+	  for (p = start; *p; p++)
+	    {
+	      if (*p == '\'')
+		{
+		  ticks--;
+		  continue;
+		}
+	      else if ((ticks % 2) != 0)
+		{
+		  if (*p == ' ')
+		    break;
+		  if (*p == '\\')
+		    {
+		      if (*++p)
+			escapes--;
+		      else
+			p--;
+		    }
+		}
+	      *q++ = *p;
+	    }
+	  *q = '\0';
+	  assert (escapes == 0);
+	  assert (ticks == oddticks);
+	  assert (q - link_output_name == len - 1);
+	  skip_in_suffix = 1;
+	}
     }
 
   return LDPS_OK;
Alexandre Oliva Jan. 16, 2020, 10:12 a.m. UTC | #40
On Jan 16, 2020, Alexandre Oliva <oliva@adacore.com> wrote:

> On Jan  9, 2020, Alexandre Oliva <oliva@adacore.com> wrote:
>> On Jan  9, 2020, Richard Biener <rguenther@suse.de> wrote:
>>> Did I miss the actual (non-documentation) patch?

>> No, I didn't post it.  It's kind of big, and only yesterday did I get it
>> to work as expected and now extensively documented, passing all of the
>> extensive testsuite I wrote for it.

> Here it is, at last, regstrapped on x86_64-linux-gnu.  Ok to install?

And here's a followup that fixes a limitation (bug?) in libiberty that
was hit when I attempted a last-minute simplification in lto-wrapper.

Regstrapped separately on x86_64-linux-gnu.  Ok to install?


[libiberty] output empty args as a pair of quotes

From: Alexandre Oliva <oliva@adacore.com>

writeargv writes out empty arguments in a way that expandargv skips
them instead of preserving them.  Fixed by writing out a pair of
quotes for them.

This enables lto-wrapper to pass down an empty string, as desired.


for  libiberty/ChangeLog

	* argv.c (writeargv): Output empty args as "".

for  gcc/ChangeLog

	* lto-wrapper.c (run_gcc): Use an empty string for -dumpdir.
---
 gcc/lto-wrapper.c |    5 +----
 libiberty/argv.c  |    8 ++++++++
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index ed076e3..aa71f1e 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -1482,10 +1482,7 @@ run_gcc (unsigned argc, char *argv[])
   if (!incoming_dumppfx)
     {
       obstack_ptr_grow (&argv_obstack, "-dumpdir");
-      /* An empty string would do, if only writeargv would write it
-	 out in a way that would not be skipped by expandargv and
-	 buildargv.  */
-      obstack_ptr_grow (&argv_obstack, current_dir);
+      obstack_ptr_grow (&argv_obstack, "");
     }
   obstack_ptr_grow (&argv_obstack, "-dumpbase");
 
diff --git a/libiberty/argv.c b/libiberty/argv.c
index 8c9794db..6a72208 100644
--- a/libiberty/argv.c
+++ b/libiberty/argv.c
@@ -327,6 +327,14 @@ writeargv (char * const *argv, FILE *f)
           arg++;
         }
 
+      /* Write out a pair of quotes for an empty argument.  */
+      if (arg == *argv)
+	if (EOF == fputs ("\"\"", f))
+	  {
+	    status = 1;
+	    goto done;
+	  }
+
       if (EOF == fputc ('\n', f))
         {
           status = 1;
Joseph Myers Jan. 17, 2020, 1:02 a.m. UTC | #41
On Thu, 16 Jan 2020, Alexandre Oliva wrote:

> And here's a followup that fixes a limitation (bug?) in libiberty that
> was hit when I attempted a last-minute simplification in lto-wrapper.
> 
> Regstrapped separately on x86_64-linux-gnu.  Ok to install?
> 
> 
> [libiberty] output empty args as a pair of quotes

This libiberty / lto-wrapper patch is OK.
Richard Biener Jan. 20, 2020, 10:32 a.m. UTC | #42
On Thu, 16 Jan 2020, Alexandre Oliva wrote:

> On Jan  9, 2020, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > On Jan  9, 2020, Richard Biener <rguenther@suse.de> wrote:
> >> Did I miss the actual (non-documentation) patch?
> 
> > No, I didn't post it.  It's kind of big, and only yesterday did I get it
> > to work as expected and now extensively documented, passing all of the
> > extensive testsuite I wrote for it.
> 
> Here it is, at last, regstrapped on x86_64-linux-gnu.  Ok to install?

I'm hesitant to approve it now since we're in stage4 and been too
permissive already.  So ...

OK for GCC 11.

And thanks alot for this work!

Thanks,
Richard.

> 
> revamp dump and aux output names
> 
> This patch simplifies (!!!) the logic governing the naming of dump
> files and auxiliary output files in the driver, in the compiler, and
> in the LTO wrapper.  No changes are made to the naming of primary
> outputs, there are often ways to restore past behavior, and a number
> of inconsistencies are fixed.  Some internal options are removed
> (-auxbase and -auxbase-strip), sensible existing uses of -dumpdir and
> -dumpbase options remain unchanged, additional useful cases are added,
> making for what is still admittedly quite complex.  Extensive
> documentation and testcases provide numerous examples, from normal to
> corner cases.
> 
> The most visible changes are:
> 
> - aux and dump files now always go in the same directory, that
> defaults to the directory of the primary output, but that can be
> overridden with -dumpdir, -save-temps=*, or, preserving past behavior,
> with a -dumpbase with a directory component.
> 
> - driver and compiler now have the same notion of naming of auxiliary
> outputs, e.g. .dwo files will no longer be in one location while the
> debug info suggests they are elsewhere, and -save-temps and .dwo
> auxiliary outputs now go in the same location as .su, .ci and
> coverage data, with consistent naming.
> 
> - explicitly-specified primary output names guide not only the
> location of aux and dump outputs: the output base name is also used in
> their base name, as a prefix when also linking (e.g. foo.c bar.c -o
> foobar creates foobar-foo.dwo and foobar-bar.dwo with -gsplit-dwarf),
> or as the base name instead of the input name (foo.c -c -o whatever.o
> creates whatever.su rather than foo.su with -fstack-usage).  The
> preference for the input file base name, quite useful for our
> testsuite, can be restored with -dumpbase "".
> 
> - naming a -dumpbase when compiling multiple sources used to cause
> dumps from later compiles to overwrite those of earlier ones; it is
> now used as a prefix when compiling multiple sources, like an
> executable name above.
> 
> - the dumpbase, explicitly specified or computed from output or input
> names, now also governs the naming of aux outputs; since aux outputs
> usually replaced the suffix from the input name, while dump outputs
> append their own additional suffixes, a -dumpbase-ext option is
> introduced to enable a chosen suffix to be dropped from dumpbase to
> form aux output names.
> 
> - LTO dump and aux outputs were quite a mess, sometimes leaking
> temporary output names into -save-temps output names, sometimes
> conversely generating desirable aux outputs in temporary locations.
> They now obey the same logic of compiler aux and dump outputs, landing
> in the expected location and taking the linker output name or an
> explicit dumpbase overrider into account.
> 
> - Naming of -fdump-final-insns outputs now follows the dump file
> naming logic for the .gkd files, and the .gk dump files generated in
> the second -fcompare-debug compilation get the .gk inserted before the
> suffix that -dumpbase-ext drops in aux outputs.
> 
> 
> for  gcc/ChangeLog
> 
> 	* common.opt (aux_base_name): Define.
> 	(dumpbase, dumpdir): Mark as Driver options.
> 	(-dumpbase, -dumpdir): Likewise.
> 	(dumpbase-ext, -dumpbase-ext): New.
> 	(auxbase, auxbase-strip): Drop.
> 	* doc/invoke.texi (-dumpbase, -dumpbase-ext, -dumpdir):
> 	Document.
> 	(-o): Introduce the notion of primary output, mention it
> 	influences auxiliary and dump output names as well, add
> 	examples.
> 	(-save-temps): Adjust, move examples into -dump*.
> 	(-save-temps=cwd, -save-temps=obj): Likewise.
> 	(-fdump-final-insns): Adjust.
> 	* dwarf2out.c (gen_producer_string): Drop auxbase and
> 	auxbase_strip; add dumpbase_ext.
> 	* gcc.c (enum save_temps): Add SAVE_TEMPS_DUMP.
> 	(save_temps_prefix, save_temps_length): Drop.
> 	(save_temps_overrides_dumpdir): New.
> 	(dumpdir, dumpbase, dumpbase_ext): New.
> 	(dumpdir_length, dumpdir_trailing_dash_added): New.
> 	(outbase, outbase_length): New.
> 	(The Specs Language): Introduce %".  Adjust %b and %B.
> 	(ASM_FINAL_SPEC): Use %b.dwo for an aux output name always.
> 	Precede object file with %w when it's the primary output.
> 	(cpp_debug_options): Do not pass on incoming -dumpdir,
> 	-dumpbase and -dumpbase-ext options; recompute them with
> 	%:dumps.
> 	(cc1_options): Drop auxbase with and without compare-debug;
> 	use cpp_debug_options instead of dumpbase.  Mark asm output
> 	with %w when it's the primary output.
> 	(static_spec_functions): Drop %:compare-debug-auxbase-opt and
> 	%:replace-exception.  Add %:dumps.
> 	(driver_handle_option): Implement -save-temps=*/-dumpdir
> 	mutual overriding logic.  Save dumpdir, dumpbase and
> 	dumpbase-ext options.  Do not save output_file in
> 	save_temps_prefix.
> 	(adds_single_suffix_p): New.
> 	(single_input_file_index): New.
> 	(process_command): Combine output dir, output base name, and
> 	dumpbase into dumpdir and outbase.
> 	(set_collect_gcc_options): Pass a possibly-adjusted -dumpdir.
> 	(do_spec_1): Optionally dumpdir instead of save_temps_prefix,
> 	and outbase instead of input_basename in %b, %B and in
> 	-save-temps aux files.  Handle empty argument %".
> 	(driver::maybe_run_linker): Adjust dumpdir and auxbase.
> 	(compare_debug_dump_opt_spec_function): Adjust gkd dump file
> 	naming.  Spec-quote the computed -fdump-final-insns file name.
> 	(debug_auxbase_opt): Drop.
> 	(compare_debug_self_opt_spec_function): Drop auxbase-strip
> 	computation.
> 	(compare_debug_auxbase_opt_spec_function): Drop.
> 	(not_actual_file_p): New.
> 	(replace_extension_spec_func): Drop.
> 	(dumps_spec_func): New.
> 	(convert_white_space): Split-out parts into...
> 	(quote_string, whitespace_to_convert_p): ... these.  New.
> 	(quote_spec_char_p, quote_spec, quote_spec_arg): New.
> 	(driver::finalize): Release and reset new variables; drop
> 	removed ones.
> 	* lto-wrapper.c (DUMPBASE_SUFFIX): Drop leading period.
> 	(debug_objcopy): Use concat.
> 	(run_gcc): Recognize -save-temps=* as -save-temps too.  Obey
> 	-dumpdir.  Pass on empty dumpdir and dumpbase with a directory
> 	component.  Simplify temp file names.
> 	* opts.c (finish_options): Drop aux base name handling.
> 	(common_handle_option): Drop auxbase-strip handling.
> 	* toplev.c (print_switch_values): Drop auxbase, add
> 	dumpbase-ext.
> 	(process_options): Derive aux_base_name from dump_base_name
> 	and dump_base_ext.
> 	(lang_dependent_init): Compute dump_base_ext along with
> 	dump_base_name.  Disable stack usage and callgraph-info	during
> 	lto generation and compare-debug recompilation.
> 
> for  gcc/fortran/ChangeLog
> 
> 	* options.c (gfc_get_option_string): Drop auxbase, add
> 	dumpbase_ext.
> 
> for  gcc/ada/ChangeLog
> 
> 	* gcc-interface/lang-specs.h: Drop auxbase and auxbase-strip.
> 	Use %:dumps instead of -dumpbase.  Add %w for implicit .s
> 	primary output.
> 	* switch.adb (Is_Internal_GCC_Switch): Recognize dumpdir and
> 	dumpbase-ext.  Drop auxbase and auxbase-strip.
> 
> for  lto-plugin/ChangeLog
> 
> 	* lto-plugin.c (skip_in_suffix): New.
> 	(exec_lto_wrapper): Use skip_in_suffix and concat to build
> 	non-temporary output names.
> 	(onload): Look for -dumpdir in COLLECT_GCC_OPTIONS, and
> 	override link_output_name with it.
> 
> for  contrib/ChangeLog
> 
> 	* compare-debug: Adjust for .gkd files named as dump files,
> 	with the source suffix rather than the object suffix.
> 
> for  gcc/testsuite/ChangeLog
> 
> 	* gcc.misc-tests/outputs.exp: New.
> 	* gcc.misc-tests/outputs-0.c: New.
> 	* gcc.misc-tests/outputs-1.c: New.
> 	* gcc.misc-tests/outputs-2.c: New.
> 	* lib/gcc-defs.exp (dg-additional-files-options): Pass
> 	-dumpbase "" when there are additional sources.
> 	* lib/profopt.exp (profopt-execute): Pass the executable
> 	suffix with -dumpbase-ext.
> 	* lib/scandump.exp (dump-base): Mention -dumpbase "" use.
> 	* lib/scanltranstree.exp: Adjust dump suffix expectation.
> 	* lib/scanwpaipa.exp: Likewise.
> ---
>  contrib/compare-debug                    |   26 +
>  gcc/ada/gcc-interface/lang-specs.h       |   16 -
>  gcc/ada/switch.adb                       |    4 
>  gcc/common.opt                           |   27 +
>  gcc/doc/invoke.texi                      |  385 +++++++++++-
>  gcc/dwarf2out.c                          |    3 
>  gcc/fortran/options.c                    |    4 
>  gcc/gcc.c                                |  938 ++++++++++++++++++++++++------
>  gcc/lto-wrapper.c                        |  153 ++---
>  gcc/opts.c                               |   35 -
>  gcc/testsuite/gcc.misc-tests/outputs-0.c |    1 
>  gcc/testsuite/gcc.misc-tests/outputs-1.c |    4 
>  gcc/testsuite/gcc.misc-tests/outputs-2.c |    2 
>  gcc/testsuite/gcc.misc-tests/outputs.exp |  655 +++++++++++++++++++++
>  gcc/testsuite/lib/gcc-defs.exp           |    4 
>  gcc/testsuite/lib/profopt.exp            |   10 
>  gcc/testsuite/lib/scandump.exp           |    3 
>  gcc/testsuite/lib/scanltranstree.exp     |   20 -
>  gcc/testsuite/lib/scanwpaipa.exp         |   20 -
>  gcc/toplev.c                             |   62 +-
>  lto-plugin/lto-plugin.c                  |   87 +++
>  21 files changed, 2040 insertions(+), 419 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-0.c
>  create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-1.c
>  create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-2.c
>  create mode 100644 gcc/testsuite/gcc.misc-tests/outputs.exp
> 
> diff --git a/contrib/compare-debug b/contrib/compare-debug
> index 22870cf..cf80ae3 100755
> --- a/contrib/compare-debug
> +++ b/contrib/compare-debug
> @@ -2,7 +2,7 @@
>  
>  # Compare stripped copies of two given object files.
>  
> -# Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation
> +# Copyright (C) 2007, 2008, 2009, 2010, 2012, 2020 Free Software Foundation
>  # Originally by Alexandre Oliva <aoliva@redhat.com>
>  
>  # This file is part of GCC.
> @@ -183,8 +183,28 @@ $rm "$1.$suf1" "$2.$suf2"
>  
>  trap "exit $status; exit" 0 1 2 15
>  
> -if test -f "$1".gkd || test -f "$2".gkd; then
> -  if cmp "$1".gkd "$2".gkd; then
> +# Replace the suffix in $1 and $2 with .*.gkd, compare them if a
> +# single file is found by the globbing.
> +base1=`echo "$1" | sed '$s,\.[^.]*$,,'` gkd1=
> +for f in "$base1".*.gkd; do
> +  if test "x$gkd1" != x; then
> +    gkd1=
> +    break
> +  elif test -f "$f"; then
> +    gkd1=$f
> +  fi
> +done
> +base2=`echo "$2" | sed '$s,\.[^.]*$,,'` gkd2=
> +for f in "$base2".*.gkd; do
> +  if test "x$gkd2" != x; then
> +    gkd2=
> +    break
> +  elif test -f "$f"; then
> +    gkd2=$f
> +  fi
> +done
> +if test "x$gkd1" != x || test "x$gkd2" != x; then
> +  if cmp "${gkd1-/dev/null}" "${gkd2-/dev/null}"; then
>      :
>    else
>      status=$?
> diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
> index 374fc1e..5e65cf98 100644
> --- a/gcc/ada/gcc-interface/lang-specs.h
> +++ b/gcc/ada/gcc-interface/lang-specs.h
> @@ -34,17 +34,15 @@
>   %{!S:%{!c:%e-c or -S required for Ada}}\
>   gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
> -    %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b) -gnatd_A} \
> -    %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}}} \
> -    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} \
> +    %{fcompare-debug-second:-gnatd_A} \
> +    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
>      %{coverage:-fprofile-arcs -ftest-coverage} "
>  #if defined(TARGET_VXWORKS_RTP)
>     "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
>  #endif
>     "%{gnatea:-gnatez} %{g*&m*&f*} "
>     "%1 %{!S:%{o*:%w%*-gnatO}} \
> -    %i %{S:%W{o*}%{!o*:-o %b.s}} \
> +    %i %{S:%W{o*}%{!o*:-o %w%b.s}} \
>      %{gnatc*|gnats*: -o %j} %{-param*} \
>      %{!gnatc*:%{!gnats*:%(invoke_as)}}", 0, 0, 0},
>  
> @@ -53,9 +51,7 @@
>   %{!c:%e-c required for gnat2why}\
>   gnat1why %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
> -    %{o*:-auxbase-strip %*}%{!o*:-auxbase %b} \
> -    %{a} %{d*} \
> +    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
>      %{gnatea:-gnatez} %{g*&m*&f*} \
>      %1 %{o*:%w%*-gnatO} \
>      %i \
> @@ -66,9 +62,7 @@
>   %{!c:%e-c required for gnat2scil}\
>   gnat1scil %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
> -    %{o*:-auxbase-strip %*}%{!o*:-auxbase %b} \
> -    %{a} %{d*} \
> +    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
>      %{gnatea:-gnatez} %{g*&m*&f*} \
>      %1 %{o*:%w%*-gnatO} \
>      %i \
> diff --git a/gcc/ada/switch.adb b/gcc/ada/switch.adb
> index 7cdaa196..b6f4e00 100644
> --- a/gcc/ada/switch.adb
> +++ b/gcc/ada/switch.adb
> @@ -163,9 +163,9 @@ package body Switch is
>        return Is_Switch (Switch_Chars)
>          and then
>            (Switch_Chars (First .. Last) = "-param"        or else
> +           Switch_Chars (First .. Last) = "dumpdir"       or else
>             Switch_Chars (First .. Last) = "dumpbase"      or else
> -           Switch_Chars (First .. Last) = "auxbase-strip" or else
> -           Switch_Chars (First .. Last) = "auxbase");
> +           Switch_Chars (First .. Last) = "dumpbase-ext");
>     end Is_Internal_GCC_Switch;
>  
>     ---------------
> diff --git a/gcc/common.opt b/gcc/common.opt
> index e9b29fb..9c299cc 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -188,6 +188,12 @@ const char *main_input_basename
>  Variable
>  int main_input_baselength
>  
> +; The base name used for auxiliary output files.
> +; dump_base_name minus dump_base_ext.
> +
> +Variable
> +const char *aux_base_name
> +
>  ; Which options have been printed by --help.
>  Variable
>  char *help_printed
> @@ -252,10 +258,13 @@ Common Separate Alias(d)
>  Common Joined Alias(d)
>  
>  -dumpbase
> -Common Separate Alias(dumpbase)
> +Driver Common Separate Alias(dumpbase)
> +
> +-dumpbase-ext
> +Driver Common Separate Alias(dumpbase-ext)
>  
>  -dumpdir
> -Common Separate Alias(dumpdir)
> +Driver Common Separate Alias(dumpdir)
>  
>  -entry
>  Driver Separate Alias(e)
> @@ -840,12 +849,6 @@ Common Separate Var(aux_info_file_name)
>  aux-info=
>  Common Joined Alias(aux-info)
>  
> -auxbase
> -Common Separate RejectDriver Var(aux_base_name)
> -
> -auxbase-strip
> -Common Separate RejectDriver
> -
>  coverage
>  Driver
>  
> @@ -857,11 +860,15 @@ Common Joined
>  -d<letters>	Enable dumps from specific passes of the compiler.
>  
>  dumpbase
> -Common Separate Var(dump_base_name)
> +Driver Common Separate Var(dump_base_name)
>  -dumpbase <file>	Set the file basename to be used for dumps.
>  
> +dumpbase-ext
> +Driver Common Separate Var(dump_base_ext)
> +-dumpbase-ext .<ext>    Drop a trailing .<ext> from the dump basename to name auxiliary output files.
> +
>  dumpdir
> -Common Separate Var(dump_dir_name)
> +Driver Common Separate Var(dump_dir_name)
>  -dumpdir <dir>	Set the directory name to be used for dumps.
>  
>  dumpmachine
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index f2c805c..c679cdf 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -184,7 +184,9 @@ in the following sections.
>  @table @emph
>  @item Overall Options
>  @xref{Overall Options,,Options Controlling the Kind of Output}.
> -@gccoptlist{-c  -S  -E  -o @var{file}  -x @var{language}  @gol
> +@gccoptlist{-c  -S  -E  -o @var{file} @gol
> +-dumpbase @var{dumpbase}  -dumpbase-ext @var{auxdropsuf} @gol
> +-dumpdir @var{dumppfx}  -x @var{language}  @gol
>  -v  -###  --help@r{[}=@var{class}@r{[},@dots{}@r{]]}  --target-help  --version @gol
>  -pass-exit-codes  -pipe  -specs=@var{file}  -wrapper  @gol
>  @@@var{file}  -ffile-prefix-map=@var{old}=@var{new}  @gol
> @@ -1552,9 +1554,9 @@ Input files that don't require preprocessing are ignored.
>  @cindex output file option
>  @item -o @var{file}
>  @opindex o
> -Place output in file @var{file}.  This applies to whatever
> -sort of output is being produced, whether it be an executable file,
> -an object file, an assembler file or preprocessed C code.
> +Place the primary output in file @var{file}.  This applies to whatever
> +sort of output is being produced, whether it be an executable file, an
> +object file, an assembler file or preprocessed C code.
>  
>  If @option{-o} is not specified, the default is to put an executable
>  file in @file{a.out}, the object file for
> @@ -1563,6 +1565,314 @@ assembler file in @file{@var{source}.s}, a precompiled header file in
>  @file{@var{source}.@var{suffix}.gch}, and all preprocessed C source on
>  standard output.
>  
> +Though @option{-o} names only the primary output, it also affects the
> +naming of auxiliary and dump outputs.  See the examples below.  Unless
> +overridden, both auxiliary outputs and dump outputs are placed in the
> +same directory as the primary output.  In auxiliary outputs, the suffix
> +of the input file is replaced with that of the auxiliary output file
> +type; in dump outputs, the suffix of the dump file is appended to the
> +input file suffix.  In compilation commands, the base name of both
> +auxiliary and dump outputs is that of the primary output; in compile and
> +link commands, the primary output name, minus the executable suffix, is
> +combined with the input file name.  If both share the same base name,
> +disregarding the suffix, the result of the combination is that base
> +name, otherwise, they are concatenated, separated by a dash.
> +
> +@smallexample
> +gcc -c foo.c ...
> +@end smallexample
> +
> +will use @file{foo.o} as the primary output, and place aux outputs and
> +dumps next to it, e.g., aux file @file{foo.dwo} for
> +@option{-gsplit-dwarf}, and dump file @file{foo.c.???r.final} for
> +@option{-fdump-rtl-final}.
> +
> +If a non-linker output file is explicitly specified, aux and dump files
> +by default take the same base name:
> +
> +@smallexample
> +gcc -c foo.c -o dir/foobar.o ...
> +@end smallexample
> +
> +will name aux outputs @file{dir/foobar.*} and dump outputs
> +@file{dir/foobar.c.*}.
> +
> +A linker output will instead prefix aux and dump outputs:
> +
> +@smallexample
> +gcc foo.c bar.c -o dir/foobar ...
> +@end smallexample
> +
> +will generally name aux outputs @file{dir/foobar-foo.*} and
> +@file{dir/foobar-bar.*}, and dump outputs @file{dir/foobar-foo.c.*} and
> +@file{dir/foobar-bar.c.*}.
> +
> +The one exception to the above is when the executable shares the base
> +name with the single input:
> +
> +@smallexample
> +gcc foo.c -o dir/foo ...
> +@end smallexample
> +
> +in which case aux outputs are named @file{dir/foo.*} and dump outputs
> +named @file{dir/foo.c.*}.
> +
> +The location and the names of auxiliary and dump outputs can be adjusted
> +by the options @option{-dumpbase}, @option{-dumpbase-ext},
> +@option{-dumpdir}, @option{-save-temps=cwd}, and
> +@option{-save-temps=obj}.
> +
> +
> +@item -dumpbase @var{dumpbase}
> +@opindex dumpbase
> +This option sets the base name for auxiliary and dump output files.  It
> +does not affect the name of the primary output file.  Intermediate
> +outputs, when preserved, are not regarded as primary outputs, but as
> +auxiliary outputs:
> +
> +@smallexample
> +gcc -save-temps -S foo.c
> +@end smallexample
> +
> +saves the (no longer) temporary preprocessed file in @file{foo.i}, and
> +then compiles to the (implied) output file @file{foo.s}, whereas:
> +
> +@smallexample
> +gcc -save-temps -dumpbase save-foo -c foo.c
> +@end smallexample
> +
> +preprocesses to in @file{save-foo.i}, compiles to @file{save-foo.s} (now
> +an intermediate, thus auxiliary output), and then assembles to the
> +(implied) output file @file{foo.o}.
> +
> +Absent this option, dump and aux files take their names from the input
> +file, or from the (non-linker) output file, if one is explicitly
> +specified: dump output files (e.g. those requested by @option{-fdump-*}
> +options) with the input name suffix, and aux output files (those
> +requested by other non-dump options, e.g. @code{-save-temps},
> +@code{-gsplit-dwarf}, @code{-fcallgraph-info}) without it.
> +
> +Similar suffix differentiation of dump and aux outputs can be attained
> +for explicitly-given @option{-dumpbase basename.suf} by also specifying
> +@option{-dumpbase-ext .suf}.
> +
> +If @var{dumpbase} is explicitly specified with any directory component,
> +any @var{dumppfx} specification (e.g. @option{-dumpdir} or
> +@option{-save-temps=*}) is ignored, and instead of appending to it,
> +@var{dumpbase} fully overrides it:
> +
> +@smallexample
> +gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
> +  -dumpdir pfx- -save-temps=cwd ...
> +@end smallexample
> +
> +creates auxiliary and dump outputs named @file{alt/foo.*}, disregarding
> +@file{dir/} in @option{-o}, the @file{./} prefix implied by
> +@option{-save-temps=cwd}, and @file{pfx-} in @option{-dumpdir}.
> +
> +When @option{-dumpbase} is specified in a command that compiles multiple
> +inputs, or that compiles and then links, it may be combined with
> +@var{dumppfx}, as specified under @option{-dumpdir}.  Then, each input
> +file is compiled using the combined @var{dumppfx}, and default values
> +for @var{dumpbase} and @var{auxdropsuf} are computed for each input
> +file:
> +
> +@smallexample
> +gcc foo.c bar.c -c -dumpbase main ...
> +@end smallexample
> +
> +creates @file{foo.o} and @file{bar.o} as primary outputs, and avoids
> +overwriting the auxiliary and dump outputs by using the @var{dumpbase}
> +as a prefix, creating auxiliary and dump outputs named @file{main-foo.*}
> +and @file{main-bar.*}.
> +
> +An empty string specified as @var{dumpbase} avoids the influence of the
> +output basename in the naming of auxiliary and dump outputs during
> +compilation, computing default values :
> +
> +@smallexample
> +gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
> +@end smallexample
> +
> +will name aux outputs @file{dir/foo.*} and dump outputs
> +@file{dir/foo.c.*}.  Note how their basenames are taken from the input
> +name, but the directory still defaults to that of the output.
> +
> +The empty-string dumpbase does not prevent the use of the output
> +basename for outputs during linking:
> +
> +@smallexample
> +gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
> +@end smallexample
> +
> +The compilation of the source files will name auxiliary outputs
> +@file{dir/foo.*} and @file{dir/bar.*}, and dump outputs
> +@file{dir/foo.c.*} and @file{dir/bar.c.*}.  LTO recompilation during
> +linking will use @file{dir/foobar.} as the prefix for dumps and
> +auxiliary files.
> +
> +
> +@item -dumpbase-ext @var{auxdropsuf}
> +@opindex dumpbase-ext
> +When forming the name of an auxiliary (but not a dump) output file, drop
> +trailing @var{auxdropsuf} from @var{dumpbase} before appending any
> +suffixes.  If not specified, this option defaults to the suffix of a
> +default @var{dumpbase}, i.e., the suffix of the input file when
> +@option{-dumpbase} is not present in the command line, or @var{dumpbase}
> +is combined with @var{dumppfx}.
> +
> +@smallexample
> +gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
> +@end smallexample
> +
> +creates @file{dir/foo.o} as the main output, and generates auxiliary
> +outputs in @file{dir/x-foo.*}, taking the location of the primary
> +output, and dropping the @file{.c} suffix from the @var{dumpbase}.  Dump
> +outputs retain the suffix: @file{dir/x-foo.c.*}.
> +
> +This option is disregarded if it does not match the suffix of a
> +specified @var{dumpbase}, except as an alternative to the executable
> +suffix when appending the linker output base name to @var{dumppfx}, as
> +specified below:
> +
> +@smallexample
> +gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
> +@end smallexample
> +
> +creates @file{main.out} as the primary output, and avoids overwriting
> +the auxiliary and dump outputs by using the executable name minus
> +@var{auxdropsuf} as a prefix, creating auxiliary outputs named
> +@file{main-foo.*} and @file{main-bar.*} and dump outputs named
> +@file{main-foo.c.*} and @file{main-bar.c.*}.
> +
> +
> +@item -dumpdir @var{dumppfx}
> +@opindex dumpdir
> +When forming the name of an auxiliary or dump output file, use
> +@var{dumppfx} as a prefix:
> +
> +@smallexample
> +gcc -dumpdir pfx- -c foo.c ...
> +@end smallexample
> +
> +creates @file{foo.o} as the primary output, and auxiliary outputs named
> +@file{pfx-foo.*}, combining the given @var{dumppfx} with the default
> +@var{dumpbase} derived from the default primary output, derived in turn
> +from the input name.  Dump outputs also take the input name suffix:
> +@file{pfx-foo.c.*}.
> +
> +If @var{dumppfx} is to be used as a directory name, it must end with a
> +directory separator:
> +
> +@smallexample
> +gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
> +@end smallexample
> +
> +creates @file{obj/bar.o} as the primary output, and auxiliary outputs
> +named @file{dir/bar.*}, combining the given @var{dumppfx} with the
> +default @var{dumpbase} derived from the primary output name.  Dump
> +outputs also take the input name suffix: @file{dir/bar.c.*}.
> +
> +It defaults to the location of the output file; options
> +@option{-save-temps=cwd} and @option{-save-temps=obj} override this
> +default, just like an explicit @option{-dumpdir} option.  In case
> +multiple such options are given, the last one prevails:
> +
> +@smallexample
> +gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
> +@end smallexample
> +
> +outputs @file{foo.o}, with auxiliary outputs named @file{foo.*} because
> +@option{-save-temps=*} overrides the @var{dumppfx} given by the earlier
> +@option{-dumpdir} option.  It does not matter that @option{=obj} is the
> +default for @option{-save-temps}, nor that the output directory is
> +implicitly the current directory.  Dump outputs are named
> +@file{foo.c.*}.
> +
> +When compiling from multiple input files, if @option{-dumpbase} is
> +specified, @var{dumpbase}, minus a @var{auxdropsuf} suffix, and a dash
> +are appended to (or override, if containing any directory components) an
> +explicit or defaulted @var{dumppfx}, so that each of the multiple
> +compilations gets differently-named aux and dump outputs.
> +
> +@smallexample
> +gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
> +@end smallexample
> +
> +outputs auxiliary dumps to @file{dir/pfx-main-foo.*} and
> +@file{dir/pfx-main-bar.*}, appending @var{dumpbase}- to @var{dumppfx}.
> +Dump outputs retain the input file suffix: @file{dir/pfx-main-foo.c.*}
> +and @file{dir/pfx-main-bar.c.*}, respectively.  Contrast with the
> +single-input compilation:
> +
> +@smallexample
> +gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
> +@end smallexample
> +
> +that, applying @option{-dumpbase} to a single source, does not compute
> +and append a separate @var{dumpbase} per input file.  Its auxiliary and
> +dump outputs go in @file{dir/pfx-main.*}.
> +
> +When compiling and then linking from multiple input files, a defaulted
> +or explicitly specified @var{dumppfx} also undergoes the @var{dumpbase}-
> +transformation above (e.g. the compilation of @file{foo.c} and
> +@file{bar.c} above, but without @option{-c}).  If neither
> +@option{-dumpdir} nor @option{-dumpbase} are given, the linker output
> +base name, minus @var{auxdropsuf}, if specified, or the executable
> +suffix otherwise, plus a dash is appended to the default @var{dumppfx}
> +instead.  Note, however, that unlike earlier cases of linking:
> +
> +@smallexample
> +gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
> +@end smallexample
> +
> +does not append the output name @file{main} to @var{dumppfx}, because
> +@option{-dumpdir} is explicitly specified.  The goal is that the
> +explicitly-specified @var{dumppfx} may contain the specified output name
> +as part of the prefix, if desired; only an explicitly-specified
> +@option{-dumpbase} would be combined with it, in order to avoid simply
> +discarding a meaningful option.
> +
> +When compiling and then linking from a single input file, the linker
> +output base name will only be appended to the default @var{dumppfx} as
> +above if it does not share the base name with the single input file
> +name.  This has been covered in single-input linking cases above, but
> +not with an explicit @option{-dumpdir} that inhibits the combination,
> +even if overridden by @option{-save-temps=*}:
> +
> +@smallexample
> +gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
> +@end smallexample
> +
> +Auxiliary outputs are named @file{foo.*}, and dump outputs
> +@file{foo.c.*}, in the current working directory as ultimately requested
> +by @option{-save-temps=cwd}.
> +
> +Summing it all up for an intuitive though slightly imprecise data flow:
> +the primary output name is broken into a directory part and a basename
> +part; @var{dumppfx} is set to the former, unless overridden by
> +@option{-dumpdir} or @option{-save-temps=*}, and @var{dumpbase} is set
> +to the latter, unless overriden by @option{-dumpbase}.  If there are
> +multiple inputs or linking, this @var{dumpbase} may be combined with
> +@var{dumppfx} and taken from each input file.  Auxiliary output names
> +for each input are formed by combining @var{dumppfx}, @var{dumpbase}
> +minus suffix, and the auxiliary output suffix; dump output names are
> +only different in that the suffix from @var{dumpbase} is retained.
> +
> +When it comes to auxiliary and dump outputs created during LTO
> +recompilation, a combination of @var{dumppfx} and @var{dumpbase}, as
> +given or as derived from the linker output name but not from inputs,
> +even in cases in which this combination would not otherwise be used as
> +such, is passed down with a trailing period replacing the compiler-added
> +dash, if any, as a @option{-dumpdir} option to @command{lto-wrapper};
> +being involved in linking, this program does not normally get any
> +@option{-dumpbase} and @option{-dumpbase-ext}, and it ignores them.
> +
> +When running sub-compilers, @command{lto-wrapper} appends LTO stage
> +names to the received @var{dumppfx}, ensures it contains a directory
> +component so that it overrides any @option{-dumpdir}, and passes that as
> +@option{-dumpbase} to sub-compilers.
> +
>  @item -v
>  @opindex v
>  Print (on standard error output) the commands executed to run the stages
> @@ -15644,54 +15954,28 @@ computing CRC32).
>  The @var{string} should be different for every file you compile.
>  
>  @item -save-temps
> -@itemx -save-temps=cwd
>  @opindex save-temps
> -Store the usual ``temporary'' intermediate files permanently; place them
> -in the current directory and name them based on the source file.  Thus,
> -compiling @file{foo.c} with @option{-c -save-temps} produces files
> -@file{foo.i} and @file{foo.s}, as well as @file{foo.o}.  This creates a
> -preprocessed @file{foo.i} output file even though the compiler now
> -normally uses an integrated preprocessor.
> +Store the usual ``temporary'' intermediate files permanently; name them
> +as auxiliary output files, as specified described under
> +@option{-dumpbase} and @option{-dumpdir}.
>  
>  When used in combination with the @option{-x} command-line option,
> -@option{-save-temps} is sensible enough to avoid over writing an
> +@option{-save-temps} is sensible enough to avoid overwriting an
>  input source file with the same extension as an intermediate file.
>  The corresponding intermediate file may be obtained by renaming the
>  source file before using @option{-save-temps}.
>  
> -If you invoke GCC in parallel, compiling several different source
> -files that share a common base name in different subdirectories or the
> -same source file compiled for multiple output destinations, it is
> -likely that the different parallel compilers will interfere with each
> -other, and overwrite the temporary files.  For instance:
> -
> -@smallexample
> -gcc -save-temps -o outdir1/foo.o indir1/foo.c&
> -gcc -save-temps -o outdir2/foo.o indir2/foo.c&
> -@end smallexample
> -
> -may result in @file{foo.i} and @file{foo.o} being written to
> -simultaneously by both compilers.
> +@item -save-temps=cwd
> +@opindex save-temps=cwd
> +Equivalent to @option{-save-temps -dumpdir ./}.
>  
>  @item -save-temps=obj
>  @opindex save-temps=obj
> -Store the usual ``temporary'' intermediate files permanently.  If the
> -@option{-o} option is used, the temporary files are based on the
> -object file.  If the @option{-o} option is not used, the
> -@option{-save-temps=obj} switch behaves like @option{-save-temps}.
> -
> -For example:
> -
> -@smallexample
> -gcc -save-temps=obj -c foo.c
> -gcc -save-temps=obj -c bar.c -o dir/xbar.o
> -gcc -save-temps=obj foobar.c -o dir2/yfoobar
> -@end smallexample
> -
> -@noindent
> -creates @file{foo.i}, @file{foo.s}, @file{dir/xbar.i},
> -@file{dir/xbar.s}, @file{dir2/yfoobar.i}, @file{dir2/yfoobar.s}, and
> -@file{dir2/yfoobar.o}.
> +Equivalent to @option{-save-temps -dumpdir @file{outdir/}}, where
> +@file{outdir/} is the directory of the output file specified after the
> +@option{-o} option, including any directory separators.  If the
> +@option{-o} option is not used, the @option{-save-temps=obj} switch
> +behaves like @option{-save-temps=cwd}.
>  
>  @item -time@r{[}=@var{file}@r{]}
>  @opindex time
> @@ -15728,7 +16012,7 @@ can later tell what file was being compiled, and with which options.
>  Dump the final internal representation (RTL) to @var{file}.  If the
>  optional argument is omitted (or if @var{file} is @code{.}), the name
>  of the dump file is determined by appending @code{.gkd} to the
> -compilation output file name.
> +dump base name, see @option{-dumpbase}.
>  
>  @item -fcompare-debug@r{[}=@var{opts}@r{]}
>  @opindex fcompare-debug
> @@ -29903,17 +30187,24 @@ together or combine them with constant text in a single argument.
>  @item %%
>  Substitute one @samp{%} into the program name or argument.
>  
> +@item %"
> +Substitute an empty argument.
> +
>  @item %i
>  Substitute the name of the input file being processed.
>  
>  @item %b
> -Substitute the basename of the input file being processed.
> -This is the substring up to (and not including) the last period
> -and not including the directory.
> +Substitute the basename for outputs related with the input file being
> +processed.  This is often the substring up to (and not including) the
> +last period and not including the directory but, unless %w is active, it
> +expands to the basename for auxiliary outputs, which may be influenced
> +by an explicit output name, and by various other options that control
> +how auxiliary outputs are named.
>  
>  @item %B
>  This is the same as @samp{%b}, but include the file suffix (text after
> -the last period).
> +the last period).  Without %w, it expands to the basename for dump
> +outputs.
>  
>  @item %d
>  Marks the argument containing or following the @samp{%d} as a
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index 70b3fad..1882116 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -24333,9 +24333,8 @@ gen_producer_string (void)
>        case OPT_o:
>        case OPT_d:
>        case OPT_dumpbase:
> +      case OPT_dumpbase_ext:
>        case OPT_dumpdir:
> -      case OPT_auxbase:
> -      case OPT_auxbase_strip:
>        case OPT_quiet:
>        case OPT_version:
>        case OPT_v:
> diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
> index 4cc8a90..d844fa9 100644
> --- a/gcc/fortran/options.c
> +++ b/gcc/fortran/options.c
> @@ -838,8 +838,8 @@ gfc_get_option_string (void)
>          case OPT_o:
>          case OPT_d:
>          case OPT_dumpbase:
> +        case OPT_dumpbase_ext:
>          case OPT_dumpdir:
> -        case OPT_auxbase:
>          case OPT_quiet:
>          case OPT_version:
>          case OPT_fintrinsic_modules_path:
> @@ -864,8 +864,8 @@ gfc_get_option_string (void)
>          case OPT_o:
>          case OPT_d:
>          case OPT_dumpbase:
> +        case OPT_dumpbase_ext:
>          case OPT_dumpdir:
> -        case OPT_auxbase:
>          case OPT_quiet:
>          case OPT_version:
>          case OPT_fintrinsic_modules_path:
> diff --git a/gcc/gcc.c b/gcc/gcc.c
> index effc384f..cc04a20 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -270,12 +270,36 @@ static const char *target_sysroot_hdrs_suffix = 0;
>  static enum save_temps {
>    SAVE_TEMPS_NONE,		/* no -save-temps */
>    SAVE_TEMPS_CWD,		/* -save-temps in current directory */
> +  SAVE_TEMPS_DUMP,              /* -save-temps in dumpdir */
>    SAVE_TEMPS_OBJ		/* -save-temps in object directory */
>  } save_temps_flag;
>  
> -/* Output file to use to get the object directory for -save-temps=obj  */
> -static char *save_temps_prefix = 0;
> -static size_t save_temps_length = 0;
> +/* Set this iff the dumppfx implied by a -save-temps=* option is to
> +   override a -dumpdir option, if any.  */
> +static bool save_temps_overrides_dumpdir = false;
> +
> +/* -dumpdir, -dumpbase and -dumpbase-ext flags passed in, possibly
> +   rearranged as they are to be passed down, e.g., dumpbase and
> +   dumpbase_ext may be cleared if integrated with dumpdir or
> +   dropped.  */
> +static char *dumpdir, *dumpbase, *dumpbase_ext;
> +
> +/* Usually the length of the string in dumpdir.  However, during
> +   linking, it may be shortened to omit a driver-added trailing dash,
> +   by then replaced with a trailing period, that is still to be passed
> +   to sub-processes in -dumpdir, but not to be generally used in spec
> +   filename expansions.  See maybe_run_linker.  */
> +static size_t dumpdir_length = 0;
> +
> +/* Set if the last character in dumpdir is (or was) a dash that the
> +   driver added to dumpdir after dumpbase or linker output name.  */
> +static bool dumpdir_trailing_dash_added = false;
> +
> +/* Basename of dump and aux outputs, computed from dumpbase (given or
> +   derived from output name), to override input_basename in non-%w %b
> +   et al.  */
> +static char *outbase;
> +static size_t outbase_length = 0;
>  
>  /* The compiler version.  */
>  
> @@ -402,13 +426,16 @@ static const char *find_plugindir_spec_function (int, const char **);
>  static const char *print_asm_header_spec_function (int, const char **);
>  static const char *compare_debug_dump_opt_spec_function (int, const char **);
>  static const char *compare_debug_self_opt_spec_function (int, const char **);
> -static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
>  static const char *pass_through_libs_spec_func (int, const char **);
> -static const char *replace_extension_spec_func (int, const char **);
> +static const char *dumps_spec_func (int, const char **);
>  static const char *greater_than_spec_func (int, const char **);
>  static const char *debug_level_greater_than_spec_func (int, const char **);
>  static const char *find_fortran_preinclude_file (int, const char **);
>  static char *convert_white_space (char *);
> +static char *quote_spec (char *);
> +static char *quote_spec_arg (char *);
> +static bool not_actual_file_p (const char *);
> +
>  
>  /* The Specs Language
>  
> @@ -426,12 +453,19 @@ expanding these sequences; therefore, you can concatenate them together
>  or with constant text in a single argument.
>  
>   %%	substitute one % into the program name or argument.
> + %"     substitute an empty argument.
>   %i     substitute the name of the input file being processed.
> - %b     substitute the basename of the input file being processed.
> -	This is the substring up to (and not including) the last period
> -	and not including the directory unless -save-temps was specified
> -	to put temporaries in a different location.
> - %B	same as %b, but include the file suffix (text after the last period).
> + %b     substitute the basename for outputs related with the input file
> +	being processed.  This is often a substring of the input file name,
> +	up to (and not including) the last period but, unless %w is active,
> +	it is affected by the directory selected by -save-temps=*, by
> +	-dumpdir, and, in case of multiple compilations, even by -dumpbase
> +	and -dumpbase-ext and, in case of linking, by the linker output
> +	name.  When %w is active, it derives the main output name only from
> +	the input file base name; when it is not, it names aux/dump output
> +	file.
> + %B	same as %b, but include the input file suffix (text after the last
> +	period).
>   %gSUFFIX
>  	substitute a file name that has suffix SUFFIX and is chosen
>  	once per compilation, and mark the argument a la %d.  To reduce
> @@ -641,10 +675,10 @@ proper position among the other output files.  */
>  #define ASM_FINAL_SPEC \
>    "%{gsplit-dwarf: \n\
>         objcopy --extract-dwo \
> -	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> -	 %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
> +	 %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
> +	 %b.dwo \n\
>         objcopy --strip-dwo \
> -	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +	 %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
>      }"
>  #endif
>  
> @@ -1139,22 +1173,20 @@ static const char *cpp_options =
>  
>  /* This contains cpp options which are not passed when the preprocessor
>     output will be used by another program.  */
> -static const char *cpp_debug_options = "%{d*}";
> +static const char *cpp_debug_options = "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps()";
>  
>  /* NB: This is shared amongst all front-ends, except for Ada.  */
>  static const char *cc1_options =
>  "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
>   %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
> - %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
> - %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
> - %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
> + %1 %{!Q:-quiet} %(cpp_debug_options) %{m*} %{aux-info*}\
>   %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
>   %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
>   %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
>   %{-target-help:--target-help}\
>   %{-version:--version}\
>   %{-help=*:--help=%*}\
> - %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
> + %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}}\
>   %{fsyntax-only:-o %j} %{-param*}\
>   %{coverage:-fprofile-arcs -ftest-coverage}\
>   %{fprofile-arcs|fprofile-generate*|coverage:\
> @@ -1642,9 +1674,8 @@ static const struct spec_function static_spec_functions[] =
>    { "print-asm-header",		print_asm_header_spec_function },
>    { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
>    { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
> -  { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
>    { "pass-through-libs",	pass_through_libs_spec_func },
> -  { "replace-extension",	replace_extension_spec_func },
> +  { "dumps",                    dumps_spec_func },
>    { "gt",			greater_than_spec_func },
>    { "debug-level-gt",		debug_level_greater_than_spec_func },
>    { "fortran-preinclude-file",	find_fortran_preinclude_file},
> @@ -4140,7 +4171,8 @@ driver_handle_option (struct gcc_options *opts,
>        return true;
>  
>      case OPT_save_temps:
> -      save_temps_flag = SAVE_TEMPS_CWD;
> +      if (!save_temps_flag)
> +	save_temps_flag = SAVE_TEMPS_DUMP;
>        validated = true;
>        break;
>  
> @@ -4153,6 +4185,23 @@ driver_handle_option (struct gcc_options *opts,
>        else
>  	fatal_error (input_location, "%qs is an unknown %<-save-temps%> option",
>  		     decoded->orig_option_with_args_text);
> +      save_temps_overrides_dumpdir = true;
> +      break;
> +
> +    case OPT_dumpdir:
> +      free (dumpdir);
> +      dumpdir = xstrdup (arg);
> +      save_temps_overrides_dumpdir = false;
> +      break;
> +
> +    case OPT_dumpbase:
> +      free (dumpbase);
> +      dumpbase = xstrdup (arg);
> +      break;
> +
> +    case OPT_dumpbase_ext:
> +      free (dumpbase_ext);
> +      dumpbase_ext = xstrdup (arg);
>        break;
>  
>      case OPT_no_canonical_prefixes:
> @@ -4259,8 +4308,6 @@ driver_handle_option (struct gcc_options *opts,
>        arg = convert_filename (arg, ! have_c, 0);
>  #endif
>        output_file = arg;
> -      /* Save the output name in case -save-temps=obj was used.  */
> -      save_temps_prefix = xstrdup (arg);
>        /* On some systems, ld cannot handle "-o" without a space.  So
>  	 split the option from its argument.  */
>        save_switch ("-o", 1, &arg, validated, true);
> @@ -4303,6 +4350,19 @@ driver_handle_option (struct gcc_options *opts,
>    return true;
>  }
>  
> +/* Return true if F2 is F1 followed by a single suffix, i.e., by a
> +   period and additional characters other than a period.  */
> +
> +static inline bool
> +adds_single_suffix_p (const char *f2, const char *f1)
> +{
> +  size_t len = strlen (f1);
> +
> +  return (strncmp (f1, f2, len) == 0
> +	  && f2[len] == '.'
> +	  && strchr (f2 + len + 1, '.') == NULL);
> +}
> +
>  /* Put the driver's standard set of option handlers in *HANDLERS.  */
>  
>  static void
> @@ -4319,6 +4379,32 @@ set_option_handlers (struct cl_option_handlers *handlers)
>    handlers->handlers[2].mask = CL_TARGET;
>  }
>  
> +
> +/* Return the index into infiles for the single non-library
> +   non-lto-wpa input file, -1 if there isn't any, or -2 if there is
> +   more than one.  */
> +static inline int
> +single_input_file_index ()
> +{
> +  int ret = -1;
> +
> +  for (int i = 0; i < n_infiles; i++)
> +    {
> +      if (infiles[i].language
> +	  && (infiles[i].language[0] == '*'
> +	      || (flag_wpa
> +		  && strcmp (infiles[i].language, "lto") == 0)))
> +	continue;
> +
> +      if (ret != -1)
> +	return -2;
> +
> +      ret = i;
> +    }
> +
> +  return ret;
> +}
> +
>  /* Create the vector `switches' and its contents.
>     Store its length in `n_switches'.  */
>  
> @@ -4631,23 +4717,371 @@ process_command (unsigned int decoded_options_count,
>    if (output_file != NULL && output_file[0] == '\0')
>      fatal_error (input_location, "output filename may not be empty");
>  
> +  /* -dumpdir and -save-temps=* both specify the location of aux/dump
> +     outputs; the one that appears last prevails.  When compiling
> +     multiple sources, an explicit dumpbase (minus -ext) may be
> +     combined with an explicit or implicit dumpdir, whereas when
> +     linking, a specified or implied link output name (minus
> +     extension) may be combined with a prevailing -save-temps=* or an
> +     otherwise implied dumpdir, but not override a prevailing
> +     -dumpdir.  Primary outputs (e.g., linker output when linking
> +     without -o, or .i, .s or .o outputs when processing multiple
> +     inputs with -E, -S or -c, respectively) are NOT affected by these
> +     -save-temps=/-dump* options, always landing in the current
> +     directory and with the same basename as the input when an output
> +     name is not given, but when they're intermediate outputs, they
> +     are named like other aux outputs, so the options affect their
> +     location and name.
> +
> +     Here are some examples.  There are several more in the
> +     documentation of -o and -dump*, and some quite exhaustive tests
> +     in gcc.misc-tests/outputs.exp.
> +
> +     When compiling any number of sources, no -dump* nor
> +     -save-temps=*, all outputs in cwd without prefix:
> +
> +     # gcc -c b.c -gsplit-dwarf
> +     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
> +
> +     # gcc -c b.c d.c -gsplit-dwarf
> +     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
> +     && cc1 [-dumpdir ./] -dumpbase d.c -dumpbase-ext .c # d.o d.dwo
> +
> +     When compiling and linking, no -dump* nor -save-temps=*, .o
> +     outputs are temporary, aux outputs land in the dir of the output,
> +     prefixed with the basename of the linker output:
> +
> +     # gcc b.c d.c -o ab -gsplit-dwarf
> +     -> cc1 -dumpdir ab- -dumpbase b.c -dumpbase-ext .c # ab-b.dwo
> +     && cc1 -dumpdir ab- -dumpbase d.c -dumpbase-ext .c # ab-d.dwo
> +     && link ... -o ab
> +
> +     # gcc b.c d.c [-o a.out] -gsplit-dwarf
> +     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.dwo
> +     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.dwo
> +     && link ... [-o a.out]
> +
> +     When compiling and linking, a prevailing -dumpdir fully overrides
> +     the prefix of aux outputs given by the output name:
> +
> +     # gcc -dumpdir f b.c d.c -gsplit-dwarf [-o [dir/]whatever]
> +     -> cc1 -dumpdir f -dumpbase b.c -dumpbase-ext .c # fb.dwo
> +     && cc1 -dumpdir f -dumpbase d.c -dumpbase-ext .c # fd.dwo
> +     && link ... [-o whatever]
> +
> +     When compiling multiple inputs, an explicit -dumpbase is combined
> +     with -dumpdir, affecting aux outputs, but not the .o outputs:
> +
> +     # gcc -dumpdir f -dumpbase g- b.c d.c -gsplit-dwarf -c
> +     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # b.o fg-b.dwo
> +     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # d.o fg-d.dwo
> +
> +     When compiling and linking with -save-temps, the .o outputs that
> +     would have been temporary become aux outputs, so they get
> +     affected by -dump* flags:
> +
> +     # gcc -dumpdir f -dumpbase g- -save-temps b.c d.c
> +     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # fg-b.o
> +     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # fg-d.o
> +     && link
> +
> +     If -save-temps=* prevails over -dumpdir, however, the explicit
> +     -dumpdir is discarded, as if it wasn't there.  The basename of
> +     the implicit linker output, a.out or a.exe, becomes a- as the aux
> +     output prefix for all compilations:
> +
> +     # gcc [-dumpdir f] -save-temps=cwd b.c d.c
> +     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.o
> +     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.o
> +     && link
> +
> +     A single -dumpbase, applying to multiple inputs, overrides the
> +     linker output name, implied or explicit, as the aux output prefix:
> +
> +     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c
> +     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
> +     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
> +     && link
> +
> +     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c -o dir/h.out
> +     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
> +     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
> +     && link -o dir/h.out
> +
> +     Now, if the linker output is NOT overridden as a prefix, but
> +     -save-temps=* overrides implicit or explicit -dumpdir, the
> +     effective dump dir combines the dir selected by the -save-temps=*
> +     option with the basename of the specified or implied link output:
> +
> +     # gcc [-dumpdir f] -save-temps=cwd b.c d.c -o dir/h.out
> +     -> cc1 -dumpdir h- -dumpbase b.c -dumpbase-ext .c # h-b.o
> +     && cc1 -dumpdir h- -dumpbase d.c -dumpbase-ext .c # h-d.o
> +     && link -o dir/h.out
> +
> +     # gcc [-dumpdir f] -save-temps=obj b.c d.c -o dir/h.out
> +     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
> +     && cc1 -dumpdir dir/h- -dumpbase d.c -dumpbase-ext .c # dir/h-d.o
> +     && link -o dir/h.out
> +
> +     But then again, a single -dumpbase applying to multiple inputs
> +     gets used instead of the linker output basename in the combined
> +     dumpdir:
> +
> +     # gcc [-dumpdir f] -dumpbase g- -save-temps=obj b.c d.c -o dir/h.out
> +     -> cc1 -dumpdir dir/g- -dumpbase b.c -dumpbase-ext .c # dir/g-b.o
> +     && cc1 -dumpdir dir/g- -dumpbase d.c -dumpbase-ext .c # dir/g-d.o
> +     && link -o dir/h.out
> +
> +     With a single input being compiled, the output basename does NOT
> +     affect the dumpdir prefix.
> +
> +     # gcc -save-temps=obj b.c -gsplit-dwarf -c -o dir/b.o
> +     -> cc1 -dumpdir dir/ -dumpbase b.c -dumpbase-ext .c # dir/b.o dir/b.dwo
> +
> +     but when compiling and linking even a single file, it does:
> +
> +     # gcc -save-temps=obj b.c -o dir/h.out
> +     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
> +
> +     unless an explicit -dumpdir prevails:
> +
> +     # gcc -save-temps[=obj] -dumpdir g- b.c -o dir/h.out
> +     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
> +
> +  */
> +
> +  bool explicit_dumpdir = dumpdir;
> +
> +  if (!save_temps_overrides_dumpdir && explicit_dumpdir)
> +    {
> +      /* Do nothing.  */
> +    }
> +
>    /* If -save-temps=obj and -o name, create the prefix to use for %b.
>       Otherwise just make -save-temps=obj the same as -save-temps=cwd.  */
> -  if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL)
> +  else if (save_temps_flag != SAVE_TEMPS_CWD && output_file != NULL)
> +    {
> +      free (dumpdir);
> +      dumpdir = NULL;
> +      temp = lbasename (output_file);
> +      if (temp != output_file)
> +	dumpdir = xstrndup (output_file,
> +			    strlen (output_file) - strlen (temp));
> +    }
> +  else if (dumpdir)
> +    {
> +      free (dumpdir);
> +      dumpdir = NULL;
> +    }
> +
> +  if (save_temps_flag)
> +    save_temps_flag = SAVE_TEMPS_DUMP;
> +
> +  /* If there is any pathname component in an explicit -dumpbase, it
> +     overrides dumpdir entirely, so discard it right away.  Although
> +     the presence of an explicit -dumpdir matters for the driver, it
> +     shouldn't matter for other processes, that get all that's needed
> +     from the -dumpdir and -dumpbase always passed to them.  */
> +  if (dumpdir && dumpbase && lbasename (dumpbase) != dumpbase)
> +    {
> +      free (dumpdir);
> +      dumpdir = NULL;
> +    }
> +
> +  /* Check that dumpbase_ext matches the end of dumpbase, drop it
> +     otherwise.  */
> +  if (dumpbase_ext && dumpbase && *dumpbase)
> +    {
> +      int lendb = strlen (dumpbase);
> +      int lendbx = strlen (dumpbase_ext);
> +
> +      if (lendbx >= lendb
> +	  || strcmp (dumpbase + lendb - lendbx, dumpbase_ext) != 0)
> +	{
> +	  free (dumpbase_ext);
> +	  dumpbase_ext = NULL;
> +	}
> +    }
> +
> +  /* -dumpbase with multiple sources goes into dumpdir.  With a single
> +     source, it does only if linking and if dumpdir was not explicitly
> +     specified.  */
> +  if (dumpbase && *dumpbase
> +      && (single_input_file_index () == -2
> +	  || (!have_c && !explicit_dumpdir)))
> +    {
> +      char *prefix;
> +
> +      if (dumpbase_ext)
> +	/* We checked that they match above.  */
> +	dumpbase[strlen (dumpbase) - strlen (dumpbase_ext)] = '\0';
> +
> +      if (dumpdir)
> +	prefix = concat (dumpdir, dumpbase, "-", NULL);
> +      else
> +	prefix = concat (dumpbase, "-", NULL);
> +
> +      free (dumpdir);
> +      free (dumpbase);
> +      free (dumpbase_ext);
> +      dumpbase = dumpbase_ext = NULL;
> +      dumpdir = prefix;
> +      dumpdir_trailing_dash_added = true;
> +    }
> +
> +  /* If dumpbase was not brought into dumpdir but we're linking, bring
> +     output_file into dumpdir unless dumpdir was explicitly specified.
> +     The test for !explicit_dumpdir is further below, because we want
> +     to use the obase computation for a ghost outbase, passed to
> +     GCC_COLLECT_OPTIONS.  */
> +  else if (!have_c && (!explicit_dumpdir || (dumpbase && !*dumpbase)))
> +    {
> +      /* If we get here, we know dumpbase was not specified, or it was
> +	 specified as an empty string.  If it was anything else, it
> +	 would have combined with dumpdir above, because the condition
> +	 for dumpbase to be used when present is broader than the
> +	 condition that gets us here.  */
> +      gcc_assert (!dumpbase || !*dumpbase);
> +
> +      const char *obase;
> +      char *tofree = NULL;
> +      if (!output_file || not_actual_file_p (output_file))
> +	obase = "a";
> +      else
> +	{
> +	  obase = lbasename (output_file);
> +	  size_t blen = strlen (obase), xlen;
> +	  /* Drop the suffix if it's dumpbase_ext, if given,
> +	     otherwise .exe or the target executable suffix, or if the
> +	     output was explicitly named a.out, but not otherwise.  */
> +	  if (dumpbase_ext
> +	      ? (blen > (xlen = strlen (dumpbase_ext))
> +		 && strcmp ((temp = (obase + blen - xlen)),
> +			    dumpbase_ext) == 0)
> +	      : ((temp = strrchr (obase + 1, '.'))
> +		 && (xlen = strlen (temp))
> +		 && (strcmp (temp, ".exe") == 0
> +#if HAVE_TARGET_EXECUTABLE_SUFFIX
> +		     || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
> +#endif
> +		     || strcmp (obase, "a.out") == 0)))
> +	    {
> +	      tofree = xstrndup (obase, blen - xlen);
> +	      obase = tofree;
> +	    }
> +	}
> +
> +      /* We wish to save this basename to the -dumpdir passed through
> +	 GCC_COLLECT_OPTIONS within maybe_run_linker, for e.g. LTO,
> +	 but we do NOT wish to add it to e.g. %b, so we keep
> +	 outbase_length as zero.  */
> +      gcc_assert (!outbase);
> +      outbase_length = 0;
> +
> +      /* If we're building [dir1/]foo[.exe] out of a single input
> +	 [dir2/]foo.c that shares the same basename, dump to
> +	 [dir2/]foo.c.* rather than duplicating the basename into
> +	 [dir2/]foo-foo.c.*.  */
> +      int idxin;
> +      if (dumpbase
> +	  || ((idxin = single_input_file_index ()) >= 0
> +	      && adds_single_suffix_p (lbasename (infiles[idxin].name),
> +				       obase)))
> +	{
> +	  if (obase == tofree)
> +	    outbase = tofree;
> +	  else
> +	    {
> +	      outbase = xstrdup (obase);
> +	      free (tofree);
> +	    }
> +	  obase = tofree = NULL;
> +	}
> +      else
> +	{
> +	  if (dumpdir)
> +	    {
> +	      char *p = concat (dumpdir, obase, "-", NULL);
> +	      free (dumpdir);
> +	      dumpdir = p;
> +	    }
> +	  else
> +	    dumpdir = concat (obase, "-", NULL);
> +
> +	  dumpdir_trailing_dash_added = true;
> +
> +	  free (tofree);
> +	  obase = tofree = NULL;
> +	}
> +
> +      if (!explicit_dumpdir || dumpbase)
> +	{
> +	  /* Absent -dumpbase and present -dumpbase-ext have been applied
> +	     to the linker output name, so compute fresh defaults for each
> +	     compilation.  */
> +	  free (dumpbase_ext);
> +	  dumpbase_ext = NULL;
> +	}
> +    }
> +
> +  /* Now, if we're compiling, or if we haven't used the dumpbase
> +     above, then outbase (%B) is derived from dumpbase, if given, or
> +     from the output name, given or implied.  We can't precompute
> +     implied output names, but that's ok, since they're derived from
> +     input names.  Just make sure we skip this if dumpbase is the
> +     empty string: we want to use input names then, so don't set
> +     outbase.  */
> +  if ((dumpbase || have_c)
> +      && !(dumpbase && !*dumpbase))
>      {
> -      save_temps_length = strlen (save_temps_prefix);
> -      temp = strrchr (lbasename (save_temps_prefix), '.');
> -      if (temp)
> +      gcc_assert (!outbase);
> +
> +      if (dumpbase)
> +	{
> +	  gcc_assert (single_input_file_index () != -2);
> +	  /* We do not want lbasename here; dumpbase with dirnames
> +	     overrides dumpdir entirely, even if dumpdir is
> +	     specified.  */
> +	  if (dumpbase_ext)
> +	    /* We've already checked above that the suffix matches.  */
> +	    outbase = xstrndup (dumpbase,
> +				strlen (dumpbase) - strlen (dumpbase_ext));
> +	  else
> +	    outbase = xstrdup (dumpbase);
> +	}
> +      else if (output_file && !not_actual_file_p (output_file))
>  	{
> -	  save_temps_length -= strlen (temp);
> -	  save_temps_prefix[save_temps_length] = '\0';
> +	  outbase = xstrdup (lbasename (output_file));
> +	  char *p = strrchr (outbase + 1, '.');
> +	  if (p)
> +	    *p = '\0';
>  	}
>  
> +      if (outbase)
> +	outbase_length = strlen (outbase);
>      }
> -  else if (save_temps_prefix != NULL)
> +
> +  /* If there is any pathname component in an explicit -dumpbase, do
> +     not use dumpdir, but retain it to pass it on to the compiler.  */
> +  if (dumpdir)
> +    dumpdir_length = strlen (dumpdir);
> +  else
> +    dumpdir_length = 0;
> +
> +  /* Check that dumpbase_ext, if still present, still matches the end
> +     of dumpbase, if present, and drop it otherwise.  We only retained
> +     it above when dumpbase was absent to maybe use it to drop the
> +     extension from output_name before combining it with dumpdir.  */
> +  if (dumpbase_ext)
>      {
> -      free (save_temps_prefix);
> -      save_temps_prefix = NULL;
> +      if (!dumpbase)
> +	{
> +	  free (dumpbase_ext);
> +	  dumpbase_ext = NULL;
> +	}
> +      else
> +	gcc_assert (strcmp (dumpbase + strlen (dumpbase)
> +			    - strlen (dumpbase_ext), dumpbase_ext) == 0);
>      }
>  
>    if (save_temps_flag && use_pipes)
> @@ -4843,6 +5277,28 @@ set_collect_gcc_options (void)
>  	  obstack_grow (&collect_obstack, "'", 1);
>  	}
>      }
> +
> +  if (dumpdir)
> +    {
> +      if (!first_time)
> +	obstack_grow (&collect_obstack, " ", 1);
> +      first_time = FALSE;
> +
> +      obstack_grow (&collect_obstack, "'-dumpdir' '", 12);
> +      const char *p, *q;
> +
> +      q = dumpdir;
> +      while ((p = strchr (q, '\'')))
> +	{
> +	  obstack_grow (&collect_obstack, q, p - q);
> +	  obstack_grow (&collect_obstack, "'\\''", 4);
> +	  q = ++p;
> +	}
> +      obstack_grow (&collect_obstack, q, strlen (q));
> +
> +      obstack_grow (&collect_obstack, "'", 1);
> +    }
> +
>    obstack_grow (&collect_obstack, "\0", 1);
>    xputenv (XOBFINISH (&collect_obstack, char *));
>  }
> @@ -5333,22 +5789,33 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>  	    fatal_error (input_location, "spec %qs invalid", spec);
>  
>  	  case 'b':
> -	    if (save_temps_length)
> -	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
> -	    else
> +	    /* Don't use %b in the linker command.  */
> +	    gcc_assert (suffixed_basename_length);
> +	    if (!this_is_output_file && dumpdir_length)
> +	      obstack_grow (&obstack, dumpdir, dumpdir_length);
> +	    if (this_is_output_file || !outbase_length)
>  	      obstack_grow (&obstack, input_basename, basename_length);
> +	    else
> +	      obstack_grow (&obstack, outbase, outbase_length);
>  	    if (compare_debug < 0)
>  	      obstack_grow (&obstack, ".gk", 3);
>  	    arg_going = 1;
>  	    break;
>  
>  	  case 'B':
> -	    if (save_temps_length)
> -	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
> +	    /* Don't use %B in the linker command.  */
> +	    gcc_assert (suffixed_basename_length);
> +	    if (!this_is_output_file && dumpdir_length)
> +	      obstack_grow (&obstack, dumpdir, dumpdir_length);
> +	    if (this_is_output_file || !outbase_length)
> +	      obstack_grow (&obstack, input_basename, basename_length);
>  	    else
> -	      obstack_grow (&obstack, input_basename, suffixed_basename_length);
> +	      obstack_grow (&obstack, outbase, outbase_length);
>  	    if (compare_debug < 0)
>  	      obstack_grow (&obstack, ".gk", 3);
> +	    obstack_grow (&obstack, input_basename + basename_length,
> +			  suffixed_basename_length - basename_length);
> +
>  	    arg_going = 1;
>  	    break;
>  
> @@ -5501,42 +5968,44 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>  		    suffix_length += 3;
>  		  }
>  
> -		/* If -save-temps=obj and -o were specified, use that for the
> +		/* If -save-temps was specified, use that for the
>  		   temp file.  */
> -		if (save_temps_length)
> -		  {
> -		    char *tmp;
> -		    temp_filename_length
> -		      = save_temps_length + suffix_length + 1;
> -		    tmp = (char *) alloca (temp_filename_length);
> -		    memcpy (tmp, save_temps_prefix, save_temps_length);
> -		    memcpy (tmp + save_temps_length, suffix, suffix_length);
> -		    tmp[save_temps_length + suffix_length] = '\0';
> -		    temp_filename = save_string (tmp, save_temps_length
> -						      + suffix_length);
> -		    obstack_grow (&obstack, temp_filename,
> -				  temp_filename_length);
> -		    arg_going = 1;
> -		    delete_this_arg = 0;
> -		    break;
> -		  }
> -
> -		/* If the gcc_input_filename has the same suffix specified
> -		   for the %g, %u, or %U, and -save-temps is specified,
> -		   we could end up using that file as an intermediate
> -		   thus clobbering the user's source file (.e.g.,
> -		   gcc -save-temps foo.s would clobber foo.s with the
> -		   output of cpp0).  So check for this condition and
> -		   generate a temp file as the intermediate.  */
> -
>  		if (save_temps_flag)
>  		  {
>  		    char *tmp;
> -		    temp_filename_length = basename_length + suffix_length + 1;
> +		    bool adjusted_suffix = false;
> +		    if (suffix_length
> +			&& !outbase_length && !basename_length
> +			&& !dumpdir_trailing_dash_added)
> +		      {
> +			adjusted_suffix = true;
> +			suffix++;
> +			suffix_length--;
> +		      }
> +		    temp_filename_length
> +		      = dumpdir_length + suffix_length + 1;
> +		    if (!outbase_length)
> +		      temp_filename_length += basename_length;
> +		    else
> +		      temp_filename_length += outbase_length;
>  		    tmp = (char *) alloca (temp_filename_length);
> -		    memcpy (tmp, input_basename, basename_length);
> -		    memcpy (tmp + basename_length, suffix, suffix_length);
> -		    tmp[basename_length + suffix_length] = '\0';
> +		    if (dumpdir_length)
> +		      memcpy (tmp, dumpdir, dumpdir_length);
> +		    if (!outbase_length)
> +		      memcpy (tmp + dumpdir_length, input_basename,
> +			      basename_length);
> +		    else
> +		      memcpy (tmp + dumpdir_length, outbase,
> +			      outbase_length);
> +		    memcpy (tmp + temp_filename_length - suffix_length - 1,
> +			    suffix, suffix_length);
> +		    if (adjusted_suffix)
> +		      {
> +			adjusted_suffix = false;
> +			suffix--;
> +			suffix_length++;
> +		      }
> +		    tmp[temp_filename_length - 1] = '\0';
>  		    temp_filename = tmp;
>  
>  		    if (filename_cmp (temp_filename, gcc_input_filename) != 0)
> @@ -6047,6 +6516,14 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>  	    }
>  	    break;
>  
> +	  case '"':
> +	    /* End a previous argument, if there is one, then issue an
> +	       empty argument.  */
> +	    end_going_arg ();
> +	    arg_going = 1;
> +	    end_going_arg ();
> +	    break;
> +
>  	  default:
>  	    error ("spec failure: unrecognized spec option %qc", c);
>  	    break;
> @@ -6057,6 +6534,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>  	/* Backslash: treat next character as ordinary.  */
>  	c = *p++;
>  
> +	/* When adding more cases that previously matched default, make
> +	   sure to adjust quote_spec_char_p as well.  */
> +
>  	/* Fall through.  */
>        default:
>  	/* Ordinary character: put it into the current argument.  */
> @@ -8262,6 +8742,40 @@ driver::maybe_run_linker (const char *argv0) const
>      if (explicit_link_files[i] || outfiles[i] != NULL)
>        num_linker_inputs++;
>  
> +  /* Arrange for temporary file names created during linking to take
> +     on names related with the linker output rather than with the
> +     inputs when appropriate.  */
> +  if (outbase && *outbase)
> +    {
> +      if (dumpdir)
> +	{
> +	  char *tofree = dumpdir;
> +	  gcc_checking_assert (strlen (dumpdir) == dumpdir_length);
> +	  dumpdir = concat (dumpdir, outbase, ".", NULL);
> +	  free (tofree);
> +	}
> +      else
> +	dumpdir = concat (outbase, ".", NULL);
> +      dumpdir_length += strlen (outbase) + 1;
> +      dumpdir_trailing_dash_added = true;
> +    }
> +  else if (dumpdir_trailing_dash_added)
> +    {
> +      gcc_assert (dumpdir[dumpdir_length - 1] == '-');
> +      dumpdir[dumpdir_length - 1] = '.';
> +    }
> +
> +  if (dumpdir_trailing_dash_added)
> +    {
> +      gcc_assert (dumpdir_length > 0);
> +      gcc_assert (dumpdir[dumpdir_length - 1] == '.');
> +      dumpdir_length--;
> +    }
> +
> +  free (outbase);
> +  input_basename = outbase = NULL;
> +  outbase_length = suffixed_basename_length = basename_length = 0;
> +
>    /* Run ld to link all the compiler output files.  */
>  
>    if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
> @@ -9732,7 +10246,7 @@ compare_debug_dump_opt_spec_function (int arg,
>    do_spec_1 (" ", 0, NULL);
>  
>    if (argbuf.length () > 0
> -      && strcmp (argv[argbuf.length () - 1], "."))
> +      && strcmp (argv[argbuf.length () - 1], ".") != 0)
>      {
>        if (!compare_debug)
>  	return NULL;
> @@ -9742,25 +10256,22 @@ compare_debug_dump_opt_spec_function (int arg,
>      }
>    else
>      {
> -      const char *ext = NULL;
> -
>        if (argbuf.length () > 0)
> -	{
> -	  do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}", NULL);
> -	  ext = ".gkd";
> -	}
> +	do_spec_2 ("%B.gkd", NULL);
>        else if (!compare_debug)
>  	return NULL;
>        else
> -	do_spec_2 ("%g.gkd", NULL);
> +	do_spec_2 ("%{!save-temps*:%g.gkd}%{save-temps*:%B.gkd}", NULL);
>  
>        do_spec_1 (" ", 0, NULL);
>  
>        gcc_assert (argbuf.length () > 0);
>  
> -      name = concat (argbuf.last (), ext, NULL);
> +      name = xstrdup (argbuf.last ());
>  
> -      ret = concat ("-fdump-final-insns=", name, NULL);
> +      char *arg = quote_spec (xstrdup (name));
> +      ret = concat ("-fdump-final-insns=", arg, NULL);
> +      free (arg);
>      }
>  
>    which = compare_debug < 0;
> @@ -9787,8 +10298,6 @@ compare_debug_dump_opt_spec_function (int arg,
>    return ret;
>  }
>  
> -static const char *debug_auxbase_opt;
> -
>  /* %:compare-debug-self-opt spec function.  Expands to the options
>      that are to be passed in the second compilation of
>      compare-debug.  */
> @@ -9804,16 +10313,6 @@ compare_debug_self_opt_spec_function (int arg,
>    if (compare_debug >= 0)
>      return NULL;
>  
> -  do_spec_2 ("%{c|S:%{o*:%*}}", NULL);
> -  do_spec_1 (" ", 0, NULL);
> -
> -  if (argbuf.length () > 0)
> -    debug_auxbase_opt = concat ("-auxbase-strip ",
> -				argbuf.last (),
> -				NULL);
> -  else
> -    debug_auxbase_opt = NULL;
> -
>    return concat ("\
>  %<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
>  %<fdump-final-insns=* -w -S -o %j \
> @@ -9821,50 +10320,6 @@ compare_debug_self_opt_spec_function (int arg,
>  ", compare_debug_opt, NULL);
>  }
>  
> -/* %:compare-debug-auxbase-opt spec function.  Expands to the auxbase
> -    options that are to be passed in the second compilation of
> -    compare-debug.  It expects, as an argument, the basename of the
> -    current input file name, with the .gk suffix appended to it.  */
> -
> -static const char *
> -compare_debug_auxbase_opt_spec_function (int arg,
> -					 const char **argv)
> -{
> -  char *name;
> -  int len;
> -
> -  if (arg == 0)
> -    fatal_error (input_location,
> -		 "too few arguments to %%:compare-debug-auxbase-opt");
> -
> -  if (arg != 1)
> -    fatal_error (input_location,
> -		 "too many arguments to %%:compare-debug-auxbase-opt");
> -
> -  if (compare_debug >= 0)
> -    return NULL;
> -
> -  len = strlen (argv[0]);
> -  if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
> -    fatal_error (input_location, "argument to %%:compare-debug-auxbase-opt "
> -		 "does not end in %<.gk%>");
> -
> -  if (debug_auxbase_opt)
> -    return debug_auxbase_opt;
> -
> -#define OPT "-auxbase "
> -
> -  len -= 3;
> -  name = (char*) xmalloc (sizeof (OPT) + len);
> -  memcpy (name, OPT, sizeof (OPT) - 1);
> -  memcpy (name + sizeof (OPT) - 1, argv[0], len);
> -  name[sizeof (OPT) - 1 + len] = '\0';
> -
> -#undef OPT
> -
> -  return name;
> -}
> -
>  /* %:pass-through-libs spec function.  Finds all -l options and input
>     file names in the lib spec passed to it, and makes a list of them
>     prepended with the plugin option to cause them to be passed through
> @@ -9908,34 +10363,105 @@ pass_through_libs_spec_func (int argc, const char **argv)
>    return prepended;
>  }
>  
> -/* %:replace-extension spec function.  Replaces the extension of the
> -   first argument with the second argument.  */
> +static bool
> +not_actual_file_p (const char *name)
> +{
> +  return (strcmp (name, "-") == 0
> +	  || strcmp (output_file, HOST_BIT_BUCKET) == 0);
> +}
>  
> +/* %:dumps spec function.  Take an optional argument that overrides
> +   the default extension for -dumpbase and -dumpbase-ext.
> +   Return -dumpdir, -dumpbase and -dumpbase-ext, if needed.  */
>  const char *
> -replace_extension_spec_func (int argc, const char **argv)
> +dumps_spec_func (int argc, const char **argv ATTRIBUTE_UNUSED)
>  {
> -  char *name;
> +  const char *ext = dumpbase_ext;
>    char *p;
> -  char *result;
> -  int i;
>  
> -  if (argc != 2)
> -    fatal_error (input_location, "too few arguments to %%:replace-extension");
> +  char *args[3] = { NULL, NULL, NULL };
> +  int nargs = 0;
>  
> -  name = xstrdup (argv[0]);
> +  /* Do not compute a default for -dumpbase-ext when -dumpbase was
> +     given explicitly.  */
> +  if (dumpbase && *dumpbase && !ext)
> +    ext = "";
>  
> -  for (i = strlen (name) - 1; i >= 0; i--)
> -    if (IS_DIR_SEPARATOR (name[i]))
> -      break;
> +  if (argc == 1)
> +    {
> +      /* Do not override the explicitly-specified -dumpbase-ext with
> +	 the specs-provided overrider.  */
> +      if (!ext)
> +	ext = argv[0];
> +    }
> +  else if (argc != 0)
> +    fatal_error (input_location, "too many arguments for %%:dumps");
>  
> -  p = strrchr (name + i + 1, '.');
> -  if (p != NULL)
> -      *p = '\0';
> +  if (dumpdir)
> +    {
> +      p = quote_spec_arg (xstrdup (dumpdir));
> +      args[nargs++] = concat (" -dumpdir ", p, NULL);
> +      free (p);
> +    }
>  
> -  result = concat (name, argv[1], NULL);
> +  if (!ext)
> +    ext = input_basename + basename_length;
>  
> -  free (name);
> -  return result;
> +  /* Use the precomputed outbase, or compute dumpbase from
> +     input_basename, just like %b would.  */
> +  char *base;
> +
> +  if (dumpbase && *dumpbase)
> +    {
> +      base = xstrdup (dumpbase);
> +      p = base + outbase_length;
> +      gcc_checking_assert (strncmp (base, outbase, outbase_length) == 0);
> +      gcc_checking_assert (strcmp (p, ext) == 0);
> +    }
> +  else if (outbase_length)
> +    {
> +      base = xstrndup (outbase, outbase_length);
> +      p = NULL;
> +    }
> +  else
> +    {
> +      base = xstrndup (input_basename, suffixed_basename_length);
> +      p = base + basename_length;
> +    }
> +
> +  if (compare_debug < 0 || !p || strcmp (p, ext) != 0)
> +    {
> +      if (p)
> +	*p = '\0';
> +
> +      const char *gk;
> +      if (compare_debug < 0)
> +	gk = ".gk";
> +      else
> +	gk = "";
> +
> +      p = concat (base, gk, ext, NULL);
> +
> +      free (base);
> +      base = p;
> +    }
> +
> +  base = quote_spec_arg (base);
> +  args[nargs++] = concat (" -dumpbase ", base, NULL);
> +  free (base);
> +
> +  if (*ext)
> +    {
> +      p = quote_spec_arg (xstrdup (ext));
> +      args[nargs++] = concat (" -dumpbase-ext ", p, NULL);
> +      free (p);
> +    }
> +
> +  const char *ret = concat (args[0], args[1], args[2], NULL);
> +  while (nargs > 0)
> +    free (args[--nargs]);
> +
> +  return ret;
>  }
>  
>  /* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
> @@ -10041,6 +10567,44 @@ find_fortran_preinclude_file (int argc, const char **argv)
>    return result;
>  }
>  
> +/* If any character in ORIG fits QUOTE_P (_, P), reallocate the string
> +   so as to precede every one of them with a backslash.  Return the
> +   original string or the reallocated one.  */
> +
> +static inline char *
> +quote_string (char *orig, bool (*quote_p)(char, void *), void *p)
> +{
> +  int len, number_of_space = 0;
> +
> +  for (len = 0; orig[len]; len++)
> +    if (quote_p (orig[len], p))
> +      number_of_space++;
> +
> +  if (number_of_space)
> +    {
> +      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
> +      int j, k;
> +      for (j = 0, k = 0; j <= len; j++, k++)
> +	{
> +	  if (quote_p (orig[j], p))
> +	    new_spec[k++] = '\\';
> +	  new_spec[k] = orig[j];
> +	}
> +      free (orig);
> +      return new_spec;
> +    }
> +  else
> +    return orig;
> +}
> +
> +/* Return true iff C is any of the characters convert_white_space
> +   should quote.  */
> +
> +static inline bool
> +whitespace_to_convert_p (char c, void *)
> +{
> +  return (c == ' ' || c == '\t');
> +}
>  
>  /* Insert backslash before spaces in ORIG (usually a file path), to 
>     avoid being broken by spec parser.
> @@ -10068,26 +10632,50 @@ find_fortran_preinclude_file (int argc, const char **argv)
>  static char *
>  convert_white_space (char *orig)
>  {
> -  int len, number_of_space = 0;
> +  return quote_string (orig, whitespace_to_convert_p, NULL);
> +}
>  
> -  for (len = 0; orig[len]; len++)
> -    if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
> +/* Return true iff C matches any of the spec active characters.  */
> +static inline bool
> +quote_spec_char_p (char c, void *)
> +{
> +  switch (c)
> +    {
> +    case ' ':
> +    case '\t':
> +    case '\n':
> +    case '|':
> +    case '%':
> +    case '\\':
> +      return true;
>  
> -  if (number_of_space)
> +    default:
> +      return false;
> +    }
> +}
> +
> +/* Like convert_white_space, but deactivate all active spec chars by
> +   quoting them.  */
> +
> +static inline char *
> +quote_spec (char *orig)
> +{
> +  return quote_string (orig, quote_spec_char_p, NULL);
> +}
> +
> +/* Like quote_spec, but also turn an empty string into the spec for an
> +   empty argument.  */
> +
> +static inline char *
> +quote_spec_arg (char *orig)
> +{
> +  if (!*orig)
>      {
> -      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
> -      int j, k;
> -      for (j = 0, k = 0; j <= len; j++, k++)
> -	{
> -	  if (orig[j] == ' ' || orig[j] == '\t')
> -	    new_spec[k++] = '\\';
> -	  new_spec[k] = orig[j];
> -	}
>        free (orig);
> -      return new_spec;
> -  }
> -  else
> -    return orig;
> +      return xstrdup ("%\"");
> +    }
> +
> +  return quote_spec (orig);
>  }
>  
>  /* Restore all state within gcc.c to the initial state, so that the driver
> @@ -10124,8 +10712,14 @@ driver::finalize ()
>    target_sysroot_suffix = 0;
>    target_sysroot_hdrs_suffix = 0;
>    save_temps_flag = SAVE_TEMPS_NONE;
> -  save_temps_prefix = 0;
> -  save_temps_length = 0;
> +  save_temps_overrides_dumpdir = false;
> +  dumpdir_trailing_dash_added = false;
> +  free (dumpdir);
> +  free (dumpbase);
> +  free (dumpbase_ext);
> +  free (outbase);
> +  dumpdir = dumpbase = dumpbase_ext = outbase = NULL;
> +  dumpdir_length = outbase_length = 0;
>    spec_machine = DEFAULT_TARGET_MACHINE;
>    greatest_status = 1;
>  
> @@ -10264,8 +10858,6 @@ driver::finalize ()
>    mdswitches = NULL;
>    n_mdswitches = 0;
>  
> -  debug_auxbase_opt = NULL;
> -
>    used_arg.finalize ();
>  }
>  
> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> index fe8f292..ed076e3 100644
> --- a/gcc/lto-wrapper.c
> +++ b/gcc/lto-wrapper.c
> @@ -125,7 +125,7 @@ maybe_unlink (const char *file)
>  }
>  
>  /* Template of LTRANS dumpbase suffix.  */
> -#define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
> +#define DUMPBASE_SUFFIX "ltrans18446744073709551615"
>  
>  /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
>     environment.  */
> @@ -1081,12 +1081,7 @@ debug_objcopy (const char *infile, bool rename)
>      }
>  
>    if (save_temps)
> -    {
> -      outfile = (char *) xmalloc (strlen (orig_infile)
> -				  + sizeof (".debug.temp.o") + 1);
> -      strcpy (outfile, orig_infile);
> -      strcat (outfile, ".debug.temp.o");
> -    }
> +    outfile = concat (orig_infile, ".debug.temp.o", NULL);
>    else
>      outfile = make_temp_file (".debug.temp.o");
>    errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err, rename);
> @@ -1271,6 +1266,8 @@ run_gcc (unsigned argc, char *argv[])
>    bool linker_output_rel = false;
>    bool skip_debug = false;
>    unsigned n_debugobj;
> +  const char *dumppfx = NULL, *incoming_dumppfx = NULL;
> +  static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
>  
>    /* Get the driver and options.  */
>    collect_gcc = getenv ("COLLECT_GCC");
> @@ -1362,6 +1359,10 @@ run_gcc (unsigned argc, char *argv[])
>  	  linker_output = option->arg;
>  	  break;
>  
> +	  /* We don't have to distinguish between -save-temps=* and
> +	     -save-temps, -dumpdir already carries that
> +	     information.  */
> +	case OPT_save_temps_:
>  	case OPT_save_temps:
>  	  save_temps = 1;
>  	  break;
> @@ -1407,6 +1408,10 @@ run_gcc (unsigned argc, char *argv[])
>  	  skip_debug = option->arg && !strcmp (option->arg, "0");
>  	  break;
>  
> +	case OPT_dumpdir:
> +	  incoming_dumppfx = dumppfx = option->arg;
> +	  break;
> +
>  	default:
>  	  break;
>  	}
> @@ -1439,32 +1444,50 @@ run_gcc (unsigned argc, char *argv[])
>        jobserver = 1;
>      }
>  
> -  if (linker_output)
> +  if (!dumppfx)
>      {
> -      char *output_dir, *base, *name;
> -      bool bit_bucket = strcmp (linker_output, HOST_BIT_BUCKET) == 0;
> -
> -      output_dir = xstrdup (linker_output);
> -      base = output_dir;
> -      for (name = base; *name; name++)
> -	if (IS_DIR_SEPARATOR (*name))
> -	  base = name + 1;
> -      *base = '\0';
> -
> -      linker_output = &linker_output[base - output_dir];
> -      if (*output_dir == '\0')
> -	{
> -	  static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
> -	  output_dir = current_dir;
> -	}
> -      if (!bit_bucket)
> +      if (!linker_output
> +	  || strcmp (linker_output, HOST_BIT_BUCKET) == 0)
> +	dumppfx = "a.";
> +      else
>  	{
> -	  obstack_ptr_grow (&argv_obstack, "-dumpdir");
> -	  obstack_ptr_grow (&argv_obstack, output_dir);
> +	  const char *obase = lbasename (linker_output), *temp;
> +
> +	  /* Strip the executable extension.  */
> +	  size_t blen = strlen (obase), xlen;
> +	  if ((temp = strrchr (obase + 1, '.'))
> +	      && (xlen = strlen (temp))
> +	      && (strcmp (temp, ".exe") == 0
> +#if HAVE_TARGET_EXECUTABLE_SUFFIX
> +		  || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
> +#endif
> +		  || strcmp (obase, "a.out") == 0))
> +	    dumppfx = xstrndup (linker_output,
> +				obase - linker_output + blen - xlen + 1);
> +	  else
> +	    dumppfx = concat (linker_output, ".", NULL);
>  	}
> +    }
>  
> -      obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  /* If there's no directory component in the dumppfx, add one, so
> +     that, when it is used as -dumpbase, it overrides any occurrence
> +     of -dumpdir that might have been passed in.  */
> +  if (!dumppfx || lbasename (dumppfx) == dumppfx)
> +    dumppfx = concat (current_dir, dumppfx, NULL);
> +
> +  /* Make sure some -dumpdir is passed, so as to get predictable
> +     -dumpbase overriding semantics.  If we got an incoming -dumpdir
> +     argument, we'll pass it on, so don't bother with another one
> +     then.  */
> +  if (!incoming_dumppfx)
> +    {
> +      obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +      /* An empty string would do, if only writeargv would write it
> +	 out in a way that would not be skipped by expandargv and
> +	 buildargv.  */
> +      obstack_ptr_grow (&argv_obstack, current_dir);
>      }
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
>  
>    /* Remember at which point we can scrub args to re-use the commons.  */
>    new_head_argc = obstack_object_size (&argv_obstack) / sizeof (void *);
> @@ -1570,15 +1593,11 @@ cont1:
>  
>    if (lto_mode == LTO_MODE_LTO)
>      {
> -      if (linker_output)
> -	{
> -	  obstack_ptr_grow (&argv_obstack, linker_output);
> -	  flto_out = (char *) xmalloc (strlen (linker_output)
> -				       + sizeof (".lto.o") + 1);
> -	  strcpy (flto_out, linker_output);
> -	  strcat (flto_out, ".lto.o");
> -	}
> -      else
> +      /* -dumpbase argument for LTO.  */
> +      flto_out = concat (dumppfx, "lto.o", NULL);
> +      obstack_ptr_grow (&argv_obstack, flto_out);
> +
> +      if (!save_temps)
>  	flto_out = make_temp_file (".lto.o");
>        obstack_ptr_grow (&argv_obstack, "-o");
>        obstack_ptr_grow (&argv_obstack, flto_out);
> @@ -1586,47 +1605,17 @@ cont1:
>    else 
>      {
>        const char *list_option = "-fltrans-output-list=";
> -      size_t list_option_len = strlen (list_option);
> -      char *tmp;
>  
> -      if (linker_output)
> -	{
> -	  char *dumpbase = (char *) xmalloc (strlen (linker_output)
> -					     + sizeof (".wpa") + 1);
> -	  strcpy (dumpbase, linker_output);
> -	  strcat (dumpbase, ".wpa");
> -	  obstack_ptr_grow (&argv_obstack, dumpbase);
> -	}
> +      /* -dumpbase argument for WPA.  */
> +      char *dumpbase = concat (dumppfx, "wpa", NULL);
> +      obstack_ptr_grow (&argv_obstack, dumpbase);
>  
> -      if (linker_output && save_temps)
> -	{
> -	  ltrans_output_file = (char *) xmalloc (strlen (linker_output)
> -						 + sizeof (".ltrans.out") + 1);
> -	  strcpy (ltrans_output_file, linker_output);
> -	  strcat (ltrans_output_file, ".ltrans.out");
> -	}
> +      if (save_temps)
> +	ltrans_output_file = concat (dumppfx, "ltrans.out", NULL);
>        else
> -	{
> -	  char *prefix = NULL;
> -	  if (linker_output)
> -	    {
> -	      prefix = (char *) xmalloc (strlen (linker_output) + 2);
> -	      strcpy (prefix, linker_output);
> -	      strcat (prefix, ".");
> -	    }
> -
> -	  ltrans_output_file = make_temp_file_with_prefix (prefix,
> -							   ".ltrans.out");
> -	  free (prefix);
> -	}
> -      list_option_full = (char *) xmalloc (sizeof (char) *
> -		         (strlen (ltrans_output_file) + list_option_len + 1));
> -      tmp = list_option_full;
> -
> -      obstack_ptr_grow (&argv_obstack, tmp);
> -      strcpy (tmp, list_option);
> -      tmp += list_option_len;
> -      strcpy (tmp, ltrans_output_file);
> +	ltrans_output_file = make_temp_file (".ltrans.out");
> +      list_option_full = concat (list_option, ltrans_output_file, NULL);
> +      obstack_ptr_grow (&argv_obstack, list_option_full);
>  
>        if (jobserver)
>  	{
> @@ -1782,16 +1771,10 @@ cont:
>  	  output_name = XOBFINISH (&env_obstack, char *);
>  
>  	  /* Adjust the dumpbase if the linker output file was seen.  */
> -	  if (linker_output)
> -	    {
> -	      char *dumpbase
> -		  = (char *) xmalloc (strlen (linker_output)
> -				      + sizeof (DUMPBASE_SUFFIX) + 1);
> -	      snprintf (dumpbase,
> -			strlen (linker_output) + sizeof (DUMPBASE_SUFFIX),
> -			"%s.ltrans%u", linker_output, i);
> -	      argv_ptr[0] = dumpbase;
> -	    }
> +	  int dumpbase_len = (strlen (dumppfx) + sizeof (DUMPBASE_SUFFIX));
> +	  char *dumpbase = (char *) xmalloc (dumpbase_len + 1);
> +	  snprintf (dumpbase, dumpbase_len, "%sltrans%u.ltrans", dumppfx, i);
> +	  argv_ptr[0] = dumpbase;
>  
>  	  argv_ptr[1] = "-fltrans";
>  	  argv_ptr[2] = "-o";
> diff --git a/gcc/opts.c b/gcc/opts.c
> index fa4804c..5b29b98 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -845,30 +845,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>  	/* We have a DUMP_DIR_NAME, prepend that.  */
>  	opts->x_dump_base_name = opts_concat (opts->x_dump_dir_name,
>  					      opts->x_dump_base_name, NULL);
> -      else if (opts->x_aux_base_name
> -	       && strcmp (opts->x_aux_base_name, HOST_BIT_BUCKET) != 0)
> -	/* AUX_BASE_NAME is set and is not the bit bucket.  If it
> -	   contains a directory component, prepend those directories.
> -	   Typically this places things in the same directory as the
> -	   object file.  */
> -	{
> -	  const char *aux_base;
> -
> -	  base_of_path (opts->x_aux_base_name, &aux_base);
> -	  if (opts->x_aux_base_name != aux_base)
> -	    {
> -	      int dir_len = aux_base - opts->x_aux_base_name;
> -	      char *new_dump_base_name
> -		= XOBNEWVEC (&opts_obstack, char,
> -			     strlen (opts->x_dump_base_name) + dir_len + 1);
> -
> -	      /* Copy directory component from OPTS->X_AUX_BASE_NAME.  */
> -	      memcpy (new_dump_base_name, opts->x_aux_base_name, dir_len);
> -	      /* Append existing OPTS->X_DUMP_BASE_NAME.  */
> -	      strcpy (new_dump_base_name + dir_len, opts->x_dump_base_name);
> -	      opts->x_dump_base_name = new_dump_base_name;
> -	    }
> -	}
>  
>        /* It is definitely prefixed now.  */
>        opts->x_dump_base_name_prefixed = true;
> @@ -2314,17 +2290,6 @@ common_handle_option (struct gcc_options *opts,
>        opts->x_flag_gen_aux_info = 1;
>        break;
>  
> -    case OPT_auxbase_strip:
> -      {
> -	char *tmp = xstrdup (arg);
> -	strip_off_ending (tmp, strlen (tmp));
> -	if (tmp[0])
> -	  opts->x_aux_base_name = tmp;
> -	else
> -	  free (tmp);
> -      }
> -      break;
> -
>      case OPT_d:
>        decode_d_option (arg, opts, loc, dc);
>        break;
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs-0.c b/gcc/testsuite/gcc.misc-tests/outputs-0.c
> new file mode 100644
> index 00000000..ca2ac4a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.misc-tests/outputs-0.c
> @@ -0,0 +1 @@
> +int main () {}
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs-1.c b/gcc/testsuite/gcc.misc-tests/outputs-1.c
> new file mode 100644
> index 00000000..35f19cf
> --- /dev/null
> +++ b/gcc/testsuite/gcc.misc-tests/outputs-1.c
> @@ -0,0 +1,4 @@
> +extern void f();
> +int main() {
> +  f();
> +}
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs-2.c b/gcc/testsuite/gcc.misc-tests/outputs-2.c
> new file mode 100644
> index 00000000..109733d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.misc-tests/outputs-2.c
> @@ -0,0 +1,2 @@
> +void f() {
> +}
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp
> new file mode 100644
> index 00000000..a37e978
> --- /dev/null
> +++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
> @@ -0,0 +1,655 @@
> +# Copyright (C) 2005-2020 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with GCC; see the file COPYING3.  If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +# This file contains a set of test that check that options intended to
> +# control the location and name of GCC outputs behave as expected.
> +
> +load_lib gcc-defs.exp
> +
> +set b "outputs"
> +
> +# These tests don't run runtest_file_p consistently if it
> +# doesn't return the same values, so disable parallelization
> +# of this *.exp file.  The first parallel runtest to reach
> +# this will run all the tests serially.
> +if ![gcc_parallel_test_run_p $b] {
> +    return
> +}
> +gcc_parallel_test_enable 0
> +
> +# For the test named TEST, run the compiler with SOURCES and OPTS, and
> +# look in DIRS for OUTPUTS.  SOURCES is a list of suffixes for source
> +# files starting with $b in $srcdir/$subdir, OPTS is a string with
> +# options to be passed to the compiler, DIRS and OUTPUTS are lists.
> +# DIRS is a list of output directories, children before parent, and
> +# for each element of DIRS, there should be a corresponding sublist in
> +# OUTPUTS.  If OUTPUTS has an additional trailing sublist, that's the
> +# output list for the current directory.  Each element of the sublists
> +# in OUTPUT is a file name or glob pattern to be checked for; a name
> +# starting with a dash or a period is taken as a suffix for $b; with a
> +# double dash, or a dash followed by a period, the first dash is
> +# replaced with $b-$b; names starting with "a--" or "a-." have "$b"
> +# inserted after the first dash.  The glob pattern may expand to more
> +# than one file, but then the test will pass when there any number of
> +# matches.  So, it's safe to use for a.{out,exe}, but .{i,s,o} and
> +# .[iso] will pass even if only the .o is present.
> +proc outest { test sources opts dirs outputs } {
> +    global b
> +    global srcdir
> +    global subdir
> +    set src {}
> +    foreach s $sources {
> +	lappend src $srcdir/$subdir/$b$s
> +    }
> +    foreach f [glob -nocomplain -path $b -- *] {
> +	file delete $f
> +    }
> +    foreach d $dirs {
> +	file mkdir $d
> +	foreach f [glob -nocomplain -path $d -- *] {
> +	    file delete $d$f
> +	}
> +    }
> +    set options ""
> +    foreach opt [split $opts " "] {
> +	set options "$options additional_flags=$opt"
> +    }
> +    set gcc_output [gcc_target_compile $src "" none "$options"]
> +    set outs {}
> +    foreach d $dirs olist $outputs {
> +	foreach og $olist {
> +	    if { [string index $og 0] == "-" } then {
> +		if { [string index $og 1] == "-" || \
> +			 [string index $og 1] == "." } then {
> +		    set o "$b-$b[string range $og 1 end]"
> +		} else {
> +		    set o "$b$og"
> +		}
> +	    } elseif { [string index $og 0] == "." } then {
> +		set o "$b$og"
> +	    } elseif { [string range $og 0 2] == "a--" } then {
> +		set o "a-$b-[string range $og 3 end]"
> +	    } elseif { [string range $og 0 2] == "a-." } then {
> +		set o "a-$b.[string range $og 3 end]"
> +	    } else {
> +		set o "$og"
> +	    }
> +	    if { [file exists $d$o] } then {
> +		pass "$test: $d$o"
> +		file delete $d$o
> +	    } else {
> +	        set ogl [glob -nocomplain -path $d -- $o]
> +		if { $ogl != {} } {
> +		    pass "$test: $d$o"
> +		    file delete $ogl
> +		} else {
> +		    fail "$test: $d$o"
> +		}
> +	    }
> +	}
> +	foreach ol [glob -nocomplain -path $d$b -- *] {
> +	    lappend outs $ol
> +	}
> +	foreach ol [glob -nocomplain -path $d -- a{-,.}*] {
> +	    lappend outs $ol
> +	}
> +    }
> +
> +    foreach f $outs {
> +	file delete $f
> +    }
> +    foreach d $dirs {
> +	file delete -force $d
> +    }
> +
> +    if { [llength $outs] == 0 } then {
> +	pass "$test: extra"
> +    } else {
> +	fail "$test: extra $outs"
> +    }
> +
> +    if { [string equal "$gcc_output" ""] } then {
> +	pass "$test: std out"
> +    } else {
> +	fail "$test: std out $gcc_output"
> +    }
> +
> +}
> +
> +set sing {-0.c}
> +set mult {-1.c -2.c}
> +
> +# Driver-chosen outputs.
> +outest "$b asm default 1" $sing "-S" {} {{-0.s}}
> +outest "$b asm default 2" $mult "-S" {} {{-1.s -2.s}}
> +
> +outest "$b obj default 1" $sing "-c" {} {{-0.o}}
> +outest "$b obj default 2" $mult "-c" {} {{-1.o -2.o}}
> +
> +outest "$b exe default 1" $sing "" {} {{a.{out,exe}}}
> +outest "$b exe default 2" $mult "" {} {{a.{out,exe}}}
> +
> +# Driver-chosen aux outputs.
> +outest "$b asm savetmp 1" $sing "-S -save-temps" {} {{-0.i -0.s}}
> +outest "$b asm savetmp 2" $mult "-S -save-temps" {} {{-1.i -1.s -2.i -2.s}}
> +outest "$b obj savetmp unnamed1" $sing "-c -save-temps" {} {{-0.i -0.s -0.o}}
> +outest "$b obj savetmp unnamed2" $mult "-c -save-temps" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
> +
> +# Aux outputs computed within the driver, based on output name (and
> +# input).
> +outest "$b cpp savetmp named0" $sing "-E -o $b-0.i -save-temps" {} {{-0.i}}
> +outest "$b asm savetmp named0" $sing "-S -o $b-0.s -save-temps" {} {{-0.i -0.s}}
> +outest "$b obj savetmp named0" $sing "-c -o $b-0.o -save-temps" {} {{-0.i -0.s -0.o}}
> +outest "$b cpp savetmp namedb" $sing "-E -o $b.i -save-temps" {} {{.i}}
> +outest "$b asm savetmp namedb" $sing "-S -o $b.s -save-temps" {} {{.i .s}}
> +outest "$b obj savetmp namedb" $sing "-c -o $b.o -save-temps" {} {{.i .s .o}}
> +
> +# When linking, the executable name gets prepended to aux output
> +# basenames, except when executable and single input share the same
> +# basename.
> +outest "$b exe savetmp unnamed1" $sing "-save-temps" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
> +outest "$b exe savetmp unnamed2" $mult "-save-temps" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
> +outest "$b exe savetmp named0" $sing "-o $b-0.exe -save-temps" {} {{-0.i -0.s -0.o -0.exe}}
> +outest "$b exe savetmp namedb" $sing "-o $b.exe -save-temps" {} {{--0.i --0.s --0.o .exe}}
> +outest "$b exe savetmp named2" $mult "-o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
> +
> +# Setting the main output to a dir selects it as the default aux&dump
> +# location.
> +outest "$b cpp savetmp namedir0" $sing "-E -o o/$b-0.i -save-temps" {o/} {{-0.i} {}}
> +outest "$b asm savetmp namedir0" $sing "-S -o o/$b-0.s -save-temps" {o/} {{-0.i -0.s} {}}
> +outest "$b obj savetmp namedir0" $sing "-c -o o/$b-0.o -save-temps" {o/} {{-0.i -0.s -0.o} {}}
> +outest "$b cpp savetmp namedir" $sing "-E -o o/$b.i -save-temps" {o/} {{.i} {}}
> +outest "$b asm savetmp namedir" $sing "-S -o o/$b.s -save-temps" {o/} {{.i .s} {}}
> +outest "$b obj savetmp namedir" $sing "-c -o o/$b.o -save-temps" {o/} {{.i .s .o} {}}
> +outest "$b exe savetmp namedir0" $sing "-o o/$b-0.exe -save-temps" {o/} {{-0.i -0.s -0.o -0.exe} {}}
> +outest "$b exe savetmp namedirb" $sing "-o o/$b.exe -save-temps" {o/} {{--0.i --0.s --0.o .exe} {}}
> +outest "$b exe savetmp namedir2" $mult "-o o/$b.exe -save-temps" {o/} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe} {}}
> +
> +# -save-temps=cwd overrides the aux output location to the current dir.
> +outest "$b obj savecwd unnamed1" $sing "-c -save-temps=cwd" {} {{-0.i -0.s -0.o}}
> +outest "$b obj savecwd unnamed2" $mult "-c -save-temps=cwd" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
> +outest "$b cpp savecwd named0" $sing "-E -o $b-0.i -save-temps=cwd" {} {{-0.i}}
> +outest "$b asm savecwd named0" $sing "-S -o $b-0.s -save-temps=cwd" {} {{-0.i -0.s}}
> +outest "$b obj savecwd named0" $sing "-c -o $b-0.o -save-temps=cwd" {} {{-0.i -0.s -0.o}}
> +outest "$b cpp savecwd namedb" $sing "-E -o $b.i -save-temps=cwd" {} {{.i}}
> +outest "$b asm savecwd namedb" $sing "-S -o $b.s -save-temps=cwd" {} {{.i .s}}
> +outest "$b obj savecwd namedb" $sing "-c -o $b.o -save-temps=cwd" {} {{.i .s .o}}
> +outest "$b exe savecwd unnamed1" $sing "-save-temps=cwd" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
> +outest "$b exe savecwd unnamed2" $mult "-save-temps=cwd" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
> +outest "$b exe savecwd named0" $sing "-o $b-0.exe -save-temps=cwd" {} {{-0.i -0.s -0.o -0.exe}}
> +outest "$b exe savecwd namedb" $sing "-o $b.exe -save-temps=cwd" {} {{--0.i --0.s --0.o .exe}}
> +outest "$b exe savecwd named2" $mult "-o $b.exe -save-temps=cwd" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
> +
> +outest "$b cpp savecwd namedir0" $sing "-E -o o/$b-0.i -save-temps=cwd" {o/} {{-0.i} {}}
> +outest "$b asm savecwd namedir0" $sing "-S -o o/$b-0.s -save-temps=cwd" {o/} {{-0.s} {-0.i}}
> +outest "$b obj savecwd namedir0" $sing "-c -o o/$b-0.o -save-temps=cwd" {o/} {{-0.o} {-0.i -0.s}}
> +outest "$b cpp savecwd namedir" $sing "-E -o o/$b.i -save-temps=cwd" {o/} {{.i} {}}
> +outest "$b asm savecwd namedir" $sing "-S -o o/$b.s -save-temps=cwd" {o/} {{.s} {.i}}
> +outest "$b obj savecwd namedir" $sing "-c -o o/$b.o -save-temps=cwd" {o/} {{.o} {.i .s}}
> +outest "$b exe savecwd namedir0" $sing "-o o/$b-0.exe -save-temps=cwd" {o/} {{-0.exe} {-0.i -0.s -0.o}}
> +outest "$b exe savecwd namedirb" $sing "-o o/$b.exe -save-temps=cwd" {o/} {{.exe} {--0.i --0.s --0.o}}
> +outest "$b exe savecwd namedir2" $mult "-o o/$b.exe -save-temps=cwd" {o/} {{.exe} {--1.i --1.s --1.o --2.i --2.s --2.o}}
> +
> +# -save-temps=obj overrides the aux output location to that of the
> +# main output
> +outest "$b obj saveobj unnamed1" $sing "-c -save-temps=obj" {} {{-0.i -0.s -0.o}}
> +outest "$b obj saveobj unnamed2" $mult "-c -save-temps=obj" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
> +outest "$b cpp saveobj named0" $sing "-E -o $b-0.i -save-temps=obj" {} {{-0.i}}
> +outest "$b asm saveobj named0" $sing "-S -o $b-0.s -save-temps=obj" {} {{-0.i -0.s}}
> +outest "$b obj saveobj named0" $sing "-c -o $b-0.o -save-temps=obj" {} {{-0.i -0.s -0.o}}
> +outest "$b cpp saveobj namedb" $sing "-E -o $b.i -save-temps=obj" {} {{.i}}
> +outest "$b asm saveobj namedb" $sing "-S -o $b.s -save-temps=obj" {} {{.i .s}}
> +outest "$b obj saveobj namedb" $sing "-c -o $b.o -save-temps=obj" {} {{.i .s .o}}
> +outest "$b exe saveobj unnamed1" $sing "-save-temps=obj" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
> +outest "$b exe saveobj unnamed2" $mult "-save-temps=obj" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
> +outest "$b exe saveobj named0" $sing "-o $b-0.exe -save-temps=obj" {} {{-0.i -0.s -0.o -0.exe}}
> +outest "$b exe saveobj namedb" $sing "-o $b.exe -save-temps=obj" {} {{--0.i --0.s --0.o .exe}}
> +outest "$b exe saveobj named2" $mult "-o $b.exe -save-temps=obj" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
> +
> +outest "$b cpp saveobj namedir0" $sing "-E -o o/$b-0.i -save-temps=obj" {o/} {{-0.i} {}}
> +outest "$b asm saveobj namedir0" $sing "-S -o o/$b-0.s -save-temps=obj" {o/} {{-0.i -0.s} {}}
> +outest "$b obj saveobj namedir0" $sing "-c -o o/$b-0.o -save-temps=obj" {o/} {{-0.i -0.s -0.o} {}}
> +outest "$b cpp saveobj namedir" $sing "-E -o o/$b.i -save-temps=obj" {o/} {{.i} {}}
> +outest "$b asm saveobj namedir" $sing "-S -o o/$b.s -save-temps=obj" {o/} {{.i .s} {}}
> +outest "$b obj saveobj namedir" $sing "-c -o o/$b.o -save-temps=obj" {o/} {{.i .s .o} {}}
> +outest "$b exe saveobj namedir0" $sing "-o o/$b-0.exe -save-temps=obj" {o/} {{-0.i -0.s -0.o -0.exe} {}}
> +outest "$b exe saveobj namedirb" $sing "-o o/$b.exe -save-temps=obj" {o/} {{--0.i --0.s --0.o .exe} {}}
> +outest "$b exe saveobj namedir2" $mult "-o o/$b.exe -save-temps=obj" {o/} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe} {}}
> +
> +# Check -dumpdir overriding by -save-temps=*, and -save-temps
> +# non-overriding, with one catch: the presence of a given dumpdir,
> +# even if ultimately overridden, still disables the prepending of the
> +# executable basename to the aux&dump output basenames (or rather the
> +# appending of the executable basename to the dumpdir).
> +outest "$b exe sobjovr namedir0" $sing "-o o/$b-0.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-0.i -0.s -0.o -0.exe} {}}
> +outest "$b exe sobjovr namedirb" $sing "-o o/$b.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-0.i -0.s -0.o .exe} {}}
> +outest "$b exe sobjovr namedir2" $mult "-o o/$b.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o .exe} {}}
> +outest "$b exe scwdovr namedir0" $sing "-o o/$b-0.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{-0.exe} {-0.i -0.s -0.o}}
> +outest "$b exe scwdovr namedirb" $sing "-o o/$b.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{.exe} {-0.i -0.s -0.o}}
> +outest "$b exe scwdovr namedir2" $mult "-o o/$b.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{.exe} {-1.i -1.s -1.o -2.i -2.s -2.o}}
> +outest "$b exe ddstovr namedir0" $sing "-o $b-0.exe -dumpdir o/ -save-temps" {o/} {{-0.i -0.s -0.o} {-0.exe}}
> +outest "$b exe ddstovr namedirb" $sing "-o $b.exe -dumpdir o/ -save-temps" {o/} {{-0.i -0.s -0.o} {.exe}}
> +outest "$b exe ddstovr namedir2" $mult "-o $b.exe -dumpdir o/ -save-temps" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o} {.exe}}
> +
> +# Check -dumpdir prevailing over -save-temps*.  Even though -dumpdir
> +# overrides the -save-temps=* directory selection, -save-temps remains
> +# enabled.
> +outest "$b exe soddovr namedir0" $sing "-o o/$b-0.exe -save-temps=obj -dumpdir ./" {o/} {{-0.exe} {-0.i -0.s -0.o}}
> +outest "$b exe soddovr namedirb" $sing "-o o/$b.exe -save-temps=obj -dumpdir ./" {o/} {{.exe} {-0.i -0.s -0.o}}
> +outest "$b exe soddovr namedir2" $mult "-o o/$b.exe -save-temps=obj -dumpdir ./" {o/} {{.exe} {-1.i -1.s -1.o -2.i -2.s -2.o}}
> +outest "$b exe scddovr namedir0" $sing "-o o/$b-0.exe -save-temps=cwd -dumpdir o/" {o/} {{-0.i -0.s -0.o -0.exe} {}}
> +outest "$b exe scddovr namedirb" $sing "-o o/$b.exe -save-temps=cwd -dumpdir o/" {o/} {{-0.i -0.s -0.o .exe} {}}
> +outest "$b exe scddovr namedir2" $mult "-o o/$b.exe -save-temps=cwd -dumpdir o/" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o .exe} {}}
> +outest "$b exe ddstovr namedir0" $sing "-o $b-0.exe -save-temps -dumpdir o/" {o/} {{-0.i -0.s -0.o} {-0.exe}}
> +outest "$b exe ddstovr namedirb" $sing "-o $b.exe -save-temps -dumpdir o/" {o/} {{-0.i -0.s -0.o} {.exe}}
> +outest "$b exe ddstovr namedir2" $mult "-o $b.exe -save-temps -dumpdir o/" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o} {.exe}}
> +
> +
> +# Compiler- and driver-generated aux and dump outputs.
> +# -fdump-rtl-final creates a .c.???r.final dump in the compiler.
> +# -fstack-usage creates a .su aux output in the compiler.
> +# -gsplit-dwarf extracts a .dwo aux output from the .o in the driver.
> +outest "$b asm auxdump 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.s}}
> +outest "$b asm auxdump 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-1.c.???r.final -1.su -1.s -2.c.???r.final -2.su -2.s}}
> +outest "$b obj auxdump unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +outest "$b obj auxdump unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-1.c.???r.final -1.su -1.dwo -1.o -2.c.???r.final -2.su -2.dwo -2.o}}
> +
> +outest "$b cpp auxdump named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.i}}
> +outest "$b asm auxdump named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.s}}
> +outest "$b obj auxdump named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.i}}
> +outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.c.???r.final .su .s}}
> +outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.c.???r.final .su .dwo .o}}
> +
> +outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
> +outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
> +outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
> +outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
> +outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
> +
> +outest "$b cpp auxdump namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.i} {}}
> +outest "$b asm auxdump namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.s} {}}
> +outest "$b obj auxdump namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.o} {}}
> +outest "$b cpp auxdump namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.i} {}}
> +outest "$b asm auxdump namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.c.???r.final .su .s} {}}
> +outest "$b obj auxdump namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.c.???r.final .su .dwo .o} {}}
> +outest "$b exe auxdump namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.exe} {}}
> +outest "$b exe auxdump namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{--0.c.???r.final --0.su --0.dwo .exe} {}}
> +outest "$b exe auxdump namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
> +
> +# Check that -save-temps doesn't break compiler aux or dumps as it
> +# changes temp file names.
> +outest "$b asm auxdmps 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
> +outest "$b asm auxdmps 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -2.i -2.c.???r.final -2.su -2.s}}
> +outest "$b obj auxdmps unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
> +outest "$b obj auxdmps unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -1.dwo -1.o -2.i -2.c.???r.final -2.su -2.s -2.dwo -2.o}}
> +
> +outest "$b cpp auxdmps named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i}}
> +outest "$b asm auxdmps named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
> +outest "$b obj auxdmps named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
> +outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i}}
> +outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
> +outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
> +
> +outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
> +outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
> +outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
> +outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
> +outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
> +
> +outest "$b cpp auxdmps namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i} {}}
> +outest "$b asm auxdmps namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s} {}}
> +outest "$b obj auxdmps namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o} {}}
> +outest "$b cpp auxdmps namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i} {}}
> +outest "$b asm auxdmps namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i .c.???r.final .su .s} {}}
> +outest "$b obj auxdmps namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i .c.???r.final .su .s .dwo .o} {}}
> +outest "$b exe auxdmps namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe} {}}
> +outest "$b exe auxdmps namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe} {}}
> +outest "$b exe auxdmps namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe} {}}
> +
> +
> +# Check that dumpdir changes the location of non-primary outputs
> +outest "$b asm dumpdir 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
> +outest "$b asm dumpdir 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -2.c.???r.final -2.su} {-1.s -2.s}}
> +outest "$b obj dumpdir unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
> +outest "$b obj dumpdir unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dumpdir named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{} {-0.i}}
> +outest "$b asm dumpdir named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
> +outest "$b obj dumpdir named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
> +outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{} {.i}}
> +outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
> +outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
> +
> +outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
> +outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
> +outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
> +outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
> +outest "$b exe dumpdira namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dumpdira named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +outest "$b exe dumpdirb namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
> +outest "$b exe dumpdirb named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +
> +outest "$b cpp dumpdir namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dumpdir namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su} {-0.s} {}}
> +outest "$b obj dumpdir namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.o} {}}
> +outest "$b cpp dumpdir namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{} {.i} {}}
> +outest "$b asm dumpdir namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su} {.s} {}}
> +outest "$b obj dumpdir namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dumpdir namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe} {}}
> +outest "$b exe dumpdir namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {.exe} {}}
> +outest "$b exe dumpdir namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe} {}}
> +outest "$b exe dumpdira namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
> +outest "$b exe dumpdira namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +outest "$b exe dumpdirb namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
> +outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +
> +# Check that a -dumpbase with a dir component disregards the -dumpdir
> +# prefix.  Also, start testing -dumpbase-ext to distinguish between
> +# aux and dump files: only the latter retain the named extension.
> +# -dumpbase-ext, if absent or used in combination with -dumpbase for
> +# an executable name, defaults to the extension of the source file.
> +# The specified dumpbase is combined with the dumpdir prefix when
> +# processing more than one input (we couldn't use the same dumpbase
> +# for them all), or when linking (the specified dumpbase is then used
> +# as prefix instead of the linker output, and a new dumpbase is
> +# computed per source).
> +outest "$b asm dbsovrdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbsovrddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbsovrdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbsovrdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbsovrdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbsovrddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbsovrdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbsovrddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbsovrdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbsovrdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {-0.i}}
> +outest "$b asm dbsovrdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbsovrdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbsovrdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {.i}}
> +outest "$b asm dbsovrdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
> +
> +# Nit: -dumpdir affects whether the specified dumpbase is combined
> +# into dumpdir or taken as the output basename, even if dumpbase will
> +# ultimately override it.
> +outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
> +outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
> +outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
> +outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbsovrdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbsovrddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbsovrdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbsovrdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbsovrdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbsovrdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbsovrdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbsovrdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbsovrdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbsovrdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
> +outest "$b exe dbsovrdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
> +outest "$b exe dbsovrdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbsovrdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
> +outest "$b exe dbsovrdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +
> +
> +# Check that a -dumpbase without a dir component adds to the -dumpdir
> +# prefix.
> +outest "$b asm dbswthdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbswthddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbswthdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbswthdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbswthdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbswthddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbswthdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbswthddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbswthdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbswthdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {-0.i}}
> +outest "$b asm dbswthdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbswthdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbswthdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {.i}}
> +outest "$b asm dbswthdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {.o}}
> +
> +# Nitty details: -dumpdir affects whether the specified dumpbase is
> +# combined into dumpdir or taken as the output basename, even if
> +# dumpbase will ultimately override it.
> +outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
> +outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
> +outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
> +outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbswthdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbswthddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbswthdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbswthdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbswthdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbswthdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbswthdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbswthdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbswthdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbswthdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
> +outest "$b exe dbswthdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
> +outest "$b exe dbswthdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbswthdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
> +outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +
> +
> +# Check for the minor differences when -dumpbase is used without
> +# -dumpdir.  The main difference between dbwoutdd and dbswthdd tests
> +# is in the single-input link tests: with the dump dir/ prefix moved
> +# to dumpbase, and without -dumpdir we end up using -dumpbase as the
> +# executable prefix rather than as the dumpbase for the single input.
> +outest "$b asm dbwoutdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbwoutddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbwoutdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbwoutdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbwoutdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbwoutddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbwoutdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbwoutddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbwoutdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbwoutdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{} {-0.i}}
> +outest "$b asm dbwoutdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbwoutdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{} {.i}}
> +outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
> +
> +outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
> +outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
> +outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
> +outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
> +outest "$b exe dbwoutdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbwoutdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dbwoutddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dbwoutdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbwoutdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbwoutdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbwoutdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbwoutdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbwoutdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbwoutdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbwoutdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe} {}}
> +outest "$b exe dbwoutdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
> +outest "$b exe dbwoutdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbwoutdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
> +outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +
> +# -fcompare-debug
> +outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage -gsplit-dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
> +outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage -gsplit-dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
> +
> +# -flto
> +outest "$b lto sing unnamed" $sing "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto mult unnamed" $mult "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.c.???i.icf a--2.c.???i.icf  a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto sing named" $sing "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
> +outest "$b lto mult named" $mult "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
> +outest "$b lto sing nameddir" $sing "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
> +outest "$b lto mult nameddir" $mult "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
> +
> +# -dumpbase without -dumpdir.  The trailing dumppfx dash after it is
> +# combined with dumpbase turns into a period when passed to lto as
> +# -dumpdir, because the dash is introduced by the compiler driver.
> +outest "$b lto sing dumpbase unnamed" $sing "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto mult dumpbase unnamed" $mult "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto sing dumpbase named" $sing "-dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto mult dumpbase named" $mult "-dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto sing dumpbase namedb" $sing "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +outest "$b lto mult dumpbase namedb" $mult "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +
> +# -dumpdir without -dumpbase.  The trailing dash in -dumpdir is given
> +# by the user, thus not replaced with a dot.
> +outest "$b lto sing dumpdir unnamed" $sing "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto mult dumpdir unnamed" $mult "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto sing dumpdir namedb" $sing "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
> +outest "$b lto mult dumpdir namedb" $mult "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
> +
> +# -dumpdir and non-overriding -dumpbase.
> +outest "$b lto dbswthdd sing unnamed" $sing "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto dbswthdd mult unnamed" $mult "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto dbswthdd sing named" $sing "-dumpdir dir/ -dumpbase $b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto dbswthdd mult named" $mult "-dumpdir dir/ -dumpbase $b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto dbswthdd sing namedb" $sing "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +outest "$b lto dbswthdd mult namedb" $mult "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +
> +# -dumpdir and an overriding -dumpbase.
> +outest "$b lto dbsovrdd sing unnamed" $sing "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto dbsovrdd mult unnamed" $mult "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto dbsovrdd sing named" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto dbsovrdd mult named" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto dbsovrdd sing namedb" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +outest "$b lto dbsovrdd mult namedb" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +
> +# Check that -dumpbase '' gets source names as dumpbases for
> +# compilation, and output name as dumpbase for linking, regardless of
> +# how many source files.
> +outest "$b lto sing empty dumpbase unnamed" $sing "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto mult empty dumpbase unnamed" $mult "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto sing empty dumpbase named" $sing "-dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.exe} {}}
> +outest "$b lto mult empty dumpbase named" $mult "-dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.exe} {}}
> +outest "$b lto sing empty dumpbase namedb" $sing "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
> +outest "$b lto mult empty dumpbase namedb" $mult "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
> +
> +# Now with -dumpdir too.
> +outest "$b lto sing empty dumpbase dumpdir unnamed" $sing "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto mult empty dumpbase dumpdir unnamed" $mult "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto sing empty dumpbase dumpdir named" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf --0.wpa.???i.icf --0.ltrans0.ltrans.???r.final --0.ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto mult empty dumpbase dumpdir named" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf --1.wpa.???i.icf --1.ltrans0.ltrans.???r.final --1.ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto sing empty dumpbase dumpdir namedb" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
> +outest "$b lto mult empty dumpbase dumpdir namedb" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
> +
> +# And also with an empty -dumpdir.  That's equivalent to -dumpdir ./,
> +# overriding any dumpdir implied by the output.
> +outest "$b lto sing empty dumpdir empty dumpbase unnamed" $sing "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto mult empty dumpdir empty dumpbase unnamed" $mult "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto sing empty dumpdir empty dumpbase named" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.exe} {-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su}}
> +outest "$b lto mult empty dumpdir empty dumpbase named" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.exe} {-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su}}
> +outest "$b lto sing empty dumpdir empty dumpbase namedb" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
> +outest "$b lto mult empty dumpdir empty dumpbase namedb" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
> +
> +# Now -flto with -save-temps, not exhaustive.
> +outest "$b lto st sing empty dumpbase unnamed" $sing "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.i -0.s -0.o -0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
> +outest "$b lto st mult empty dumpbase unnamed" $mult "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
> +outest "$b lto st sing dumpdir empty dumpbase named" $sing "-dumpdir dir/ -dumpbase \"\" -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf -0.lto_wrapper_args -0.wpa.???i.icf -0.ltrans.out -0.res -0.ltrans0.o -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.ltrans0.ltrans.s -0.ltrans0.ltrans.o} {-0.exe}}
> +outest "$b lto st mult dumpdir empty dumpbase named" $mult "-dumpdir dir/ -dumpbase \"\" -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf -1.lto_wrapper_args -1.wpa.???i.icf -1.ltrans.out -1.res -1.ltrans0.o -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.ltrans0.ltrans.s -1.ltrans0.ltrans.o} {-1.exe}}
> +outest "$b lto st sing empty dumpbase namedb" $sing "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
> +outest "$b lto st mult empty dumpbase namedb" $mult "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
> +
> +# lto save-temps without -dumpbase.
> +outest "$b lto st sing unnamed" $sing "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.i a--0.s a--0.o a--0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
> +outest "$b lto st mult unnamed" $mult "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.i a--1.s a--1.o a--1.c.???i.icf a--2.i a--2.s a--2.o a--2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
> +outest "$b lto st sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-0.exe}}
> +outest "$b lto st mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-1.exe}}
> +outest "$b lto st sing namedb" $sing "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
> +outest "$b lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
> +
> +# Below are examples taken from the documentation.
> +# They are likely redundant with earlier test,
> +# but we want to make sure behavior matches the docs.
> +
> +# gcc -c foo.c ...
> +outest "$b doc single  -c !-o" $sing "-c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +
> +# gcc -c foo.c -o dir/foobar.o ...
> +outest "$b doc single  -c +-o" $sing "-c -o dir/$b.o -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.c.???r.final .su .dwo .o} {}}
> +
> +# gcc foo.c bar.c -o dir/foobar ...
> +outest "$b doc double !-c  -o" $mult "-o dir/$b.exe -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
> +
> +# gcc foo.c -o dir/foo ...
> +outest "$b doc single !-c  -o" $sing "-o dir/$b-0 -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo -0} {}}
> +
> +# gcc -save-temps -S foo.c
> +outest "$b doc single  -S -st" $sing "-save-temps -S" {} {{-0.i -0.s}}
> +
> +# gcc -save-temps -dumpbase save-foo -c foo.c
> +outest "$b doc single  -c -st -db" $sing "-save-temps -dumpbase $b -c" {} {{.i .s -0.o}}
> +
> +# gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
> +#   -dumpdir pfx- -save-temps=cwd ...
> +outest "$b doc single  -c  -o -db" $sing "-c -o dir/$b.o -dumpbase alt/$b -dumpdir pfx- -save-temps=cwd -fdump-rtl-final -fstack-usage -gsplit-dwarf" {alt/ dir/} {{.i .s .???r.final .su .dwo} {.o} {}}
> +
> +# gcc foo.c bar.c -c -dumpbase main ...
> +outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo -1.o --2.c.???r.final --2.su --2.dwo -2.o}}
> +
> +# gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
> +outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
> +
> +# gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
> +outest "$b doc double !-c  -o -db'' -flto" $mult "-o dir/$b.exe -dumpbase \"\" -flto -O2 -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
> +
> +
> +# gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
> +outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
> +
> +# gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
> +outest "$b doc double !-c  -o -dbx" $mult "-o $b.out -dumpbase-ext .out -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .out}}
> +
> +# gcc -dumpdir pfx- -c foo.c ...
> +outest "$b doc single  -c !-o -dd" $sing "-dumpdir $b- -c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--0.c.???r.final --0.su --0.dwo -0.o}}
> +
> +# gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
> +outest "$b doc single  -c  -o -dd" $sing "-dumpdir dir/ -c -o obj/$b.o -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/ obj/} {{.c.???r.final .su .dwo} {.o} {}}
> +
> +# gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
> +outest "$b doc single  -c  -o -dd -st=" $sing "-dumpdir $b- -c -save-temps=obj -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.i -0.s -0.o}}
> +
> +# gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
> +outest "$b doc double  -c !-o -dd -db" $mult "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +# gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
> +outest "$b doc single  -c !-o -dd -db" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
> +
> +# gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
> +outest "$b doc double !-c  -o -dd" $mult "-dumpdir dir/ -o $b.exe -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
> +
> +# gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
> +outest "$b doc single !-c  -o -dd -st=" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
> +
> +
> +gcc_parallel_test_enable 1
> diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
> index da0d1bc..e656e27 100644
> --- a/gcc/testsuite/lib/gcc-defs.exp
> +++ b/gcc/testsuite/lib/gcc-defs.exp
> @@ -305,6 +305,10 @@ proc dg-additional-files-options { options source } {
>  	set to_download [concat $to_download $additional_sources]
>  	set additional_sources_used "$additional_sources"
>  	set additional_sources ""
> +	# This option restores naming of aux and dump output files
> +	# after input files when multiple input files are named,
> +	# instead of getting them combined with the output name.
> +	lappend options "additional_flags=-dumpbase \"\""
>      }
>      if { $additional_files != "" } then { 
>  	regsub -all "^| " $additional_files " [file dirname $source]/" additional_files
> diff --git a/gcc/testsuite/lib/profopt.exp b/gcc/testsuite/lib/profopt.exp
> index 0b853a1..af1fd62f 100644
> --- a/gcc/testsuite/lib/profopt.exp
> +++ b/gcc/testsuite/lib/profopt.exp
> @@ -353,6 +353,10 @@ proc profopt-execute { src } {
>  
>      set count 0
>      foreach option $prof_option_list {
> +	# We pass -dumpbase-ext ${execext}[123] to the compile&link
> +	# commands so as to avoid the combination of the executable
> +	# with the source name in the aux outputs.
> +	set execext ".x${count}"
>  	set execname1 "${executable}${count}1"
>  	set execname2 "${executable}${count}2"
>  	set execname3 "${executable}${count}3"
> @@ -402,7 +406,7 @@ proc profopt-execute { src } {
>  	# Compile for profiling.
>  
>  	set options "$extra_options"
> -	lappend options "additional_flags=$option $extra_flags $profile_option"
> +	lappend options "additional_flags=$option $extra_flags $profile_option -dumpbase-ext ${execext}1"
>  	set optstr "$option $profile_option"
>  	set comp_output [${tool}_target_compile "$src" "$execname1" executable $options]
>  	if ![${tool}_check_compile "$testcase compilation" $optstr $execname1 $comp_output] {
> @@ -491,7 +495,7 @@ proc profopt-execute { src } {
>  	# Compile with feedback-directed optimizations.
>  
>  	set options "$extra_options"
> -	lappend options "additional_flags=$option $extra_flags $feedback_option"
> +	lappend options "additional_flags=$option $extra_flags $feedback_option -dumpbase-ext ${execext}2"
>  	set optstr "$option $feedback_option"
>  	if { [string first "-fauto-profile" $options] >= 0} {
>  	    set options [regsub -- "-fauto-profile" $options "-fauto-profile=$tmpdir/$bprefix$base.$ext"]
> @@ -548,7 +552,7 @@ proc profopt-execute { src } {
>  	# Compile with normal optimizations.
>  
>  	set options "$extra_options"
> -	lappend options "additional_flags=$option"
> +	lappend options "additional_flags=$option -dumpbase-ext ${execext}3"
>  	set optstr "$option"
>  	set comp_output [${tool}_target_compile "$src" "$execname3" "executable" $options]
>  	if ![${tool}_check_compile "$testcase compilation" $optstr $execname3 $comp_output] {
> diff --git a/gcc/testsuite/lib/scandump.exp b/gcc/testsuite/lib/scandump.exp
> index 4c7d904..b29a95a 100644
> --- a/gcc/testsuite/lib/scandump.exp
> +++ b/gcc/testsuite/lib/scandump.exp
> @@ -32,6 +32,9 @@ proc dump-suffix { arg } {
>  proc dump-base { args } {
>      set src [lindex $args 0]
>      set dumpbase_suf [lindex $args 1]
> +    # The dump basename may vary depending on the output name, on
> +    # whether there are multiple sources.  We use -dumpbase "" in
> +    # gcc-defs to base compilation dumps only on the source basename.
>      set dumpbase $src
>      if { [string length $dumpbase_suf] != 0 } {
>  	regsub {[.][^.]*$} $src $dumpbase_suf dumpbase
> diff --git a/gcc/testsuite/lib/scanltranstree.exp b/gcc/testsuite/lib/scanltranstree.exp
> index cff956b..6d35bef 100644
> --- a/gcc/testsuite/lib/scanltranstree.exp
> +++ b/gcc/testsuite/lib/scanltranstree.exp
> @@ -37,11 +37,11 @@ proc scan-ltrans-tree-dump { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump "ltrans-tree" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
> +		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
>  		  [lindex $args 2]
>      } else {
>  	scan-dump "ltrans-tree" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
> +		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
>      }
>  }
>  
> @@ -63,10 +63,10 @@ proc scan-ltrans-tree-dump-times { args } {
>      if { [llength $args] >= 4 } {
>  	scan-dump-times "ltrans-tree" [lindex $args 0] [lindex $args 1] \
>  			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" \
> -			".exe.ltrans0" [lindex $args 3]
> +			".ltrans0.ltrans" [lindex $args 3]
>      } else {
>  	scan-dump-times "ltrans-tree" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" ".exe.ltrans0"
> +			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" ".ltrans0.ltrans"
>      }
>  }
>  
> @@ -87,11 +87,11 @@ proc scan-ltrans-tree-dump-not { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-not "ltrans-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
> +		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
>  		      [lindex $args 2]
>      } else {
>  	scan-dump-not "ltrans-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
> +		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
>      }
>  }
>  
> @@ -113,11 +113,11 @@ proc scan-ltrans-tree-dump-dem { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-dem "ltrans-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
> +		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
>  		      [lindex $args 2]
>      } else {
>  	scan-dump-dem "ltrans-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
> +		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
>      }
>  }
>  
> @@ -139,10 +139,10 @@ proc scan-ltrans-tree-dump-dem-not { args } {
>      if { [llength $args] >= 3 } {
>  	scan-dump-dem-not "ltrans-tree" [lindex $args 0] \
>  			  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" \
> -			  ".exe.ltrans0" [lindex $args 2]
> +			  ".ltrans0.ltrans" [lindex $args 2]
>      } else {
>  	scan-dump-dem-not "ltrans-tree" [lindex $args 0] \
>  			  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" \
> -			  ".exe.ltrans0"
> +			  ".ltrans0.ltrans"
>      }
>  }
> diff --git a/gcc/testsuite/lib/scanwpaipa.exp b/gcc/testsuite/lib/scanwpaipa.exp
> index d00b400..39e95b8 100644
> --- a/gcc/testsuite/lib/scanwpaipa.exp
> +++ b/gcc/testsuite/lib/scanwpaipa.exp
> @@ -37,11 +37,11 @@ proc scan-wpa-ipa-dump { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump "wpa-ipa" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
> +		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
>  		  [lindex $args 2]
>      } else {
>  	scan-dump "wpa-ipa" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
> +		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
>      }
>  }
>  
> @@ -62,11 +62,11 @@ proc scan-wpa-ipa-dump-times { args } {
>      }
>      if { [llength $args] >= 4 } {
>  	scan-dump-times "wpa-ipa" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".exe.wpa" \
> +			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".wpa" \
>  			[lindex $args 3]
>      } else {
>  	scan-dump-times "wpa-ipa" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".exe.wpa"
> +			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".wpa"
>      }
>  }
>  
> @@ -87,11 +87,11 @@ proc scan-wpa-ipa-dump-not { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-not "wpa-ipa" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
> +		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
>  		      [lindex $args 2]
>      } else {
>  	scan-dump-not "wpa-ipa" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
> +		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
>      }
>  }
>  
> @@ -113,11 +113,11 @@ proc scan-wpa-ipa-dump-dem { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-dem "wpa-ipa" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
> +		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
>  		      [lindex $args 2]
>      } else {
>  	scan-dump-dem "wpa-ipa" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
> +		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
>      }
>  }
>  
> @@ -138,10 +138,10 @@ proc scan-wpa-ipa-dump-dem-not { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-dem-not "wpa-ipa" [lindex $args 0] \
> -			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
> +			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
>  			  [lindex $args 2]
>      } else {
>  	scan-dump-dem-not "wpa-ipa" [lindex $args 0] \
> -			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
> +			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
>      }
>  }
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index 4c8be50..04f8938 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -796,8 +796,8 @@ print_switch_values (print_switch_fn_type print_fn)
>  	case OPT_o:
>  	case OPT_d:
>  	case OPT_dumpbase:
> +	case OPT_dumpbase_ext:
>  	case OPT_dumpdir:
> -	case OPT_auxbase:
>  	case OPT_quiet:
>  	case OPT_version:
>  	  /* Ignore these.  */
> @@ -1410,11 +1410,19 @@ process_options (void)
>    /* Set aux_base_name if not already set.  */
>    if (aux_base_name)
>      ;
> -  else if (main_input_filename)
> +  else if (dump_base_name)
>      {
> -      char *name = xstrdup (lbasename (main_input_filename));
> +      const char *name = dump_base_name;
> +      int nlen, len;
> +
> +      if (dump_base_ext && (len = strlen (dump_base_ext))
> +	  && (nlen = strlen (name)) && nlen > len
> +	  && strcmp (name + nlen - len, dump_base_ext) == 0)
> +	{
> +	  char *p = xstrndup (name, nlen - len);
> +	  name = p;
> +	}
>  
> -      strip_off_ending (name, strlen (name));
>        aux_base_name = name;
>      }
>    else
> @@ -1961,8 +1969,21 @@ static int
>  lang_dependent_init (const char *name)
>  {
>    location_t save_loc = input_location;
> -  if (dump_base_name == 0)
> -    dump_base_name = name && name[0] ? name : "gccdump";
> +  if (!dump_base_name)
> +    {
> +      dump_base_name = name && name[0] ? name : "gccdump";
> +
> +      /* We do not want to derive a non-empty dumpbase-ext from an
> +	 explicit -dumpbase argument, only from a defaulted
> +	 dumpbase.  */
> +      if (!dump_base_ext)
> +	{
> +	  const char *base = lbasename (dump_base_name);
> +	  const char *ext = strrchr (base, '.');
> +	  if (ext)
> +	    dump_base_ext = ext;
> +	}
> +    }
>  
>    /* Other front-end initialization.  */
>    input_location = BUILTINS_LOCATION;
> @@ -1974,20 +1995,25 @@ lang_dependent_init (const char *name)
>      {
>        init_asm_output (name);
>  
> -      /* If stack usage information is desired, open the output file.  */
> -      if (flag_stack_usage && !flag_generate_lto)
> -	stack_usage_file = open_auxiliary_file ("su");
> -
> -      /* If call graph information is desired, open the output file.  */
> -      if (flag_callgraph_info && !flag_generate_lto)
> +      if (!flag_generate_lto && !flag_compare_debug)
>  	{
> -	  callgraph_info_file = open_auxiliary_file ("ci");
> -	  /* Write the file header.  */
> -	  fprintf (callgraph_info_file,
> -		   "graph: { title: \"%s\"\n", main_input_filename);
> -	  bitmap_obstack_initialize (NULL);
> -	  callgraph_info_external_printed = BITMAP_ALLOC (NULL);
> +	  /* If stack usage information is desired, open the output file.  */
> +	  if (flag_stack_usage)
> +	    stack_usage_file = open_auxiliary_file ("su");
> +
> +	  /* If call graph information is desired, open the output file.  */
> +	  if (flag_callgraph_info)
> +	    {
> +	      callgraph_info_file = open_auxiliary_file ("ci");
> +	      /* Write the file header.  */
> +	      fprintf (callgraph_info_file,
> +		       "graph: { title: \"%s\"\n", main_input_filename);
> +	      bitmap_obstack_initialize (NULL);
> +	      callgraph_info_external_printed = BITMAP_ALLOC (NULL);
> +	    }
>  	}
> +      else
> +	flag_stack_usage = flag_callgraph_info = false;
>      }
>  
>    /* This creates various _DECL nodes, so needs to be called after the
> diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c
> index c307fc8..30f9cca 100644
> --- a/lto-plugin/lto-plugin.c
> +++ b/lto-plugin/lto-plugin.c
> @@ -195,6 +195,10 @@ static int linker_output_set;
>  static int linker_output_known;
>  static const char *link_output_name = NULL;
>  
> +/* This indicates link_output_name already contains the dot of the
> +   suffix, so we can skip it in extensions.  */
> +static int skip_in_suffix = 0;
> +
>  /* The version of gold being used, or -1 if not gold.  The number is
>     MAJOR * 100 + MINOR.  */
>  static int gold_version = -1;
> @@ -567,14 +571,11 @@ exec_lto_wrapper (char *argv[])
>    /* Write argv to a file to avoid a command line that is too long
>       Save the file locally on save-temps.  */
>    if (save_temps && link_output_name)
> -    {
> -      arguments_file_name = (char *) xmalloc (strlen (link_output_name)
> -				  + sizeof (".lto_wrapper_args") + 1);
> -      strcpy (arguments_file_name, link_output_name);
> -      strcat (arguments_file_name, ".lto_wrapper_args");
> -    }
> +    arguments_file_name = concat (link_output_name,
> +				  ".lto_wrapper_args"
> +				  + skip_in_suffix, NULL);
>    else
> -     arguments_file_name = make_temp_file (".lto_wrapper_args");
> +    arguments_file_name = make_temp_file (".lto_wrapper_args");
>    check (arguments_file_name, LDPL_FATAL,
>           "Failed to generate a temorary file name");
>  
> @@ -1312,12 +1313,82 @@ onload (struct ld_plugin_tv *tv)
>        if (strstr (collect_gcc_options, "'-fno-use-linker-plugin'"))
>  	return LDPS_ERR;
>  
> -      if ( strstr (collect_gcc_options, "'-save-temps'"))
> +      if (strstr (collect_gcc_options, "'-save-temps'"))
>  	save_temps = true;
>  
>        if (strstr (collect_gcc_options, "'-v'")
>            || strstr (collect_gcc_options, "'--verbose'"))
>  	verbose = true;
> +
> +      const char *p;
> +      if ((p = strstr (collect_gcc_options, "'-dumpdir'")))
> +	{
> +	  p += sizeof ("'-dumpdir'");
> +	  while (*p == ' ')
> +	    p++;
> +	  const char *start = p;
> +	  int ticks = 0, escapes = 0;
> +	  /* Count ticks (') and escaped (\.) characters.  Stop at the
> +	     end of the options or at a blank after an even number of
> +	     ticks (not counting escaped ones.  */
> +	  for (p = start; *p; p++)
> +	    {
> +	      if (*p == '\'')
> +		{
> +		  ticks++;
> +		  continue;
> +		}
> +	      else if ((ticks % 2) != 0)
> +		{
> +		  if (*p == ' ')
> +		    break;
> +		  if (*p == '\\')
> +		    {
> +		      if (*++p)
> +			escapes++;
> +		      else
> +			p--;
> +		    }
> +		}
> +	    }
> +
> +	  /* Now allocate a new link_output_name and decode dumpdir
> +	     into it.  The loop uses the same logic, except it counts
> +	     ticks and escapes backwards (so ticks is adjusted if we
> +	     find an odd number of them), and it copies characters
> +	     that are escaped or not otherwise skipped.  */
> +	  int len = p - start - ticks - escapes + 1;
> +	  char *q = xmalloc (len);
> +	  link_output_name = q;
> +	  int oddticks = (ticks % 2);
> +	  ticks += oddticks;
> +	  for (p = start; *p; p++)
> +	    {
> +	      if (*p == '\'')
> +		{
> +		  ticks--;
> +		  continue;
> +		}
> +	      else if ((ticks % 2) != 0)
> +		{
> +		  if (*p == ' ')
> +		    break;
> +		  if (*p == '\\')
> +		    {
> +		      if (*++p)
> +			escapes--;
> +		      else
> +			p--;
> +		    }
> +		}
> +	      *q++ = *p;
> +	    }
> +	  *q = '\0';
> +	  assert (escapes == 0);
> +	  assert (ticks == oddticks);
> +	  assert (q - link_output_name == len - 1);
> +	  skip_in_suffix = 1;
> +	}
>      }
>  
>    return LDPS_OK;
> 
>
Alexandre Oliva Jan. 22, 2020, 1:11 a.m. UTC | #43
On Jan 20, 2020, Richard Biener <rguenther@suse.de> wrote:

> On Thu, 16 Jan 2020, Alexandre Oliva wrote:

>> Here it is, at last, regstrapped on x86_64-linux-gnu.  Ok to install?

> I'm hesitant to approve it now since we're in stage4 and been too
> permissive already.  So ...

> OK for GCC 11.

Thanks, that sounds quite reasonable.  The patch itself is not very
invasive, but the behavior changes could probably use a longer time of
pre-release community use before hitting a release.  I'm queuing it up
for when we get to stage 1.

I suppose I might go ahead and install the libiberty follow-up patch
approved by Joseph, and squash the lto-wrapper portion into the larger
patch.  Please let me know in case you think the libiberty change to
preserve empty arguments should also be deferred to 11.
Richard Biener Jan. 22, 2020, 7:58 a.m. UTC | #44
On Tue, 21 Jan 2020, Alexandre Oliva wrote:

> On Jan 20, 2020, Richard Biener <rguenther@suse.de> wrote:
> 
> > On Thu, 16 Jan 2020, Alexandre Oliva wrote:
> 
> >> Here it is, at last, regstrapped on x86_64-linux-gnu.  Ok to install?
> 
> > I'm hesitant to approve it now since we're in stage4 and been too
> > permissive already.  So ...
> 
> > OK for GCC 11.
> 
> Thanks, that sounds quite reasonable.  The patch itself is not very
> invasive, but the behavior changes could probably use a longer time of
> pre-release community use before hitting a release.  I'm queuing it up
> for when we get to stage 1.
> 
> I suppose I might go ahead and install the libiberty follow-up patch
> approved by Joseph, and squash the lto-wrapper portion into the larger
> patch.  Please let me know in case you think the libiberty change to
> preserve empty arguments should also be deferred to 11.

I think it's fine to make that change now.

Richard.
Alexandre Oliva Jan. 23, 2020, 7:43 p.m. UTC | #45
On Jan 22, 2020, Richard Biener <rguenther@suse.de> wrote:

>> I suppose I might go ahead and install the libiberty follow-up patch
>> approved by Joseph, and squash the lto-wrapper portion into the larger
>> patch.  Please let me know in case you think the libiberty change to
>> preserve empty arguments should also be deferred to 11.

> I think it's fine to make that change now.

Here's the split-out patch I'm installing now.  The other fragment is
being combined with the patch pending for GCC 11 stage 1.


[libiberty] output empty args as a pair of quotes

From: Alexandre Oliva <oliva@adacore.com>

writeargv writes out empty arguments in a way that expandargv skips
them instead of preserving them.  Fixed by writing out a pair of
quotes for them.


for  libiberty/ChangeLog

	* argv.c (writeargv): Output empty args as "".
---
 libiberty/argv.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/libiberty/argv.c b/libiberty/argv.c
index 8c9794db..6a72208 100644
--- a/libiberty/argv.c
+++ b/libiberty/argv.c
@@ -327,6 +327,14 @@ writeargv (char * const *argv, FILE *f)
           arg++;
         }
 
+      /* Write out a pair of quotes for an empty argument.  */
+      if (arg == *argv)
+	if (EOF == fputs ("\"\"", f))
+	  {
+	    status = 1;
+	    goto done;
+	  }
+
       if (EOF == fputc ('\n', f))
         {
           status = 1;
Alexandre Oliva Jan. 23, 2020, 11:53 p.m. UTC | #46
On Jan 22, 2020, Richard Biener <rguenther@suse.de> wrote:

> I think it's fine to make that change now.

FTR, the combined patch, to be installed in GCC 11, is commit
f798a915a2a00ff7921644d0e08cb88e7db581a2, in
refs/users/aoliva/heads/aux-dump-revamp

I'm not reposting the monster patch right now.
Alexandre Oliva May 19, 2020, 8:51 a.m. UTC | #47
I've refreshed the patch, approved back on Jan 22 for gcc-11, in
refs/users/aoliva/heads/aux-dump-revamp, and committed 3 other related
patches on top of it, that I hope to get approved for folding and joint
installation:

- fix a build problem when targeting platforms with an executable suffix

- fix spurious outputs.exp test failures on targets that do not support
  -gsplit-dwarf

- fix for outputs.exp for platforms with nonempty ldflags, libs,
  ldscripts, or output_format in the dejagnu board configuration, and
  for link tests with aux dumps in the testsuite when ldflags, libs or
  ldscripts in the board config name files that gcc would regard as
  additional inputs.

I'll post followups with each of the patches for review.
Alexandre Oliva May 19, 2020, 8:59 a.m. UTC | #48
On May 19, 2020, Alexandre Oliva <oliva@adacore.com> wrote:

> - fix a build problem when targeting platforms with an executable suffix

aux and dump revamp: fix target exec suffix handling

HAVE_TARGET_EXECUTABLE_SUFFIX is defined only in gcc.c, and in a way
that requires testing whether it's defined, rather than for nonzero.
Fixed the new use in gcc.c, copied the fix and the definition to
lto-wrapper.c.


for  gcc/ChangeLog

	* lto-wrapper.c (HAVE_TARGET_EXECUTABLE_SUFFIX): Define if...
	(TARGET_EXECUTABLE_SUFFIX): ... is defined; define this to the
	empty string otherwise.
	(run_gcc): Test for HAVE_TARGET_EXECUTABLE_SUFFIX with defined.
	* gcc.c (process_command): Likewise.
---
 gcc/gcc.c         |    2 +-
 gcc/lto-wrapper.c |    9 ++++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/gcc/gcc.c b/gcc/gcc.c
index 1e4ac9d..8c851d7 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -4966,7 +4966,7 @@ process_command (unsigned int decoded_options_count,
 	      : ((temp = strrchr (obase + 1, '.'))
 		 && (xlen = strlen (temp))
 		 && (strcmp (temp, ".exe") == 0
-#if HAVE_TARGET_EXECUTABLE_SUFFIX
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
 		     || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
 #endif
 		     || strcmp (obase, "a.out") == 0)))
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index 026c419..d565b08 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -53,6 +53,13 @@ along with GCC; see the file COPYING3.  If not see
    driver to lto-wrapper.  */
 #define OFFLOAD_TARGET_NAMES_ENV	"OFFLOAD_TARGET_NAMES"
 
+/* By default there is no special suffix for target executables.  */
+#ifdef TARGET_EXECUTABLE_SUFFIX
+#define HAVE_TARGET_EXECUTABLE_SUFFIX
+#else
+#define TARGET_EXECUTABLE_SUFFIX ""
+#endif
+
 enum lto_mode_d {
   LTO_MODE_NONE,			/* Not doing LTO.  */
   LTO_MODE_LTO,				/* Normal LTO.  */
@@ -1509,7 +1516,7 @@ run_gcc (unsigned argc, char *argv[])
 	  if ((temp = strrchr (obase + 1, '.'))
 	      && (xlen = strlen (temp))
 	      && (strcmp (temp, ".exe") == 0
-#if HAVE_TARGET_EXECUTABLE_SUFFIX
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
 		  || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
 #endif
 		  || strcmp (obase, "a.out") == 0))
Alexandre Oliva May 19, 2020, 8:59 a.m. UTC | #49
On May 19, 2020, Alexandre Oliva <oliva@adacore.com> wrote:

> - fix spurious outputs.exp test failures on targets that do not support
>   -gsplit-dwarf

cope with -gsplit-dwarf errors

From: Alexandre Oliva <oliva@adacore.com>

On targets that did not support -gsplit-dwarf, we'd get tons of
spurious failures.  This patch tests for support early on, and drops
the option and disregards the absence of .dwo files if unsupported.


for  gcc/testsuite/ChangeLog

	* gcc.misc-tests/outputs.exp (gsplit_dwarf): New.  Use it
        instead of -gsplit-dwarf all over.
	(outest): Disregard .dwo expectations if unsupported.
---
 gcc/testsuite/gcc.misc-tests/outputs.exp |  452 +++++++++++++++---------------
 1 file changed, 232 insertions(+), 220 deletions(-)

diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp
index a063334..6cb2c64 100644
--- a/gcc/testsuite/gcc.misc-tests/outputs.exp
+++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
@@ -36,6 +36,13 @@ if ![gcc_parallel_test_run_p $b] {
 }
 gcc_parallel_test_enable 0
 
+set gsplit_dwarf "-gsplit-dwarf"
+if ![check_no_compiler_messages gsplitdwarf object {
+    void foo (void) { }
+} "$gsplit_dwarf"] {
+    set gsplit_dwarf ""
+}
+
 # For the test named TEST, run the compiler with SOURCES and OPTS, and
 # look in DIRS for OUTPUTS.  SOURCES is a list of suffixes for source
 # files starting with $b in $srcdir/$subdir, OPTS is a string with
@@ -56,6 +63,7 @@ proc outest { test sources opts dirs outputs } {
     global b
     global srcdir
     global subdir
+    global gsplit_dwarf
     set src {}
     foreach s $sources {
 	lappend src $srcdir/$subdir/$b$s
@@ -78,8 +86,8 @@ proc outest { test sources opts dirs outputs } {
     foreach d $dirs olist $outputs {
 	foreach og $olist {
 	    if { [string index $og 0] == "-" } then {
-		if { [string index $og 1] == "-" || \
-			 [string index $og 1] == "." } then {
+		if { [string index $og 1] == "-" \
+		     || [string index $og 1] == "." } then {
 		    set o "$b-$b[string range $og 1 end]"
 		} else {
 		    set o "$b$og"
@@ -93,6 +101,10 @@ proc outest { test sources opts dirs outputs } {
 	    } else {
 		set o "$og"
 	    }
+	    if { "$gsplit_dwarf" == "" \
+		 && [string match "*.dwo" "$og"] } then {
+		continue
+	    }
 	    if { [file exists $d$o] } then {
 		pass "$test: $d$o"
 		file delete $d$o
@@ -267,102 +279,102 @@ outest "$b exe ddstovr namedir2" $mult "-o $b.exe -save-temps -dumpdir o/" {o/}
 # Compiler- and driver-generated aux and dump outputs.
 # -fdump-rtl-final creates a .c.???r.final dump in the compiler.
 # -fstack-usage creates a .su aux output in the compiler.
-# -gsplit-dwarf extracts a .dwo aux output from the .o in the driver.
-outest "$b asm auxdump 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.s}}
-outest "$b asm auxdump 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-1.c.???r.final -1.su -1.s -2.c.???r.final -2.su -2.s}}
-outest "$b obj auxdump unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
-outest "$b obj auxdump unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-1.c.???r.final -1.su -1.dwo -1.o -2.c.???r.final -2.su -2.dwo -2.o}}
-
-outest "$b cpp auxdump named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.i}}
-outest "$b asm auxdump named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.s}}
-outest "$b obj auxdump named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
-outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.i}}
-outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.c.???r.final .su .s}}
-outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.c.???r.final .su .dwo .o}}
-
-outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
-outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
-outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
-outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
-outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
-
-outest "$b cpp auxdump namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.i} {}}
-outest "$b asm auxdump namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.s} {}}
-outest "$b obj auxdump namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.o} {}}
-outest "$b cpp auxdump namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.i} {}}
-outest "$b asm auxdump namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.c.???r.final .su .s} {}}
-outest "$b obj auxdump namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.c.???r.final .su .dwo .o} {}}
-outest "$b exe auxdump namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.exe} {}}
-outest "$b exe auxdump namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{--0.c.???r.final --0.su --0.dwo .exe} {}}
-outest "$b exe auxdump namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
+# $gsplit_dwarf extracts a .dwo aux output from the .o in the driver.
+outest "$b asm auxdump 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.s}}
+outest "$b asm auxdump 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-1.c.???r.final -1.su -1.s -2.c.???r.final -2.su -2.s}}
+outest "$b obj auxdump unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+outest "$b obj auxdump unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-1.c.???r.final -1.su -1.dwo -1.o -2.c.???r.final -2.su -2.dwo -2.o}}
+
+outest "$b cpp auxdump named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.i}}
+outest "$b asm auxdump named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.s}}
+outest "$b obj auxdump named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.i}}
+outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .s}}
+outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .dwo .o}}
+
+outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
+outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
+outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
+outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
+outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
+
+outest "$b cpp auxdump namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.i} {}}
+outest "$b asm auxdump namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.s} {}}
+outest "$b obj auxdump namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.o} {}}
+outest "$b cpp auxdump namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.i} {}}
+outest "$b asm auxdump namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.c.???r.final .su .s} {}}
+outest "$b obj auxdump namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.c.???r.final .su .dwo .o} {}}
+outest "$b exe auxdump namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.exe} {}}
+outest "$b exe auxdump namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{--0.c.???r.final --0.su --0.dwo .exe} {}}
+outest "$b exe auxdump namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
 
 # Check that -save-temps doesn't break compiler aux or dumps as it
 # changes temp file names.
-outest "$b asm auxdmps 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
-outest "$b asm auxdmps 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -2.i -2.c.???r.final -2.su -2.s}}
-outest "$b obj auxdmps unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
-outest "$b obj auxdmps unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -1.dwo -1.o -2.i -2.c.???r.final -2.su -2.s -2.dwo -2.o}}
-
-outest "$b cpp auxdmps named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i}}
-outest "$b asm auxdmps named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
-outest "$b obj auxdmps named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
-outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i}}
-outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
-outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
-
-outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
-outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
-outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
-outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
-outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
-
-outest "$b cpp auxdmps namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i} {}}
-outest "$b asm auxdmps namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s} {}}
-outest "$b obj auxdmps namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o} {}}
-outest "$b cpp auxdmps namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i} {}}
-outest "$b asm auxdmps namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i .c.???r.final .su .s} {}}
-outest "$b obj auxdmps namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i .c.???r.final .su .s .dwo .o} {}}
-outest "$b exe auxdmps namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe} {}}
-outest "$b exe auxdmps namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe} {}}
-outest "$b exe auxdmps namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe} {}}
+outest "$b asm auxdmps 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
+outest "$b asm auxdmps 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -2.i -2.c.???r.final -2.su -2.s}}
+outest "$b obj auxdmps unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
+outest "$b obj auxdmps unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -1.dwo -1.o -2.i -2.c.???r.final -2.su -2.s -2.dwo -2.o}}
+
+outest "$b cpp auxdmps named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i}}
+outest "$b asm auxdmps named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
+outest "$b obj auxdmps named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
+outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i}}
+outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
+outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
+
+outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
+outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
+outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
+outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
+outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
+
+outest "$b cpp auxdmps namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i} {}}
+outest "$b asm auxdmps namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s} {}}
+outest "$b obj auxdmps namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o} {}}
+outest "$b cpp auxdmps namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i} {}}
+outest "$b asm auxdmps namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i .c.???r.final .su .s} {}}
+outest "$b obj auxdmps namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i .c.???r.final .su .s .dwo .o} {}}
+outest "$b exe auxdmps namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe} {}}
+outest "$b exe auxdmps namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe} {}}
+outest "$b exe auxdmps namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe} {}}
 
 
 # Check that dumpdir changes the location of non-primary outputs
-outest "$b asm dumpdir 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
-outest "$b asm dumpdir 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -2.c.???r.final -2.su} {-1.s -2.s}}
-outest "$b obj dumpdir unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
-outest "$b obj dumpdir unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {-1.o -2.o}}
-
-outest "$b cpp dumpdir named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{} {-0.i}}
-outest "$b asm dumpdir named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
-outest "$b obj dumpdir named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
-outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{} {.i}}
-outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
-outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
-
-outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
-outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
-outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
-outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
-outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
-outest "$b exe dumpdira namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
-outest "$b exe dumpdira named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
-outest "$b exe dumpdirb namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
-outest "$b exe dumpdirb named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
-
-outest "$b cpp dumpdir namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{} {-0.i} {}}
-outest "$b asm dumpdir namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su} {-0.s} {}}
-outest "$b obj dumpdir namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.o} {}}
-outest "$b cpp dumpdir namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{} {.i} {}}
-outest "$b asm dumpdir namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su} {.s} {}}
-outest "$b obj dumpdir namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su .dwo} {.o} {}}
-outest "$b exe dumpdir namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe} {}}
-outest "$b exe dumpdir namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {.exe} {}}
-outest "$b exe dumpdir namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe} {}}
-outest "$b exe dumpdira namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
-outest "$b exe dumpdira namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
-outest "$b exe dumpdirb namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
-outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b asm dumpdir 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
+outest "$b asm dumpdir 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -2.c.???r.final -2.su} {-1.s -2.s}}
+outest "$b obj dumpdir unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
+outest "$b obj dumpdir unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dumpdir named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{} {-0.i}}
+outest "$b asm dumpdir named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
+outest "$b obj dumpdir named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
+outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{} {.i}}
+outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
+outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
+
+outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
+outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
+outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
+outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
+outest "$b exe dumpdira namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dumpdira named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+outest "$b exe dumpdirb namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
+outest "$b exe dumpdirb named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+
+outest "$b cpp dumpdir namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dumpdir namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su} {-0.s} {}}
+outest "$b obj dumpdir namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.o} {}}
+outest "$b cpp dumpdir namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{} {.i} {}}
+outest "$b asm dumpdir namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su} {.s} {}}
+outest "$b obj dumpdir namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su .dwo} {.o} {}}
+outest "$b exe dumpdir namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe} {}}
+outest "$b exe dumpdir namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {.exe} {}}
+outest "$b exe dumpdir namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe} {}}
+outest "$b exe dumpdira namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
+outest "$b exe dumpdira namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+outest "$b exe dumpdirb namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
+outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
 
 # Check that a -dumpbase with a dir component disregards the -dumpdir
 # prefix.  Also, start testing -dumpbase-ext to distinguish between
@@ -374,90 +386,90 @@ outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack
 # for them all), or when linking (the specified dumpbase is then used
 # as prefix instead of the linker output, and a new dumpbase is
 # computed per source).
-outest "$b asm dbsovrdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
-outest "$b asm dbsovrddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
-outest "$b asm dbsovrdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
-outest "$b asm dbsovrdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
-outest "$b asm dbsovrdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
-outest "$b asm dbsovrddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
-outest "$b obj dbsovrdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
-outest "$b obj dbsovrddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
-outest "$b obj dbsovrdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
-
-outest "$b cpp dbsovrdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {-0.i}}
-outest "$b asm dbsovrdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
-outest "$b obj dbsovrdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
-outest "$b cpp dbsovrdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {.i}}
-outest "$b asm dbsovrdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
-outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
+outest "$b asm dbsovrdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbsovrddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbsovrdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbsovrdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbsovrdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbsovrddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbsovrdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbsovrddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbsovrdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbsovrdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {-0.i}}
+outest "$b asm dbsovrdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbsovrdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbsovrdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {.i}}
+outest "$b asm dbsovrdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
 
 # Nit: -dumpdir affects whether the specified dumpbase is combined
 # into dumpdir or taken as the output basename, even if dumpbase will
 # ultimately override it.
-outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
-outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
-outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
-outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
-outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
-outest "$b exe dbsovrdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
-outest "$b exe dbsovrddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
-outest "$b exe dbsovrdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
-
-outest "$b cpp dbsovrdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
-outest "$b asm dbsovrdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
-outest "$b obj dbsovrdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
-outest "$b cpp dbsovrdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {.i} {}}
-outest "$b asm dbsovrdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
-outest "$b obj dbsovrdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
-outest "$b exe dbsovrdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
-outest "$b exe dbsovrdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
-outest "$b exe dbsovrdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
-outest "$b exe dbsovrdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
-outest "$b exe dbsovrdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
+outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
+outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
+outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbsovrdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbsovrddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbsovrdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbsovrdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbsovrdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbsovrdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbsovrdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbsovrdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbsovrdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbsovrdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
+outest "$b exe dbsovrdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
+outest "$b exe dbsovrdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbsovrdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
+outest "$b exe dbsovrdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
 
 
 # Check that a -dumpbase without a dir component adds to the -dumpdir
 # prefix.
-outest "$b asm dbswthdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
-outest "$b asm dbswthddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
-outest "$b asm dbswthdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
-outest "$b asm dbswthdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
-outest "$b asm dbswthdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
-outest "$b asm dbswthddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
-outest "$b obj dbswthdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
-outest "$b obj dbswthddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
-outest "$b obj dbswthdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
-
-outest "$b cpp dbswthdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {-0.i}}
-outest "$b asm dbswthdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
-outest "$b obj dbswthdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
-outest "$b cpp dbswthdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {.i}}
-outest "$b asm dbswthdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {.s}}
-outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {.o}}
+outest "$b asm dbswthdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbswthddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbswthdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbswthdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbswthdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbswthddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbswthdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbswthddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbswthdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbswthdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {-0.i}}
+outest "$b asm dbswthdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbswthdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbswthdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {.i}}
+outest "$b asm dbswthdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {.o}}
 
 # Nitty details: -dumpdir affects whether the specified dumpbase is
 # combined into dumpdir or taken as the output basename, even if
 # dumpbase will ultimately override it.
-outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
-outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
-outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
-outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
-outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
-outest "$b exe dbswthdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
-outest "$b exe dbswthddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
-outest "$b exe dbswthdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
-
-outest "$b cpp dbswthdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {-0.i} {}}
-outest "$b asm dbswthdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {-0.s} {}}
-outest "$b obj dbswthdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
-outest "$b cpp dbswthdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {.i} {}}
-outest "$b asm dbswthdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {.s} {}}
-outest "$b obj dbswthdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
-outest "$b exe dbswthdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
-outest "$b exe dbswthdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
-outest "$b exe dbswthdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
-outest "$b exe dbswthdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
-outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
+outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
+outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
+outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbswthdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbswthddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbswthdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbswthdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbswthdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbswthdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbswthdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbswthdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbswthdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbswthdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
+outest "$b exe dbswthdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
+outest "$b exe dbswthdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbswthdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
+outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
 
 
 # Check for the minor differences when -dumpbase is used without
@@ -465,48 +477,48 @@ outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstac
 # is in the single-input link tests: with the dump dir/ prefix moved
 # to dumpbase, and without -dumpdir we end up using -dumpbase as the
 # executable prefix rather than as the dumpbase for the single input.
-outest "$b asm dbwoutdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
-outest "$b asm dbwoutddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
-outest "$b asm dbwoutdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
-outest "$b asm dbwoutdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
-outest "$b asm dbwoutdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
-outest "$b asm dbwoutddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
-outest "$b obj dbwoutdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
-outest "$b obj dbwoutddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
-outest "$b obj dbwoutdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
-
-outest "$b cpp dbwoutdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{} {-0.i}}
-outest "$b asm dbwoutdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
-outest "$b obj dbwoutdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
-outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{} {.i}}
-outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
-outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
-
-outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
-outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
-outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
-outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
-outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
-outest "$b exe dbwoutdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
-outest "$b exe dbwoutdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
-outest "$b exe dbwoutddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
-outest "$b exe dbwoutdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
-
-outest "$b cpp dbwoutdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
-outest "$b asm dbwoutdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
-outest "$b obj dbwoutdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
-outest "$b cpp dbwoutdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{} {.i} {}}
-outest "$b asm dbwoutdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
-outest "$b obj dbwoutdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
-outest "$b exe dbwoutdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe} {}}
-outest "$b exe dbwoutdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
-outest "$b exe dbwoutdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
-outest "$b exe dbwoutdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
-outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+outest "$b asm dbwoutdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbwoutddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbwoutdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbwoutdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbwoutdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbwoutddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbwoutdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbwoutddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbwoutdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbwoutdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{} {-0.i}}
+outest "$b asm dbwoutdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbwoutdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{} {.i}}
+outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
+
+outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
+outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
+outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
+outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
+outest "$b exe dbwoutdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbwoutdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dbwoutddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dbwoutdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbwoutdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbwoutdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbwoutdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbwoutdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbwoutdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbwoutdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbwoutdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe} {}}
+outest "$b exe dbwoutdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
+outest "$b exe dbwoutdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbwoutdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
+outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
 
 # -fcompare-debug
-outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage -gsplit-dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
-outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage -gsplit-dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
+outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
+outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
 
 # -flto
 outest "$b lto sing unnamed" $sing "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
@@ -599,16 +611,16 @@ outest "$b lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-
 # but we want to make sure behavior matches the docs.
 
 # gcc -c foo.c ...
-outest "$b doc single  -c !-o" $sing "-c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+outest "$b doc single  -c !-o" $sing "-c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
 
 # gcc -c foo.c -o dir/foobar.o ...
-outest "$b doc single  -c +-o" $sing "-c -o dir/$b.o -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.c.???r.final .su .dwo .o} {}}
+outest "$b doc single  -c +-o" $sing "-c -o dir/$b.o -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo .o} {}}
 
 # gcc foo.c bar.c -o dir/foobar ...
-outest "$b doc double !-c  -o" $mult "-o dir/$b.exe -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
+outest "$b doc double !-c  -o" $mult "-o dir/$b.exe -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
 
 # gcc foo.c -o dir/foo ...
-outest "$b doc single !-c  -o" $sing "-o dir/$b-0 -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo -0} {}}
+outest "$b doc single !-c  -o" $sing "-o dir/$b-0 -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo -0} {}}
 
 # gcc -save-temps -S foo.c
 outest "$b doc single  -S -st" $sing "-save-temps -S" {} {{-0.i -0.s}}
@@ -618,44 +630,44 @@ outest "$b doc single  -c -st -db" $sing "-save-temps -dumpbase $b -c" {} {{.i .
 
 # gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
 #   -dumpdir pfx- -save-temps=cwd ...
-outest "$b doc single  -c  -o -db" $sing "-c -o dir/$b.o -dumpbase alt/$b -dumpdir pfx- -save-temps=cwd -fdump-rtl-final -fstack-usage -gsplit-dwarf" {alt/ dir/} {{.i .s .???r.final .su .dwo} {.o} {}}
+outest "$b doc single  -c  -o -db" $sing "-c -o dir/$b.o -dumpbase alt/$b -dumpdir pfx- -save-temps=cwd -fdump-rtl-final -fstack-usage $gsplit_dwarf" {alt/ dir/} {{.i .s .???r.final .su .dwo} {.o} {}}
 
 # gcc foo.c bar.c -c -dumpbase main ...
-outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo -1.o --2.c.???r.final --2.su --2.dwo -2.o}}
+outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo -1.o --2.c.???r.final --2.su --2.dwo -2.o}}
 
 # gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
-outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
+outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
 
 # gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
 outest "$b doc double !-c  -o -db'' -flto" $mult "-o dir/$b.exe -dumpbase \"\" -flto -O2 -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
 
 
 # gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
-outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
+outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
 
 # gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
-outest "$b doc double !-c  -o -dbx" $mult "-o $b.out -dumpbase-ext .out -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .out}}
+outest "$b doc double !-c  -o -dbx" $mult "-o $b.out -dumpbase-ext .out -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .out}}
 
 # gcc -dumpdir pfx- -c foo.c ...
-outest "$b doc single  -c !-o -dd" $sing "-dumpdir $b- -c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--0.c.???r.final --0.su --0.dwo -0.o}}
+outest "$b doc single  -c !-o -dd" $sing "-dumpdir $b- -c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo -0.o}}
 
 # gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
-outest "$b doc single  -c  -o -dd" $sing "-dumpdir dir/ -c -o obj/$b.o -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/ obj/} {{.c.???r.final .su .dwo} {.o} {}}
+outest "$b doc single  -c  -o -dd" $sing "-dumpdir dir/ -c -o obj/$b.o -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/ obj/} {{.c.???r.final .su .dwo} {.o} {}}
 
 # gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
-outest "$b doc single  -c  -o -dd -st=" $sing "-dumpdir $b- -c -save-temps=obj -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.i -0.s -0.o}}
+outest "$b doc single  -c  -o -dd -st=" $sing "-dumpdir $b- -c -save-temps=obj -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.i -0.s -0.o}}
 
 # gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
-outest "$b doc double  -c !-o -dd -db" $mult "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+outest "$b doc double  -c !-o -dd -db" $mult "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
 
 # gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
-outest "$b doc single  -c !-o -dd -db" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b doc single  -c !-o -dd -db" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
 
 # gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
-outest "$b doc double !-c  -o -dd" $mult "-dumpdir dir/ -o $b.exe -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
+outest "$b doc double !-c  -o -dd" $mult "-dumpdir dir/ -o $b.exe -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
 
 # gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
-outest "$b doc single !-c  -o -dd -st=" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b doc single !-c  -o -dd -st=" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
 
 
 gcc_parallel_test_enable 1
Alexandre Oliva May 19, 2020, 9 a.m. UTC | #50
On May 19, 2020, Alexandre Oliva <oliva@adacore.com> wrote:

> - fix for outputs.exp for platforms with nonempty ldflags, libs,
>   ldscripts, or output_format in the dejagnu board configuration, and
>   for link tests with aux dumps in the testsuite when ldflags, libs or
>   ldscripts in the board config name files that gcc would regard as
>   additional inputs.

protect filenames in linker flags with -Wl,

From: Alexandre Oliva <oliva@adacore.com>

outputs.exp is not suited for remote compilation, so disable it if
host is remote.  Make it so that any extra data that complements fail
messages goes in a separate line, instead of appearing to be part of
the test name.

ldflags, libs, ldscripts and output_format flags that would normally
be passed to the compiler driver when linking would not be passed in
our special arrangement that bypasses the dejagnu requirement of
naming an output file when creating an executable.  With this patch we
collect them into a variable and add them to the options when running
linking tests.

Another issue with linking tests is that any object or library names
in these board configuration knobs would be taken by the compiler
driver as another input, changing the name of auxiliary outputs such
as those that -save-temps creates.  Tests that look for the auxiliary
outputs for single-inputs would not find them, and end up UNSUPPORTED.
This is fixed by prependig "-Wl," to any filename that appears in
ldflags, libs or ldscripts.


for  gcc/testsuite/ChangeLog

	* gcc.misc-tests/outputs.exp: Skip if host is remote.
	(link_options): New.  Compute once, use in all link tests.
	(outest): Move extra notes for fails to separate line.
	* lib/gcc-defs.exp (gcc_adjusted_linker_flags): New.
	(gcc_adjust_linker_flags): New.
	(dg-additional-files-options): Call it.
---
 gcc/testsuite/gcc.misc-tests/outputs.exp |   36 +++++++++++++++++++++++---
 gcc/testsuite/lib/gcc-defs.exp           |   42 ++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp
index 6cb2c64..889db17 100644
--- a/gcc/testsuite/gcc.misc-tests/outputs.exp
+++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
@@ -31,7 +31,7 @@ set b "outputs"
 # doesn't return the same values, so disable parallelization
 # of this *.exp file.  The first parallel runtest to reach
 # this will run all the tests serially.
-if ![gcc_parallel_test_run_p $b] {
+if {![gcc_parallel_test_run_p $b] || [is_remote host]} {
     return
 }
 gcc_parallel_test_enable 0
@@ -43,6 +43,29 @@ if ![check_no_compiler_messages gsplitdwarf object {
     set gsplit_dwarf ""
 }
 
+# Prepare additional options to be used for linking.
+# We do not compile to an executable, because that requires naming an output.
+set link_options ""
+set dest [target_info name]
+foreach i { ldflags libs ldscripts } {
+    if {[board_info $dest exists $i]} {
+	set skip ""
+	foreach opt [split [board_info $dest $i]] {
+	    if { $skip != "" } then {
+		set skip ""
+	    } elseif { $opt == "-Xlinker" } then {
+		set skip $opt
+	    } elseif { ![string match "-*" $opt] && [file isfile $opt] } {
+	    	set opt "-Wl,$opt"
+	    }
+	    append link_options " additional_flags=$opt"
+	}
+    }
+}
+if {[board_info $dest exists output_format]} {
+    append link_options " additional_flags=-Wl,-oformat,[board_info $dest output_format]"
+}
+
 # For the test named TEST, run the compiler with SOURCES and OPTS, and
 # look in DIRS for OUTPUTS.  SOURCES is a list of suffixes for source
 # files starting with $b in $srcdir/$subdir, OPTS is a string with
@@ -79,7 +102,12 @@ proc outest { test sources opts dirs outputs } {
     }
     set options ""
     foreach opt [split $opts " "] {
-	set options "$options additional_flags=$opt"
+	append options " additional_flags=$opt"
+    }
+    # Add linker flags if we're linking
+    if {![string match "* -\[ESc\] *" " $opts "]} {
+	global link_options
+	append options "$link_options"
     }
     set gcc_output [gcc_target_compile $src "" none "$options"]
     set outs {}
@@ -136,13 +164,13 @@ proc outest { test sources opts dirs outputs } {
     if { [llength $outs] == 0 } then {
 	pass "$test: extra"
     } else {
-	fail "$test: extra $outs"
+	fail "$test: extra\n$outs"
     }
 
     if { [string equal "$gcc_output" ""] } then {
 	pass "$test: std out"
     } else {
-	fail "$test: std out $gcc_output"
+	fail "$test: std out\n$gcc_output"
     }
 
 }
diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
index 4abb2b3..fc7e8e2 100644
--- a/gcc/testsuite/lib/gcc-defs.exp
+++ b/gcc/testsuite/lib/gcc-defs.exp
@@ -285,11 +285,53 @@ proc dg-additional-files { args } {
     set additional_files [lindex $args 1]
 }
 
+set gcc_adjusted_linker_flags 0
+
+# Add -Wl, before any file names in ldflags, libs, and ldscripts, so
+# that default object files or libraries do not change the names of
+# gcc auxiliary outputs.
+
+proc gcc_adjust_linker_flags {} {
+    global gcc_adjusted_linker_flags
+    if {$gcc_adjusted_linker_flags} {
+	return
+    }
+    set gcc_adjusted_linker_flags 1
+
+    if {![is_remote host]} {
+	set dest [target_info name]
+	foreach i { ldflags libs ldscripts } {
+	    if {[board_info $dest exists $i]} {
+		set opts [board_info $dest $i]
+		set nopts {}
+		set skip ""
+		foreach opt [split $opts] {
+		    if { $skip != "" } then {
+			set skip ""
+		    } elseif { $opt == "-Xlinker" } then {
+			set skip $opt
+		    } elseif { ![string match "-*" $opt] \
+				&& [file isfile $opt] } {
+			set opt "-Wl,$opt"
+		    }
+		    lappend nopts $opt
+		}
+		if { $nopts != $opts } {
+		    unset_currtarget_info $i
+		    set_currtarget_info $i "$nopts"
+		}
+	    }
+	}
+    }
+}
+
 # Return an updated version of OPTIONS that mentions any additional
 # source files registered with dg-additional-sources.  SOURCE is the
 # name of the test case.
 
 proc dg-additional-files-options { options source } {
+    gcc_adjust_linker_flags
+
     global additional_sources
     global additional_sources_used
     global additional_files
Richard Biener May 19, 2020, 9:04 a.m. UTC | #51
On Tue, 19 May 2020, Alexandre Oliva wrote:

> I've refreshed the patch, approved back on Jan 22 for gcc-11, in
> refs/users/aoliva/heads/aux-dump-revamp, and committed 3 other related
> patches on top of it, that I hope to get approved for folding and joint
> installation:

Thanks again for doing this.  May I also suggest to prepare a short
entry for gcc-11/changes.html with these things (like "Output of
auxiliary files changed.  See https://gcc.gnu.org/ml/gcc-patches/...
for details")?

Richard.

> - fix a build problem when targeting platforms with an executable suffix
> 
> - fix spurious outputs.exp test failures on targets that do not support
>   -gsplit-dwarf
> 
> - fix for outputs.exp for platforms with nonempty ldflags, libs,
>   ldscripts, or output_format in the dejagnu board configuration, and
>   for link tests with aux dumps in the testsuite when ldflags, libs or
>   ldscripts in the board config name files that gcc would regard as
>   additional inputs.
> 
> I'll post followups with each of the patches for review.
Richard Biener May 19, 2020, 9:29 a.m. UTC | #52
On Tue, 19 May 2020, Alexandre Oliva wrote:

> On May 19, 2020, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > - fix a build problem when targeting platforms with an executable suffix
> 
> aux and dump revamp: fix target exec suffix handling
> 
> HAVE_TARGET_EXECUTABLE_SUFFIX is defined only in gcc.c, and in a way
> that requires testing whether it's defined, rather than for nonzero.
> Fixed the new use in gcc.c, copied the fix and the definition to
> lto-wrapper.c.

OK.

> 
> for  gcc/ChangeLog
> 
> 	* lto-wrapper.c (HAVE_TARGET_EXECUTABLE_SUFFIX): Define if...
> 	(TARGET_EXECUTABLE_SUFFIX): ... is defined; define this to the
> 	empty string otherwise.
> 	(run_gcc): Test for HAVE_TARGET_EXECUTABLE_SUFFIX with defined.
> 	* gcc.c (process_command): Likewise.
> ---
>  gcc/gcc.c         |    2 +-
>  gcc/lto-wrapper.c |    9 ++++++++-
>  2 files changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/gcc/gcc.c b/gcc/gcc.c
> index 1e4ac9d..8c851d7 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -4966,7 +4966,7 @@ process_command (unsigned int decoded_options_count,
>  	      : ((temp = strrchr (obase + 1, '.'))
>  		 && (xlen = strlen (temp))
>  		 && (strcmp (temp, ".exe") == 0
> -#if HAVE_TARGET_EXECUTABLE_SUFFIX
> +#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
>  		     || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
>  #endif
>  		     || strcmp (obase, "a.out") == 0)))
> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> index 026c419..d565b08 100644
> --- a/gcc/lto-wrapper.c
> +++ b/gcc/lto-wrapper.c
> @@ -53,6 +53,13 @@ along with GCC; see the file COPYING3.  If not see
>     driver to lto-wrapper.  */
>  #define OFFLOAD_TARGET_NAMES_ENV	"OFFLOAD_TARGET_NAMES"
>  
> +/* By default there is no special suffix for target executables.  */
> +#ifdef TARGET_EXECUTABLE_SUFFIX
> +#define HAVE_TARGET_EXECUTABLE_SUFFIX
> +#else
> +#define TARGET_EXECUTABLE_SUFFIX ""
> +#endif
> +
>  enum lto_mode_d {
>    LTO_MODE_NONE,			/* Not doing LTO.  */
>    LTO_MODE_LTO,				/* Normal LTO.  */
> @@ -1509,7 +1516,7 @@ run_gcc (unsigned argc, char *argv[])
>  	  if ((temp = strrchr (obase + 1, '.'))
>  	      && (xlen = strlen (temp))
>  	      && (strcmp (temp, ".exe") == 0
> -#if HAVE_TARGET_EXECUTABLE_SUFFIX
> +#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
>  		  || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
>  #endif
>  		  || strcmp (obase, "a.out") == 0))
> 
> 
>
Richard Biener May 19, 2020, 9:30 a.m. UTC | #53
On Tue, 19 May 2020, Alexandre Oliva wrote:

> On May 19, 2020, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > - fix spurious outputs.exp test failures on targets that do not support
> >   -gsplit-dwarf
> 
> cope with -gsplit-dwarf errors
> 
> From: Alexandre Oliva <oliva@adacore.com>
> 
> On targets that did not support -gsplit-dwarf, we'd get tons of
> spurious failures.  This patch tests for support early on, and drops
> the option and disregards the absence of .dwo files if unsupported.

OK.

> 
> for  gcc/testsuite/ChangeLog
> 
> 	* gcc.misc-tests/outputs.exp (gsplit_dwarf): New.  Use it
>         instead of -gsplit-dwarf all over.
> 	(outest): Disregard .dwo expectations if unsupported.
> ---
>  gcc/testsuite/gcc.misc-tests/outputs.exp |  452 +++++++++++++++---------------
>  1 file changed, 232 insertions(+), 220 deletions(-)
> 
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp
> index a063334..6cb2c64 100644
> --- a/gcc/testsuite/gcc.misc-tests/outputs.exp
> +++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
> @@ -36,6 +36,13 @@ if ![gcc_parallel_test_run_p $b] {
>  }
>  gcc_parallel_test_enable 0
>  
> +set gsplit_dwarf "-gsplit-dwarf"
> +if ![check_no_compiler_messages gsplitdwarf object {
> +    void foo (void) { }
> +} "$gsplit_dwarf"] {
> +    set gsplit_dwarf ""
> +}
> +
>  # For the test named TEST, run the compiler with SOURCES and OPTS, and
>  # look in DIRS for OUTPUTS.  SOURCES is a list of suffixes for source
>  # files starting with $b in $srcdir/$subdir, OPTS is a string with
> @@ -56,6 +63,7 @@ proc outest { test sources opts dirs outputs } {
>      global b
>      global srcdir
>      global subdir
> +    global gsplit_dwarf
>      set src {}
>      foreach s $sources {
>  	lappend src $srcdir/$subdir/$b$s
> @@ -78,8 +86,8 @@ proc outest { test sources opts dirs outputs } {
>      foreach d $dirs olist $outputs {
>  	foreach og $olist {
>  	    if { [string index $og 0] == "-" } then {
> -		if { [string index $og 1] == "-" || \
> -			 [string index $og 1] == "." } then {
> +		if { [string index $og 1] == "-" \
> +		     || [string index $og 1] == "." } then {
>  		    set o "$b-$b[string range $og 1 end]"
>  		} else {
>  		    set o "$b$og"
> @@ -93,6 +101,10 @@ proc outest { test sources opts dirs outputs } {
>  	    } else {
>  		set o "$og"
>  	    }
> +	    if { "$gsplit_dwarf" == "" \
> +		 && [string match "*.dwo" "$og"] } then {
> +		continue
> +	    }
>  	    if { [file exists $d$o] } then {
>  		pass "$test: $d$o"
>  		file delete $d$o
> @@ -267,102 +279,102 @@ outest "$b exe ddstovr namedir2" $mult "-o $b.exe -save-temps -dumpdir o/" {o/}
>  # Compiler- and driver-generated aux and dump outputs.
>  # -fdump-rtl-final creates a .c.???r.final dump in the compiler.
>  # -fstack-usage creates a .su aux output in the compiler.
> -# -gsplit-dwarf extracts a .dwo aux output from the .o in the driver.
> -outest "$b asm auxdump 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.s}}
> -outest "$b asm auxdump 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-1.c.???r.final -1.su -1.s -2.c.???r.final -2.su -2.s}}
> -outest "$b obj auxdump unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> -outest "$b obj auxdump unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-1.c.???r.final -1.su -1.dwo -1.o -2.c.???r.final -2.su -2.dwo -2.o}}
> -
> -outest "$b cpp auxdump named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.i}}
> -outest "$b asm auxdump named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.s}}
> -outest "$b obj auxdump named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> -outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.i}}
> -outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.c.???r.final .su .s}}
> -outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{.c.???r.final .su .dwo .o}}
> -
> -outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
> -outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
> -outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
> -outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
> -outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
> -
> -outest "$b cpp auxdump namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.i} {}}
> -outest "$b asm auxdump namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.s} {}}
> -outest "$b obj auxdump namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.o} {}}
> -outest "$b cpp auxdump namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.i} {}}
> -outest "$b asm auxdump namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.c.???r.final .su .s} {}}
> -outest "$b obj auxdump namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{.c.???r.final .su .dwo .o} {}}
> -outest "$b exe auxdump namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.exe} {}}
> -outest "$b exe auxdump namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{--0.c.???r.final --0.su --0.dwo .exe} {}}
> -outest "$b exe auxdump namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf" {o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
> +# $gsplit_dwarf extracts a .dwo aux output from the .o in the driver.
> +outest "$b asm auxdump 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.s}}
> +outest "$b asm auxdump 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-1.c.???r.final -1.su -1.s -2.c.???r.final -2.su -2.s}}
> +outest "$b obj auxdump unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +outest "$b obj auxdump unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-1.c.???r.final -1.su -1.dwo -1.o -2.c.???r.final -2.su -2.dwo -2.o}}
> +
> +outest "$b cpp auxdump named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.i}}
> +outest "$b asm auxdump named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.s}}
> +outest "$b obj auxdump named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.i}}
> +outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .s}}
> +outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .dwo .o}}
> +
> +outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
> +outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
> +outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
> +outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
> +outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
> +
> +outest "$b cpp auxdump namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.i} {}}
> +outest "$b asm auxdump namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.s} {}}
> +outest "$b obj auxdump namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.o} {}}
> +outest "$b cpp auxdump namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.i} {}}
> +outest "$b asm auxdump namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.c.???r.final .su .s} {}}
> +outest "$b obj auxdump namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.c.???r.final .su .dwo .o} {}}
> +outest "$b exe auxdump namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.exe} {}}
> +outest "$b exe auxdump namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{--0.c.???r.final --0.su --0.dwo .exe} {}}
> +outest "$b exe auxdump namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
>  
>  # Check that -save-temps doesn't break compiler aux or dumps as it
>  # changes temp file names.
> -outest "$b asm auxdmps 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
> -outest "$b asm auxdmps 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -2.i -2.c.???r.final -2.su -2.s}}
> -outest "$b obj auxdmps unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
> -outest "$b obj auxdmps unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -1.dwo -1.o -2.i -2.c.???r.final -2.su -2.s -2.dwo -2.o}}
> -
> -outest "$b cpp auxdmps named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i}}
> -outest "$b asm auxdmps named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
> -outest "$b obj auxdmps named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
> -outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i}}
> -outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
> -outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
> -
> -outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
> -outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
> -outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
> -outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
> -outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
> -
> -outest "$b cpp auxdmps namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i} {}}
> -outest "$b asm auxdmps namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s} {}}
> -outest "$b obj auxdmps namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o} {}}
> -outest "$b cpp auxdmps namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i} {}}
> -outest "$b asm auxdmps namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i .c.???r.final .su .s} {}}
> -outest "$b obj auxdmps namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{.i .c.???r.final .su .s .dwo .o} {}}
> -outest "$b exe auxdmps namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe} {}}
> -outest "$b exe auxdmps namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe} {}}
> -outest "$b exe auxdmps namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -save-temps" {o/} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe} {}}
> +outest "$b asm auxdmps 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
> +outest "$b asm auxdmps 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -2.i -2.c.???r.final -2.su -2.s}}
> +outest "$b obj auxdmps unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
> +outest "$b obj auxdmps unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -1.dwo -1.o -2.i -2.c.???r.final -2.su -2.s -2.dwo -2.o}}
> +
> +outest "$b cpp auxdmps named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i}}
> +outest "$b asm auxdmps named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
> +outest "$b obj auxdmps named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
> +outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i}}
> +outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
> +outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
> +
> +outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
> +outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
> +outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
> +outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
> +outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
> +
> +outest "$b cpp auxdmps namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i} {}}
> +outest "$b asm auxdmps namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s} {}}
> +outest "$b obj auxdmps namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o} {}}
> +outest "$b cpp auxdmps namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i} {}}
> +outest "$b asm auxdmps namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i .c.???r.final .su .s} {}}
> +outest "$b obj auxdmps namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i .c.???r.final .su .s .dwo .o} {}}
> +outest "$b exe auxdmps namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe} {}}
> +outest "$b exe auxdmps namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe} {}}
> +outest "$b exe auxdmps namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe} {}}
>  
>  
>  # Check that dumpdir changes the location of non-primary outputs
> -outest "$b asm dumpdir 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
> -outest "$b asm dumpdir 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -2.c.???r.final -2.su} {-1.s -2.s}}
> -outest "$b obj dumpdir unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
> -outest "$b obj dumpdir unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {-1.o -2.o}}
> -
> -outest "$b cpp dumpdir named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{} {-0.i}}
> -outest "$b asm dumpdir named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
> -outest "$b obj dumpdir named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
> -outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{} {.i}}
> -outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
> -outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
> -
> -outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
> -outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> -outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
> -outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
> -outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
> -outest "$b exe dumpdira namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> -outest "$b exe dumpdira named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> -outest "$b exe dumpdirb namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
> -outest "$b exe dumpdirb named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> -
> -outest "$b cpp dumpdir namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{} {-0.i} {}}
> -outest "$b asm dumpdir namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su} {-0.s} {}}
> -outest "$b obj dumpdir namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.o} {}}
> -outest "$b cpp dumpdir namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{} {.i} {}}
> -outest "$b asm dumpdir namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su} {.s} {}}
> -outest "$b obj dumpdir namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su .dwo} {.o} {}}
> -outest "$b exe dumpdir namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe} {}}
> -outest "$b exe dumpdir namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {.exe} {}}
> -outest "$b exe dumpdir namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/" {od/ o/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe} {}}
> -outest "$b exe dumpdira namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
> -outest "$b exe dumpdira namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/a-" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> -outest "$b exe dumpdirb namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
> -outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/$b-" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b asm dumpdir 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
> +outest "$b asm dumpdir 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -2.c.???r.final -2.su} {-1.s -2.s}}
> +outest "$b obj dumpdir unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
> +outest "$b obj dumpdir unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dumpdir named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{} {-0.i}}
> +outest "$b asm dumpdir named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
> +outest "$b obj dumpdir named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
> +outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{} {.i}}
> +outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
> +outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
> +
> +outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
> +outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
> +outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
> +outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
> +outest "$b exe dumpdira namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dumpdira named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +outest "$b exe dumpdirb namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
> +outest "$b exe dumpdirb named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +
> +outest "$b cpp dumpdir namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dumpdir namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su} {-0.s} {}}
> +outest "$b obj dumpdir namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.o} {}}
> +outest "$b cpp dumpdir namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{} {.i} {}}
> +outest "$b asm dumpdir namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su} {.s} {}}
> +outest "$b obj dumpdir namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dumpdir namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe} {}}
> +outest "$b exe dumpdir namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {.exe} {}}
> +outest "$b exe dumpdir namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe} {}}
> +outest "$b exe dumpdira namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
> +outest "$b exe dumpdira namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +outest "$b exe dumpdirb namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
> +outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
>  
>  # Check that a -dumpbase with a dir component disregards the -dumpdir
>  # prefix.  Also, start testing -dumpbase-ext to distinguish between
> @@ -374,90 +386,90 @@ outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack
>  # for them all), or when linking (the specified dumpbase is then used
>  # as prefix instead of the linker output, and a new dumpbase is
>  # computed per source).
> -outest "$b asm dbsovrdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> -outest "$b asm dbsovrddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> -outest "$b asm dbsovrdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> -outest "$b asm dbsovrdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> -outest "$b asm dbsovrdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> -outest "$b asm dbsovrddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> -outest "$b obj dbsovrdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> -outest "$b obj dbsovrddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> -outest "$b obj dbsovrdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> -
> -outest "$b cpp dbsovrdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {-0.i}}
> -outest "$b asm dbsovrdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> -outest "$b obj dbsovrdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> -outest "$b cpp dbsovrdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {.i}}
> -outest "$b asm dbsovrdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
> -outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
> +outest "$b asm dbsovrdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbsovrddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbsovrdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbsovrdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbsovrdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbsovrddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbsovrdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbsovrddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbsovrdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbsovrdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {-0.i}}
> +outest "$b asm dbsovrdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbsovrdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbsovrdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {.i}}
> +outest "$b asm dbsovrdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
>  
>  # Nit: -dumpdir affects whether the specified dumpbase is combined
>  # into dumpdir or taken as the output basename, even if dumpbase will
>  # ultimately override it.
> -outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
> -outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> -outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
> -outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
> -outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> -outest "$b exe dbsovrdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
> -outest "$b exe dbsovrddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
> -outest "$b exe dbsovrdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> -
> -outest "$b cpp dbsovrdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
> -outest "$b asm dbsovrdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> -outest "$b obj dbsovrdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> -outest "$b cpp dbsovrdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {.i} {}}
> -outest "$b asm dbsovrdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
> -outest "$b obj dbsovrdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> -outest "$b exe dbsovrdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
> -outest "$b exe dbsovrdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
> -outest "$b exe dbsovrdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> -outest "$b exe dbsovrdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
> -outest "$b exe dbsovrdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
> +outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
> +outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
> +outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbsovrdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbsovrddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbsovrdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbsovrdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbsovrdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbsovrdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbsovrdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbsovrdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbsovrdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbsovrdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
> +outest "$b exe dbsovrdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
> +outest "$b exe dbsovrdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbsovrdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
> +outest "$b exe dbsovrdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
>  
>  
>  # Check that a -dumpbase without a dir component adds to the -dumpdir
>  # prefix.
> -outest "$b asm dbswthdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
> -outest "$b asm dbswthddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> -outest "$b asm dbswthdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> -outest "$b asm dbswthdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> -outest "$b asm dbswthdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> -outest "$b asm dbswthddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> -outest "$b obj dbswthdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
> -outest "$b obj dbswthddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> -outest "$b obj dbswthdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> -
> -outest "$b cpp dbswthdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {-0.i}}
> -outest "$b asm dbswthdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
> -outest "$b obj dbswthdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
> -outest "$b cpp dbswthdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {.i}}
> -outest "$b asm dbswthdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {.s}}
> -outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {.o}}
> +outest "$b asm dbswthdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbswthddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbswthdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbswthdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbswthdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbswthddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbswthdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbswthddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbswthdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbswthdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {-0.i}}
> +outest "$b asm dbswthdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbswthdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbswthdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {.i}}
> +outest "$b asm dbswthdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {.o}}
>  
>  # Nitty details: -dumpdir affects whether the specified dumpbase is
>  # combined into dumpdir or taken as the output basename, even if
>  # dumpbase will ultimately override it.
> -outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
> -outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> -outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
> -outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
> -outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> -outest "$b exe dbswthdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
> -outest "$b exe dbswthddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
> -outest "$b exe dbswthdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> -
> -outest "$b cpp dbswthdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {-0.i} {}}
> -outest "$b asm dbswthdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> -outest "$b obj dbswthdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> -outest "$b cpp dbswthdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {.i} {}}
> -outest "$b asm dbswthdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {.s} {}}
> -outest "$b obj dbswthdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> -outest "$b exe dbswthdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
> -outest "$b exe dbswthdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
> -outest "$b exe dbswthdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> -outest "$b exe dbswthdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
> -outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
> +outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
> +outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
> +outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbswthdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbswthddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbswthdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbswthdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbswthdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbswthdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbswthdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbswthdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbswthdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbswthdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
> +outest "$b exe dbswthdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
> +outest "$b exe dbswthdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbswthdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
> +outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
>  
>  
>  # Check for the minor differences when -dumpbase is used without
> @@ -465,48 +477,48 @@ outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstac
>  # is in the single-input link tests: with the dump dir/ prefix moved
>  # to dumpbase, and without -dumpdir we end up using -dumpbase as the
>  # executable prefix rather than as the dumpbase for the single input.
> -outest "$b asm dbwoutdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> -outest "$b asm dbwoutddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> -outest "$b asm dbwoutdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> -outest "$b asm dbwoutdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> -outest "$b asm dbwoutdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> -outest "$b asm dbwoutddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> -outest "$b obj dbwoutdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> -outest "$b obj dbwoutddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> -outest "$b obj dbwoutdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> -
> -outest "$b cpp dbwoutdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{} {-0.i}}
> -outest "$b asm dbwoutdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> -outest "$b obj dbwoutdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> -outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{} {.i}}
> -outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
> -outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
> -
> -outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
> -outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> -outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
> -outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
> -outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
> -outest "$b exe dbwoutdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> -outest "$b exe dbwoutdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> -outest "$b exe dbwoutddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> -outest "$b exe dbwoutdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> -
> -outest "$b cpp dbwoutdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
> -outest "$b asm dbwoutdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> -outest "$b obj dbwoutdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> -outest "$b cpp dbwoutdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{} {.i} {}}
> -outest "$b asm dbwoutdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
> -outest "$b obj dbwoutdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> -outest "$b exe dbwoutdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe} {}}
> -outest "$b exe dbwoutdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
> -outest "$b exe dbwoutdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> -outest "$b exe dbwoutdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
> -outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage -gsplit-dwarf -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +outest "$b asm dbwoutdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbwoutddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbwoutdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbwoutdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbwoutdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbwoutddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbwoutdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbwoutddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbwoutdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbwoutdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{} {-0.i}}
> +outest "$b asm dbwoutdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbwoutdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{} {.i}}
> +outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
> +
> +outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
> +outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
> +outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
> +outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
> +outest "$b exe dbwoutdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbwoutdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dbwoutddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dbwoutdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbwoutdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbwoutdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbwoutdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbwoutdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbwoutdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbwoutdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbwoutdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe} {}}
> +outest "$b exe dbwoutdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
> +outest "$b exe dbwoutdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbwoutdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
> +outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
>  
>  # -fcompare-debug
> -outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage -gsplit-dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
> -outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage -gsplit-dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
> +outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
> +outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
>  
>  # -flto
>  outest "$b lto sing unnamed" $sing "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> @@ -599,16 +611,16 @@ outest "$b lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-
>  # but we want to make sure behavior matches the docs.
>  
>  # gcc -c foo.c ...
> -outest "$b doc single  -c !-o" $sing "-c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +outest "$b doc single  -c !-o" $sing "-c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
>  
>  # gcc -c foo.c -o dir/foobar.o ...
> -outest "$b doc single  -c +-o" $sing "-c -o dir/$b.o -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.c.???r.final .su .dwo .o} {}}
> +outest "$b doc single  -c +-o" $sing "-c -o dir/$b.o -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo .o} {}}
>  
>  # gcc foo.c bar.c -o dir/foobar ...
> -outest "$b doc double !-c  -o" $mult "-o dir/$b.exe -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
> +outest "$b doc double !-c  -o" $mult "-o dir/$b.exe -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
>  
>  # gcc foo.c -o dir/foo ...
> -outest "$b doc single !-c  -o" $sing "-o dir/$b-0 -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo -0} {}}
> +outest "$b doc single !-c  -o" $sing "-o dir/$b-0 -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo -0} {}}
>  
>  # gcc -save-temps -S foo.c
>  outest "$b doc single  -S -st" $sing "-save-temps -S" {} {{-0.i -0.s}}
> @@ -618,44 +630,44 @@ outest "$b doc single  -c -st -db" $sing "-save-temps -dumpbase $b -c" {} {{.i .
>  
>  # gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
>  #   -dumpdir pfx- -save-temps=cwd ...
> -outest "$b doc single  -c  -o -db" $sing "-c -o dir/$b.o -dumpbase alt/$b -dumpdir pfx- -save-temps=cwd -fdump-rtl-final -fstack-usage -gsplit-dwarf" {alt/ dir/} {{.i .s .???r.final .su .dwo} {.o} {}}
> +outest "$b doc single  -c  -o -db" $sing "-c -o dir/$b.o -dumpbase alt/$b -dumpdir pfx- -save-temps=cwd -fdump-rtl-final -fstack-usage $gsplit_dwarf" {alt/ dir/} {{.i .s .???r.final .su .dwo} {.o} {}}
>  
>  # gcc foo.c bar.c -c -dumpbase main ...
> -outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo -1.o --2.c.???r.final --2.su --2.dwo -2.o}}
> +outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo -1.o --2.c.???r.final --2.su --2.dwo -2.o}}
>  
>  # gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
> -outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
> +outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
>  
>  # gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
>  outest "$b doc double !-c  -o -db'' -flto" $mult "-o dir/$b.exe -dumpbase \"\" -flto -O2 -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
>  
>  
>  # gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
> -outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
> +outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
>  
>  # gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
> -outest "$b doc double !-c  -o -dbx" $mult "-o $b.out -dumpbase-ext .out -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .out}}
> +outest "$b doc double !-c  -o -dbx" $mult "-o $b.out -dumpbase-ext .out -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .out}}
>  
>  # gcc -dumpdir pfx- -c foo.c ...
> -outest "$b doc single  -c !-o -dd" $sing "-dumpdir $b- -c -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{--0.c.???r.final --0.su --0.dwo -0.o}}
> +outest "$b doc single  -c !-o -dd" $sing "-dumpdir $b- -c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo -0.o}}
>  
>  # gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
> -outest "$b doc single  -c  -o -dd" $sing "-dumpdir dir/ -c -o obj/$b.o -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/ obj/} {{.c.???r.final .su .dwo} {.o} {}}
> +outest "$b doc single  -c  -o -dd" $sing "-dumpdir dir/ -c -o obj/$b.o -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/ obj/} {{.c.???r.final .su .dwo} {.o} {}}
>  
>  # gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
> -outest "$b doc single  -c  -o -dd -st=" $sing "-dumpdir $b- -c -save-temps=obj -fdump-rtl-final -fstack-usage -gsplit-dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.i -0.s -0.o}}
> +outest "$b doc single  -c  -o -dd -st=" $sing "-dumpdir $b- -c -save-temps=obj -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.i -0.s -0.o}}
>  
>  # gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
> -outest "$b doc double  -c !-o -dd -db" $mult "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +outest "$b doc double  -c !-o -dd -db" $mult "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
>  
>  # gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
> -outest "$b doc single  -c !-o -dd -db" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b doc single  -c !-o -dd -db" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
>  
>  # gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
> -outest "$b doc double !-c  -o -dd" $mult "-dumpdir dir/ -o $b.exe -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
> +outest "$b doc double !-c  -o -dd" $mult "-dumpdir dir/ -o $b.exe -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
>  
>  # gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
> -outest "$b doc single !-c  -o -dd -st=" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage -gsplit-dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b doc single !-c  -o -dd -st=" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
>  
>  
>  gcc_parallel_test_enable 1
> 
> 
>
Alexandre Oliva May 22, 2020, 12:32 a.m. UTC | #54
On May 19, 2020, Richard Biener <rguenther@suse.de> wrote:

> On Tue, 19 May 2020, Alexandre Oliva wrote:
>> I've refreshed the patch, approved back on Jan 22 for gcc-11, in
>> refs/users/aoliva/heads/aux-dump-revamp, and committed 3 other related
>> patches on top of it, that I hope to get approved for folding and joint
>> installation:

> Thanks again for doing this.  May I also suggest to prepare a short
> entry for gcc-11/changes.html with these things (like "Output of
> auxiliary files changed.  See https://gcc.gnu.org/ml/gcc-patches/...
> for details")?

How about, under Caveats:

* Naming and location of auxiliary and dump output files changed.  If
you compile multiple input files in a single command, if you enable Link
Time Optimization, or if you use -dumpbase, -dumpdir, -save-temps=*, and
you expect any file other than the primary output file(s) to be created
as a side effect, watch out for improvements and a few surprises.  See
https://gcc.gnu.org/ml/...


Before I can check it all in, I'm still missing a review of:

https://gcc.gnu.org/pipermail/gcc-patches/2020-May/546015.html

Did you by any chance miss it, or choose not to review it?

Any takers?

I've just realized I failed to mention I'd regstrapped the patchset on
x86_64-linux-gnu, and got successful cross builds and regression test
results for arm-elf, aarch64-elf, aarch64-vx7r2, and x86_64-windows.
Richard Biener May 22, 2020, 6:05 a.m. UTC | #55
On Thu, 21 May 2020, Alexandre Oliva wrote:

> On May 19, 2020, Richard Biener <rguenther@suse.de> wrote:
> 
> > On Tue, 19 May 2020, Alexandre Oliva wrote:
> >> I've refreshed the patch, approved back on Jan 22 for gcc-11, in
> >> refs/users/aoliva/heads/aux-dump-revamp, and committed 3 other related
> >> patches on top of it, that I hope to get approved for folding and joint
> >> installation:
> 
> > Thanks again for doing this.  May I also suggest to prepare a short
> > entry for gcc-11/changes.html with these things (like "Output of
> > auxiliary files changed.  See https://gcc.gnu.org/ml/gcc-patches/...
> > for details")?
> 
> How about, under Caveats:
> 
> * Naming and location of auxiliary and dump output files changed.  If
> you compile multiple input files in a single command, if you enable Link
> Time Optimization, or if you use -dumpbase, -dumpdir, -save-temps=*, and
> you expect any file other than the primary output file(s) to be created
> as a side effect, watch out for improvements and a few surprises.  See
> https://gcc.gnu.org/ml/...

Looks good to me.

> 
> Before I can check it all in, I'm still missing a review of:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2020-May/546015.html
> 
> Did you by any chance miss it, or choose not to review it?

I looked at it shortly but decided somebody else may have more knowledge
there - I'd simply trust you'd done things correctly...

So unless anybody comes up to review and ack it consider it approved
by me after the weekend ;)

Thanks,
Richard.

> Any takers?
> 
> I've just realized I failed to mention I'd regstrapped the patchset on
> x86_64-linux-gnu, and got successful cross builds and regression test
> results for arm-elf, aarch64-elf, aarch64-vx7r2, and x86_64-windows.
> 
>
Alexandre Oliva May 26, 2020, 7:08 a.m. UTC | #56
On May 22, 2020, Richard Biener <rguenther@suse.de> wrote:

>> https://gcc.gnu.org/pipermail/gcc-patches/2020-May/546015.html
>> 
>> Did you by any chance miss it, or choose not to review it?

> I looked at it shortly but decided somebody else may have more knowledge
> there - I'd simply trust you'd done things correctly...

> So unless anybody comes up to review and ack it consider it approved
> by me after the weekend ;)

Thanks, here's the combined patch I'm checking in.

revamp dump and aux output names

From: Alexandre Oliva <oliva@adacore.com>

This patch simplifies (!!!) the logic governing the naming of dump
files and auxiliary output files in the driver, in the compiler, and
in the LTO wrapper.  No changes are made to the naming of primary
outputs, there are often ways to restore past behavior, and a number
of inconsistencies are fixed.  Some internal options are removed
(-auxbase and -auxbase-strip), sensible existing uses of -dumpdir and
-dumpbase options remain unchanged, additional useful cases are added,
making for what is still admittedly quite complex.  Extensive
documentation and testcases provide numerous examples, from normal to
corner cases.

The most visible changes are:

- aux and dump files now always go in the same directory, that
defaults to the directory of the primary output, but that can be
overridden with -dumpdir, -save-temps=*, or, preserving past behavior,
with a -dumpbase with a directory component.

- driver and compiler now have the same notion of naming of auxiliary
outputs, e.g. .dwo files will no longer be in one location while the
debug info suggests they are elsewhere, and -save-temps and .dwo
auxiliary outputs now go in the same location as .su, .ci and
coverage data, with consistent naming.

- explicitly-specified primary output names guide not only the
location of aux and dump outputs: the output base name is also used in
their base name, as a prefix when also linking (e.g. foo.c bar.c -o
foobar creates foobar-foo.dwo and foobar-bar.dwo with -gsplit-dwarf),
or as the base name instead of the input name (foo.c -c -o whatever.o
creates whatever.su rather than foo.su with -fstack-usage).  The
preference for the input file base name, quite useful for our
testsuite, can be restored with -dumpbase "".  When compiling and
linking tests in the testsuite with additional inputs, we now use this
flag.  Files named in dejagnu board ldflags, libs, and ldscripts are
now quoted in the gcc testsuite with -Wl, so that they are not counted
as additional inputs by the compiler driver.

- naming a -dumpbase when compiling multiple sources used to cause
dumps from later compiles to overwrite those of earlier ones; it is
now used as a prefix when compiling multiple sources, like an
executable name above.

- the dumpbase, explicitly specified or computed from output or input
names, now also governs the naming of aux outputs; since aux outputs
usually replaced the suffix from the input name, while dump outputs
append their own additional suffixes, a -dumpbase-ext option is
introduced to enable a chosen suffix to be dropped from dumpbase to
form aux output names.

- LTO dump and aux outputs were quite a mess, sometimes leaking
temporary output names into -save-temps output names, sometimes
conversely generating desirable aux outputs in temporary locations.
They now obey the same logic of compiler aux and dump outputs, landing
in the expected location and taking the linker output name or an
explicit dumpbase overrider into account.

- Naming of -fdump-final-insns outputs now follows the dump file
naming logic for the .gkd files, and the .gk dump files generated in
the second -fcompare-debug compilation get the .gk inserted before the
suffix that -dumpbase-ext drops in aux outputs.


gcc/ChangeLog:

	* common.opt (aux_base_name): Define.
	(dumpbase, dumpdir): Mark as Driver options.
	(-dumpbase, -dumpdir): Likewise.
	(dumpbase-ext, -dumpbase-ext): New.
	(auxbase, auxbase-strip): Drop.
	* doc/invoke.texi (-dumpbase, -dumpbase-ext, -dumpdir):
	Document.
	(-o): Introduce the notion of primary output, mention it
	influences auxiliary and dump output names as well, add
	examples.
	(-save-temps): Adjust, move examples into -dump*.
	(-save-temps=cwd, -save-temps=obj): Likewise.
	(-fdump-final-insns): Adjust.
	* dwarf2out.c (gen_producer_string): Drop auxbase and
	auxbase_strip; add dumpbase_ext.
	* gcc.c (enum save_temps): Add SAVE_TEMPS_DUMP.
	(save_temps_prefix, save_temps_length): Drop.
	(save_temps_overrides_dumpdir): New.
	(dumpdir, dumpbase, dumpbase_ext): New.
	(dumpdir_length, dumpdir_trailing_dash_added): New.
	(outbase, outbase_length): New.
	(The Specs Language): Introduce %".  Adjust %b and %B.
	(ASM_FINAL_SPEC): Use %b.dwo for an aux output name always.
	Precede object file with %w when it's the primary output.
	(cpp_debug_options): Do not pass on incoming -dumpdir,
	-dumpbase and -dumpbase-ext options; recompute them with
	%:dumps.
	(cc1_options): Drop auxbase with and without compare-debug;
	use cpp_debug_options instead of dumpbase.  Mark asm output
	with %w when it's the primary output.
	(static_spec_functions): Drop %:compare-debug-auxbase-opt and
	%:replace-exception.  Add %:dumps.
	(driver_handle_option): Implement -save-temps=*/-dumpdir
	mutual overriding logic.  Save dumpdir, dumpbase and
	dumpbase-ext options.  Do not save output_file in
	save_temps_prefix.
	(adds_single_suffix_p): New.
	(single_input_file_index): New.
	(process_command): Combine output dir, output base name, and
	dumpbase into dumpdir and outbase.
	(set_collect_gcc_options): Pass a possibly-adjusted -dumpdir.
	(do_spec_1): Optionally dumpdir instead of save_temps_prefix,
	and outbase instead of input_basename in %b, %B and in
	-save-temps aux files.  Handle empty argument %".
	(driver::maybe_run_linker): Adjust dumpdir and auxbase.
	(compare_debug_dump_opt_spec_function): Adjust gkd dump file
	naming.  Spec-quote the computed -fdump-final-insns file name.
	(debug_auxbase_opt): Drop.
	(compare_debug_self_opt_spec_function): Drop auxbase-strip
	computation.
	(compare_debug_auxbase_opt_spec_function): Drop.
	(not_actual_file_p): New.
	(replace_extension_spec_func): Drop.
	(dumps_spec_func): New.
	(convert_white_space): Split-out parts into...
	(quote_string, whitespace_to_convert_p): ... these.  New.
	(quote_spec_char_p, quote_spec, quote_spec_arg): New.
	(driver::finalize): Release and reset new variables; drop
	removed ones.
	* lto-wrapper.c (HAVE_TARGET_EXECUTABLE_SUFFIX): Define if...
	(TARGET_EXECUTABLE_SUFFIX): ... is defined; define this to the
	empty string otherwise.
	(DUMPBASE_SUFFIX): Drop leading period.
	(debug_objcopy): Use concat.
	(run_gcc): Recognize -save-temps=* as -save-temps too.  Obey
	-dumpdir.  Pass on empty dumpdir and dumpbase with a directory
	component.  Simplify temp file names.
	* opts.c (finish_options): Drop aux base name handling.
	(common_handle_option): Drop auxbase-strip handling.
	* toplev.c (print_switch_values): Drop auxbase, add
	dumpbase-ext.
	(process_options): Derive aux_base_name from dump_base_name
	and dump_base_ext.
	(lang_dependent_init): Compute dump_base_ext along with
	dump_base_name.  Disable stack usage and callgraph-info	during
	lto generation and compare-debug recompilation.

gcc/fortran/ChangeLog:

	* options.c (gfc_get_option_string): Drop auxbase, add
	dumpbase_ext.

gcc/ada/ChangeLog:

	* gcc-interface/lang-specs.h: Drop auxbase and auxbase-strip.
	Use %:dumps instead of -dumpbase.  Add %w for implicit .s
	primary output.
	* switch.adb (Is_Internal_GCC_Switch): Recognize dumpdir and
	dumpbase-ext.  Drop auxbase and auxbase-strip.

lto-plugin/ChangeLog:

	* lto-plugin.c (skip_in_suffix): New.
	(exec_lto_wrapper): Use skip_in_suffix and concat to build
	non-temporary output names.
	(onload): Look for -dumpdir in COLLECT_GCC_OPTIONS, and
	override link_output_name with it.

contrib/ChangeLog:

	* compare-debug: Adjust for .gkd files named as dump files,
	with the source suffix rather than the object suffix.

gcc/testsuite/ChangeLog:

	* gcc.misc-tests/outputs.exp: New.
	* gcc.misc-tests/outputs-0.c: New.
	* gcc.misc-tests/outputs-1.c: New.
	* gcc.misc-tests/outputs-2.c: New.
	* lib/gcc-defs.exp (gcc_adjusted_linker_flags): New.
	(gcc_adjust_linker_flags): New.
	(dg-additional-files-options): Call it.  Pass -dumpbase ""
	when there are additional sources.
	* lib/profopt.exp (profopt-execute): Pass the executable
	suffix with -dumpbase-ext.
	* lib/scandump.exp (dump-base): Mention -dumpbase "" use.
	* lib/scanltranstree.exp: Adjust dump suffix expectation.
	* lib/scanwpaipa.exp: Likewise.
---
 contrib/compare-debug                    |   26 +
 gcc/ada/gcc-interface/lang-specs.h       |   16 -
 gcc/ada/switch.adb                       |    4 
 gcc/common.opt                           |   27 +
 gcc/doc/invoke.texi                      |  385 +++++++++++-
 gcc/dwarf2out.c                          |    3 
 gcc/fortran/options.c                    |    4 
 gcc/gcc.c                                |  938 ++++++++++++++++++++++++------
 gcc/lto-wrapper.c                        |  157 ++---
 gcc/opts.c                               |   35 -
 gcc/testsuite/gcc.misc-tests/outputs-0.c |    1 
 gcc/testsuite/gcc.misc-tests/outputs-1.c |    4 
 gcc/testsuite/gcc.misc-tests/outputs-2.c |    2 
 gcc/testsuite/gcc.misc-tests/outputs.exp |  695 ++++++++++++++++++++++
 gcc/testsuite/lib/gcc-defs.exp           |   46 +
 gcc/testsuite/lib/profopt.exp            |   10 
 gcc/testsuite/lib/scandump.exp           |    3 
 gcc/testsuite/lib/scanltranstree.exp     |   20 -
 gcc/testsuite/lib/scanwpaipa.exp         |   20 -
 gcc/toplev.c                             |   62 +-
 lto-plugin/lto-plugin.c                  |   87 +++
 21 files changed, 2126 insertions(+), 419 deletions(-)
 create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-0.c
 create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-1.c
 create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-2.c
 create mode 100644 gcc/testsuite/gcc.misc-tests/outputs.exp

diff --git a/contrib/compare-debug b/contrib/compare-debug
index 22870cf..cf80ae3 100755
--- a/contrib/compare-debug
+++ b/contrib/compare-debug
@@ -2,7 +2,7 @@
 
 # Compare stripped copies of two given object files.
 
-# Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation
+# Copyright (C) 2007, 2008, 2009, 2010, 2012, 2020 Free Software Foundation
 # Originally by Alexandre Oliva <aoliva@redhat.com>
 
 # This file is part of GCC.
@@ -183,8 +183,28 @@ $rm "$1.$suf1" "$2.$suf2"
 
 trap "exit $status; exit" 0 1 2 15
 
-if test -f "$1".gkd || test -f "$2".gkd; then
-  if cmp "$1".gkd "$2".gkd; then
+# Replace the suffix in $1 and $2 with .*.gkd, compare them if a
+# single file is found by the globbing.
+base1=`echo "$1" | sed '$s,\.[^.]*$,,'` gkd1=
+for f in "$base1".*.gkd; do
+  if test "x$gkd1" != x; then
+    gkd1=
+    break
+  elif test -f "$f"; then
+    gkd1=$f
+  fi
+done
+base2=`echo "$2" | sed '$s,\.[^.]*$,,'` gkd2=
+for f in "$base2".*.gkd; do
+  if test "x$gkd2" != x; then
+    gkd2=
+    break
+  elif test -f "$f"; then
+    gkd2=$f
+  fi
+done
+if test "x$gkd1" != x || test "x$gkd2" != x; then
+  if cmp "${gkd1-/dev/null}" "${gkd2-/dev/null}"; then
     :
   else
     status=$?
diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
index 10f8473..12b7cf5e 100644
--- a/gcc/ada/gcc-interface/lang-specs.h
+++ b/gcc/ada/gcc-interface/lang-specs.h
@@ -34,17 +34,15 @@
  %{!S:%{!c:%e-c or -S required for Ada}}\
  gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
-    %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b) -gnatd_A} \
-    %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}}} \
-    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} \
+    %{fcompare-debug-second:-gnatd_A} \
+    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
     %{coverage:-fprofile-arcs -ftest-coverage} "
 #if defined(TARGET_VXWORKS_RTP)
    "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
 #endif
    "%{gnatea:-gnatez} %{g*&m*&f*} "
    "%1 %{!S:%{o*:%w%*-gnatO}} \
-    %i %{S:%W{o*}%{!o*:-o %b.s}} \
+    %i %{S:%W{o*}%{!o*:-o %w%b.s}} \
     %{gnatc*|gnats*: -o %j} %{-param*} \
     %{!gnatc*:%{!gnats*:%(invoke_as)}}", 0, 0, 0},
 
@@ -53,9 +51,7 @@
  %{!c:%e-c required for gnat2why}\
  gnat1why %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
-    %{o*:-auxbase-strip %*}%{!o*:-auxbase %b} \
-    %{a} %{d*} \
+    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
     %{gnatea:-gnatez} %{g*&m*&f*} \
     %1 %{o*:%w%*-gnatO} \
     %i \
@@ -66,9 +62,7 @@
  %{!c:%e-c required for gnat2scil}\
  gnat1scil %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
-    %{o*:-auxbase-strip %*}%{!o*:-auxbase %b} \
-    %{a} %{d*} \
+    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
     %{gnatea:-gnatez} %{g*&m*&f*} \
     %1 %{o*:%w%*-gnatO} \
     %i \
diff --git a/gcc/ada/switch.adb b/gcc/ada/switch.adb
index 7cdaa196..b6f4e00 100644
--- a/gcc/ada/switch.adb
+++ b/gcc/ada/switch.adb
@@ -163,9 +163,9 @@ package body Switch is
       return Is_Switch (Switch_Chars)
         and then
           (Switch_Chars (First .. Last) = "-param"        or else
+           Switch_Chars (First .. Last) = "dumpdir"       or else
            Switch_Chars (First .. Last) = "dumpbase"      or else
-           Switch_Chars (First .. Last) = "auxbase-strip" or else
-           Switch_Chars (First .. Last) = "auxbase");
+           Switch_Chars (First .. Last) = "dumpbase-ext");
    end Is_Internal_GCC_Switch;
 
    ---------------
diff --git a/gcc/common.opt b/gcc/common.opt
index 4464049..1b770bc 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -188,6 +188,12 @@ const char *main_input_basename
 Variable
 int main_input_baselength
 
+; The base name used for auxiliary output files.
+; dump_base_name minus dump_base_ext.
+
+Variable
+const char *aux_base_name
+
 ; Which options have been printed by --help.
 Variable
 char *help_printed
@@ -252,10 +258,13 @@ Common Separate Alias(d)
 Common Joined Alias(d)
 
 -dumpbase
-Common Separate Alias(dumpbase)
+Driver Common Separate Alias(dumpbase)
+
+-dumpbase-ext
+Driver Common Separate Alias(dumpbase-ext)
 
 -dumpdir
-Common Separate Alias(dumpdir)
+Driver Common Separate Alias(dumpdir)
 
 -entry
 Driver Separate Alias(e)
@@ -852,12 +861,6 @@ Common Separate Var(aux_info_file_name)
 aux-info=
 Common Joined Alias(aux-info)
 
-auxbase
-Common Separate RejectDriver Var(aux_base_name)
-
-auxbase-strip
-Common Separate RejectDriver
-
 coverage
 Driver
 
@@ -869,11 +872,15 @@ Common Joined
 -d<letters>	Enable dumps from specific passes of the compiler.
 
 dumpbase
-Common Separate Var(dump_base_name)
+Driver Common Separate Var(dump_base_name)
 -dumpbase <file>	Set the file basename to be used for dumps.
 
+dumpbase-ext
+Driver Common Separate Var(dump_base_ext)
+-dumpbase-ext .<ext>    Drop a trailing .<ext> from the dump basename to name auxiliary output files.
+
 dumpdir
-Common Separate Var(dump_dir_name)
+Driver Common Separate Var(dump_dir_name)
 -dumpdir <dir>	Set the directory name to be used for dumps.
 
 dumpmachine
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 8b9935d..78c2f50 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -185,7 +185,9 @@ in the following sections.
 @table @emph
 @item Overall Options
 @xref{Overall Options,,Options Controlling the Kind of Output}.
-@gccoptlist{-c  -S  -E  -o @var{file}  -x @var{language}  @gol
+@gccoptlist{-c  -S  -E  -o @var{file} @gol
+-dumpbase @var{dumpbase}  -dumpbase-ext @var{auxdropsuf} @gol
+-dumpdir @var{dumppfx}  -x @var{language}  @gol
 -v  -###  --help@r{[}=@var{class}@r{[},@dots{}@r{]]}  --target-help  --version @gol
 -pass-exit-codes  -pipe  -specs=@var{file}  -wrapper  @gol
 @@@var{file}  -ffile-prefix-map=@var{old}=@var{new}  @gol
@@ -1602,9 +1604,9 @@ Input files that don't require preprocessing are ignored.
 @cindex output file option
 @item -o @var{file}
 @opindex o
-Place output in file @var{file}.  This applies to whatever
-sort of output is being produced, whether it be an executable file,
-an object file, an assembler file or preprocessed C code.
+Place the primary output in file @var{file}.  This applies to whatever
+sort of output is being produced, whether it be an executable file, an
+object file, an assembler file or preprocessed C code.
 
 If @option{-o} is not specified, the default is to put an executable
 file in @file{a.out}, the object file for
@@ -1613,6 +1615,314 @@ assembler file in @file{@var{source}.s}, a precompiled header file in
 @file{@var{source}.@var{suffix}.gch}, and all preprocessed C source on
 standard output.
 
+Though @option{-o} names only the primary output, it also affects the
+naming of auxiliary and dump outputs.  See the examples below.  Unless
+overridden, both auxiliary outputs and dump outputs are placed in the
+same directory as the primary output.  In auxiliary outputs, the suffix
+of the input file is replaced with that of the auxiliary output file
+type; in dump outputs, the suffix of the dump file is appended to the
+input file suffix.  In compilation commands, the base name of both
+auxiliary and dump outputs is that of the primary output; in compile and
+link commands, the primary output name, minus the executable suffix, is
+combined with the input file name.  If both share the same base name,
+disregarding the suffix, the result of the combination is that base
+name, otherwise, they are concatenated, separated by a dash.
+
+@smallexample
+gcc -c foo.c ...
+@end smallexample
+
+will use @file{foo.o} as the primary output, and place aux outputs and
+dumps next to it, e.g., aux file @file{foo.dwo} for
+@option{-gsplit-dwarf}, and dump file @file{foo.c.???r.final} for
+@option{-fdump-rtl-final}.
+
+If a non-linker output file is explicitly specified, aux and dump files
+by default take the same base name:
+
+@smallexample
+gcc -c foo.c -o dir/foobar.o ...
+@end smallexample
+
+will name aux outputs @file{dir/foobar.*} and dump outputs
+@file{dir/foobar.c.*}.
+
+A linker output will instead prefix aux and dump outputs:
+
+@smallexample
+gcc foo.c bar.c -o dir/foobar ...
+@end smallexample
+
+will generally name aux outputs @file{dir/foobar-foo.*} and
+@file{dir/foobar-bar.*}, and dump outputs @file{dir/foobar-foo.c.*} and
+@file{dir/foobar-bar.c.*}.
+
+The one exception to the above is when the executable shares the base
+name with the single input:
+
+@smallexample
+gcc foo.c -o dir/foo ...
+@end smallexample
+
+in which case aux outputs are named @file{dir/foo.*} and dump outputs
+named @file{dir/foo.c.*}.
+
+The location and the names of auxiliary and dump outputs can be adjusted
+by the options @option{-dumpbase}, @option{-dumpbase-ext},
+@option{-dumpdir}, @option{-save-temps=cwd}, and
+@option{-save-temps=obj}.
+
+
+@item -dumpbase @var{dumpbase}
+@opindex dumpbase
+This option sets the base name for auxiliary and dump output files.  It
+does not affect the name of the primary output file.  Intermediate
+outputs, when preserved, are not regarded as primary outputs, but as
+auxiliary outputs:
+
+@smallexample
+gcc -save-temps -S foo.c
+@end smallexample
+
+saves the (no longer) temporary preprocessed file in @file{foo.i}, and
+then compiles to the (implied) output file @file{foo.s}, whereas:
+
+@smallexample
+gcc -save-temps -dumpbase save-foo -c foo.c
+@end smallexample
+
+preprocesses to in @file{save-foo.i}, compiles to @file{save-foo.s} (now
+an intermediate, thus auxiliary output), and then assembles to the
+(implied) output file @file{foo.o}.
+
+Absent this option, dump and aux files take their names from the input
+file, or from the (non-linker) output file, if one is explicitly
+specified: dump output files (e.g. those requested by @option{-fdump-*}
+options) with the input name suffix, and aux output files (those
+requested by other non-dump options, e.g. @code{-save-temps},
+@code{-gsplit-dwarf}, @code{-fcallgraph-info}) without it.
+
+Similar suffix differentiation of dump and aux outputs can be attained
+for explicitly-given @option{-dumpbase basename.suf} by also specifying
+@option{-dumpbase-ext .suf}.
+
+If @var{dumpbase} is explicitly specified with any directory component,
+any @var{dumppfx} specification (e.g. @option{-dumpdir} or
+@option{-save-temps=*}) is ignored, and instead of appending to it,
+@var{dumpbase} fully overrides it:
+
+@smallexample
+gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
+  -dumpdir pfx- -save-temps=cwd ...
+@end smallexample
+
+creates auxiliary and dump outputs named @file{alt/foo.*}, disregarding
+@file{dir/} in @option{-o}, the @file{./} prefix implied by
+@option{-save-temps=cwd}, and @file{pfx-} in @option{-dumpdir}.
+
+When @option{-dumpbase} is specified in a command that compiles multiple
+inputs, or that compiles and then links, it may be combined with
+@var{dumppfx}, as specified under @option{-dumpdir}.  Then, each input
+file is compiled using the combined @var{dumppfx}, and default values
+for @var{dumpbase} and @var{auxdropsuf} are computed for each input
+file:
+
+@smallexample
+gcc foo.c bar.c -c -dumpbase main ...
+@end smallexample
+
+creates @file{foo.o} and @file{bar.o} as primary outputs, and avoids
+overwriting the auxiliary and dump outputs by using the @var{dumpbase}
+as a prefix, creating auxiliary and dump outputs named @file{main-foo.*}
+and @file{main-bar.*}.
+
+An empty string specified as @var{dumpbase} avoids the influence of the
+output basename in the naming of auxiliary and dump outputs during
+compilation, computing default values :
+
+@smallexample
+gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
+@end smallexample
+
+will name aux outputs @file{dir/foo.*} and dump outputs
+@file{dir/foo.c.*}.  Note how their basenames are taken from the input
+name, but the directory still defaults to that of the output.
+
+The empty-string dumpbase does not prevent the use of the output
+basename for outputs during linking:
+
+@smallexample
+gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
+@end smallexample
+
+The compilation of the source files will name auxiliary outputs
+@file{dir/foo.*} and @file{dir/bar.*}, and dump outputs
+@file{dir/foo.c.*} and @file{dir/bar.c.*}.  LTO recompilation during
+linking will use @file{dir/foobar.} as the prefix for dumps and
+auxiliary files.
+
+
+@item -dumpbase-ext @var{auxdropsuf}
+@opindex dumpbase-ext
+When forming the name of an auxiliary (but not a dump) output file, drop
+trailing @var{auxdropsuf} from @var{dumpbase} before appending any
+suffixes.  If not specified, this option defaults to the suffix of a
+default @var{dumpbase}, i.e., the suffix of the input file when
+@option{-dumpbase} is not present in the command line, or @var{dumpbase}
+is combined with @var{dumppfx}.
+
+@smallexample
+gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
+@end smallexample
+
+creates @file{dir/foo.o} as the main output, and generates auxiliary
+outputs in @file{dir/x-foo.*}, taking the location of the primary
+output, and dropping the @file{.c} suffix from the @var{dumpbase}.  Dump
+outputs retain the suffix: @file{dir/x-foo.c.*}.
+
+This option is disregarded if it does not match the suffix of a
+specified @var{dumpbase}, except as an alternative to the executable
+suffix when appending the linker output base name to @var{dumppfx}, as
+specified below:
+
+@smallexample
+gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
+@end smallexample
+
+creates @file{main.out} as the primary output, and avoids overwriting
+the auxiliary and dump outputs by using the executable name minus
+@var{auxdropsuf} as a prefix, creating auxiliary outputs named
+@file{main-foo.*} and @file{main-bar.*} and dump outputs named
+@file{main-foo.c.*} and @file{main-bar.c.*}.
+
+
+@item -dumpdir @var{dumppfx}
+@opindex dumpdir
+When forming the name of an auxiliary or dump output file, use
+@var{dumppfx} as a prefix:
+
+@smallexample
+gcc -dumpdir pfx- -c foo.c ...
+@end smallexample
+
+creates @file{foo.o} as the primary output, and auxiliary outputs named
+@file{pfx-foo.*}, combining the given @var{dumppfx} with the default
+@var{dumpbase} derived from the default primary output, derived in turn
+from the input name.  Dump outputs also take the input name suffix:
+@file{pfx-foo.c.*}.
+
+If @var{dumppfx} is to be used as a directory name, it must end with a
+directory separator:
+
+@smallexample
+gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
+@end smallexample
+
+creates @file{obj/bar.o} as the primary output, and auxiliary outputs
+named @file{dir/bar.*}, combining the given @var{dumppfx} with the
+default @var{dumpbase} derived from the primary output name.  Dump
+outputs also take the input name suffix: @file{dir/bar.c.*}.
+
+It defaults to the location of the output file; options
+@option{-save-temps=cwd} and @option{-save-temps=obj} override this
+default, just like an explicit @option{-dumpdir} option.  In case
+multiple such options are given, the last one prevails:
+
+@smallexample
+gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
+@end smallexample
+
+outputs @file{foo.o}, with auxiliary outputs named @file{foo.*} because
+@option{-save-temps=*} overrides the @var{dumppfx} given by the earlier
+@option{-dumpdir} option.  It does not matter that @option{=obj} is the
+default for @option{-save-temps}, nor that the output directory is
+implicitly the current directory.  Dump outputs are named
+@file{foo.c.*}.
+
+When compiling from multiple input files, if @option{-dumpbase} is
+specified, @var{dumpbase}, minus a @var{auxdropsuf} suffix, and a dash
+are appended to (or override, if containing any directory components) an
+explicit or defaulted @var{dumppfx}, so that each of the multiple
+compilations gets differently-named aux and dump outputs.
+
+@smallexample
+gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
+@end smallexample
+
+outputs auxiliary dumps to @file{dir/pfx-main-foo.*} and
+@file{dir/pfx-main-bar.*}, appending @var{dumpbase}- to @var{dumppfx}.
+Dump outputs retain the input file suffix: @file{dir/pfx-main-foo.c.*}
+and @file{dir/pfx-main-bar.c.*}, respectively.  Contrast with the
+single-input compilation:
+
+@smallexample
+gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
+@end smallexample
+
+that, applying @option{-dumpbase} to a single source, does not compute
+and append a separate @var{dumpbase} per input file.  Its auxiliary and
+dump outputs go in @file{dir/pfx-main.*}.
+
+When compiling and then linking from multiple input files, a defaulted
+or explicitly specified @var{dumppfx} also undergoes the @var{dumpbase}-
+transformation above (e.g. the compilation of @file{foo.c} and
+@file{bar.c} above, but without @option{-c}).  If neither
+@option{-dumpdir} nor @option{-dumpbase} are given, the linker output
+base name, minus @var{auxdropsuf}, if specified, or the executable
+suffix otherwise, plus a dash is appended to the default @var{dumppfx}
+instead.  Note, however, that unlike earlier cases of linking:
+
+@smallexample
+gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
+@end smallexample
+
+does not append the output name @file{main} to @var{dumppfx}, because
+@option{-dumpdir} is explicitly specified.  The goal is that the
+explicitly-specified @var{dumppfx} may contain the specified output name
+as part of the prefix, if desired; only an explicitly-specified
+@option{-dumpbase} would be combined with it, in order to avoid simply
+discarding a meaningful option.
+
+When compiling and then linking from a single input file, the linker
+output base name will only be appended to the default @var{dumppfx} as
+above if it does not share the base name with the single input file
+name.  This has been covered in single-input linking cases above, but
+not with an explicit @option{-dumpdir} that inhibits the combination,
+even if overridden by @option{-save-temps=*}:
+
+@smallexample
+gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
+@end smallexample
+
+Auxiliary outputs are named @file{foo.*}, and dump outputs
+@file{foo.c.*}, in the current working directory as ultimately requested
+by @option{-save-temps=cwd}.
+
+Summing it all up for an intuitive though slightly imprecise data flow:
+the primary output name is broken into a directory part and a basename
+part; @var{dumppfx} is set to the former, unless overridden by
+@option{-dumpdir} or @option{-save-temps=*}, and @var{dumpbase} is set
+to the latter, unless overriden by @option{-dumpbase}.  If there are
+multiple inputs or linking, this @var{dumpbase} may be combined with
+@var{dumppfx} and taken from each input file.  Auxiliary output names
+for each input are formed by combining @var{dumppfx}, @var{dumpbase}
+minus suffix, and the auxiliary output suffix; dump output names are
+only different in that the suffix from @var{dumpbase} is retained.
+
+When it comes to auxiliary and dump outputs created during LTO
+recompilation, a combination of @var{dumppfx} and @var{dumpbase}, as
+given or as derived from the linker output name but not from inputs,
+even in cases in which this combination would not otherwise be used as
+such, is passed down with a trailing period replacing the compiler-added
+dash, if any, as a @option{-dumpdir} option to @command{lto-wrapper};
+being involved in linking, this program does not normally get any
+@option{-dumpbase} and @option{-dumpbase-ext}, and it ignores them.
+
+When running sub-compilers, @command{lto-wrapper} appends LTO stage
+names to the received @var{dumppfx}, ensures it contains a directory
+component so that it overrides any @option{-dumpdir}, and passes that as
+@option{-dumpbase} to sub-compilers.
+
 @item -v
 @opindex v
 Print (on standard error output) the commands executed to run the stages
@@ -16279,54 +16589,28 @@ computing CRC32).
 The @var{string} should be different for every file you compile.
 
 @item -save-temps
-@itemx -save-temps=cwd
 @opindex save-temps
-Store the usual ``temporary'' intermediate files permanently; place them
-in the current directory and name them based on the source file.  Thus,
-compiling @file{foo.c} with @option{-c -save-temps} produces files
-@file{foo.i} and @file{foo.s}, as well as @file{foo.o}.  This creates a
-preprocessed @file{foo.i} output file even though the compiler now
-normally uses an integrated preprocessor.
+Store the usual ``temporary'' intermediate files permanently; name them
+as auxiliary output files, as specified described under
+@option{-dumpbase} and @option{-dumpdir}.
 
 When used in combination with the @option{-x} command-line option,
-@option{-save-temps} is sensible enough to avoid over writing an
+@option{-save-temps} is sensible enough to avoid overwriting an
 input source file with the same extension as an intermediate file.
 The corresponding intermediate file may be obtained by renaming the
 source file before using @option{-save-temps}.
 
-If you invoke GCC in parallel, compiling several different source
-files that share a common base name in different subdirectories or the
-same source file compiled for multiple output destinations, it is
-likely that the different parallel compilers will interfere with each
-other, and overwrite the temporary files.  For instance:
-
-@smallexample
-gcc -save-temps -o outdir1/foo.o indir1/foo.c&
-gcc -save-temps -o outdir2/foo.o indir2/foo.c&
-@end smallexample
-
-may result in @file{foo.i} and @file{foo.o} being written to
-simultaneously by both compilers.
+@item -save-temps=cwd
+@opindex save-temps=cwd
+Equivalent to @option{-save-temps -dumpdir ./}.
 
 @item -save-temps=obj
 @opindex save-temps=obj
-Store the usual ``temporary'' intermediate files permanently.  If the
-@option{-o} option is used, the temporary files are based on the
-object file.  If the @option{-o} option is not used, the
-@option{-save-temps=obj} switch behaves like @option{-save-temps}.
-
-For example:
-
-@smallexample
-gcc -save-temps=obj -c foo.c
-gcc -save-temps=obj -c bar.c -o dir/xbar.o
-gcc -save-temps=obj foobar.c -o dir2/yfoobar
-@end smallexample
-
-@noindent
-creates @file{foo.i}, @file{foo.s}, @file{dir/xbar.i},
-@file{dir/xbar.s}, @file{dir2/yfoobar.i}, @file{dir2/yfoobar.s}, and
-@file{dir2/yfoobar.o}.
+Equivalent to @option{-save-temps -dumpdir @file{outdir/}}, where
+@file{outdir/} is the directory of the output file specified after the
+@option{-o} option, including any directory separators.  If the
+@option{-o} option is not used, the @option{-save-temps=obj} switch
+behaves like @option{-save-temps=cwd}.
 
 @item -time@r{[}=@var{file}@r{]}
 @opindex time
@@ -16363,7 +16647,7 @@ can later tell what file was being compiled, and with which options.
 Dump the final internal representation (RTL) to @var{file}.  If the
 optional argument is omitted (or if @var{file} is @code{.}), the name
 of the dump file is determined by appending @code{.gkd} to the
-compilation output file name.
+dump base name, see @option{-dumpbase}.
 
 @item -fcompare-debug@r{[}=@var{opts}@r{]}
 @opindex fcompare-debug
@@ -30630,17 +30914,24 @@ together or combine them with constant text in a single argument.
 @item %%
 Substitute one @samp{%} into the program name or argument.
 
+@item %"
+Substitute an empty argument.
+
 @item %i
 Substitute the name of the input file being processed.
 
 @item %b
-Substitute the basename of the input file being processed.
-This is the substring up to (and not including) the last period
-and not including the directory.
+Substitute the basename for outputs related with the input file being
+processed.  This is often the substring up to (and not including) the
+last period and not including the directory but, unless %w is active, it
+expands to the basename for auxiliary outputs, which may be influenced
+by an explicit output name, and by various other options that control
+how auxiliary outputs are named.
 
 @item %B
 This is the same as @samp{%b}, but include the file suffix (text after
-the last period).
+the last period).  Without %w, it expands to the basename for dump
+outputs.
 
 @item %d
 Marks the argument containing or following the @samp{%d} as a
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index fad5eb4..9deca03 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -24351,9 +24351,8 @@ gen_producer_string (void)
       case OPT_o:
       case OPT_d:
       case OPT_dumpbase:
+      case OPT_dumpbase_ext:
       case OPT_dumpdir:
-      case OPT_auxbase:
-      case OPT_auxbase_strip:
       case OPT_quiet:
       case OPT_version:
       case OPT_v:
diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
index 4cc8a90..d844fa9 100644
--- a/gcc/fortran/options.c
+++ b/gcc/fortran/options.c
@@ -838,8 +838,8 @@ gfc_get_option_string (void)
         case OPT_o:
         case OPT_d:
         case OPT_dumpbase:
+        case OPT_dumpbase_ext:
         case OPT_dumpdir:
-        case OPT_auxbase:
         case OPT_quiet:
         case OPT_version:
         case OPT_fintrinsic_modules_path:
@@ -864,8 +864,8 @@ gfc_get_option_string (void)
         case OPT_o:
         case OPT_d:
         case OPT_dumpbase:
+        case OPT_dumpbase_ext:
         case OPT_dumpdir:
-        case OPT_auxbase:
         case OPT_quiet:
         case OPT_version:
         case OPT_fintrinsic_modules_path:
diff --git a/gcc/gcc.c b/gcc/gcc.c
index b0d0308..8c851d7 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -270,12 +270,36 @@ static const char *target_sysroot_hdrs_suffix = 0;
 static enum save_temps {
   SAVE_TEMPS_NONE,		/* no -save-temps */
   SAVE_TEMPS_CWD,		/* -save-temps in current directory */
+  SAVE_TEMPS_DUMP,              /* -save-temps in dumpdir */
   SAVE_TEMPS_OBJ		/* -save-temps in object directory */
 } save_temps_flag;
 
-/* Output file to use to get the object directory for -save-temps=obj  */
-static char *save_temps_prefix = 0;
-static size_t save_temps_length = 0;
+/* Set this iff the dumppfx implied by a -save-temps=* option is to
+   override a -dumpdir option, if any.  */
+static bool save_temps_overrides_dumpdir = false;
+
+/* -dumpdir, -dumpbase and -dumpbase-ext flags passed in, possibly
+   rearranged as they are to be passed down, e.g., dumpbase and
+   dumpbase_ext may be cleared if integrated with dumpdir or
+   dropped.  */
+static char *dumpdir, *dumpbase, *dumpbase_ext;
+
+/* Usually the length of the string in dumpdir.  However, during
+   linking, it may be shortened to omit a driver-added trailing dash,
+   by then replaced with a trailing period, that is still to be passed
+   to sub-processes in -dumpdir, but not to be generally used in spec
+   filename expansions.  See maybe_run_linker.  */
+static size_t dumpdir_length = 0;
+
+/* Set if the last character in dumpdir is (or was) a dash that the
+   driver added to dumpdir after dumpbase or linker output name.  */
+static bool dumpdir_trailing_dash_added = false;
+
+/* Basename of dump and aux outputs, computed from dumpbase (given or
+   derived from output name), to override input_basename in non-%w %b
+   et al.  */
+static char *outbase;
+static size_t outbase_length = 0;
 
 /* The compiler version.  */
 
@@ -402,13 +426,16 @@ static const char *find_plugindir_spec_function (int, const char **);
 static const char *print_asm_header_spec_function (int, const char **);
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
-static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
 static const char *pass_through_libs_spec_func (int, const char **);
-static const char *replace_extension_spec_func (int, const char **);
+static const char *dumps_spec_func (int, const char **);
 static const char *greater_than_spec_func (int, const char **);
 static const char *debug_level_greater_than_spec_func (int, const char **);
 static const char *find_fortran_preinclude_file (int, const char **);
 static char *convert_white_space (char *);
+static char *quote_spec (char *);
+static char *quote_spec_arg (char *);
+static bool not_actual_file_p (const char *);
+
 
 /* The Specs Language
 
@@ -426,12 +453,19 @@ expanding these sequences; therefore, you can concatenate them together
 or with constant text in a single argument.
 
  %%	substitute one % into the program name or argument.
+ %"     substitute an empty argument.
  %i     substitute the name of the input file being processed.
- %b     substitute the basename of the input file being processed.
-	This is the substring up to (and not including) the last period
-	and not including the directory unless -save-temps was specified
-	to put temporaries in a different location.
- %B	same as %b, but include the file suffix (text after the last period).
+ %b     substitute the basename for outputs related with the input file
+	being processed.  This is often a substring of the input file name,
+	up to (and not including) the last period but, unless %w is active,
+	it is affected by the directory selected by -save-temps=*, by
+	-dumpdir, and, in case of multiple compilations, even by -dumpbase
+	and -dumpbase-ext and, in case of linking, by the linker output
+	name.  When %w is active, it derives the main output name only from
+	the input file base name; when it is not, it names aux/dump output
+	file.
+ %B	same as %b, but include the input file suffix (text after the last
+	period).
  %gSUFFIX
 	substitute a file name that has suffix SUFFIX and is chosen
 	once per compilation, and mark the argument a la %d.  To reduce
@@ -641,10 +675,10 @@ proper position among the other output files.  */
 #define ASM_FINAL_SPEC \
   "%{gsplit-dwarf: \n\
        objcopy --extract-dwo \
-	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
-	 %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
+	 %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
+	 %b.dwo \n\
        objcopy --strip-dwo \
-	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+	 %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
     }"
 #endif
 
@@ -1144,22 +1178,20 @@ static const char *cpp_options =
 
 /* This contains cpp options which are not passed when the preprocessor
    output will be used by another program.  */
-static const char *cpp_debug_options = "%{d*}";
+static const char *cpp_debug_options = "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps()";
 
 /* NB: This is shared amongst all front-ends, except for Ada.  */
 static const char *cc1_options =
 "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
  %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
- %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
- %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
- %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
+ %1 %{!Q:-quiet} %(cpp_debug_options) %{m*} %{aux-info*}\
  %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
  %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
  %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
  %{-target-help:--target-help}\
  %{-version:--version}\
  %{-help=*:--help=%*}\
- %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
+ %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}}\
  %{fsyntax-only:-o %j} %{-param*}\
  %{coverage:-fprofile-arcs -ftest-coverage}\
  %{fprofile-arcs|fprofile-generate*|coverage:\
@@ -1647,9 +1679,8 @@ static const struct spec_function static_spec_functions[] =
   { "print-asm-header",		print_asm_header_spec_function },
   { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
-  { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
   { "pass-through-libs",	pass_through_libs_spec_func },
-  { "replace-extension",	replace_extension_spec_func },
+  { "dumps",                    dumps_spec_func },
   { "gt",			greater_than_spec_func },
   { "debug-level-gt",		debug_level_greater_than_spec_func },
   { "fortran-preinclude-file",	find_fortran_preinclude_file},
@@ -4145,7 +4176,8 @@ driver_handle_option (struct gcc_options *opts,
       return true;
 
     case OPT_save_temps:
-      save_temps_flag = SAVE_TEMPS_CWD;
+      if (!save_temps_flag)
+	save_temps_flag = SAVE_TEMPS_DUMP;
       validated = true;
       break;
 
@@ -4158,6 +4190,23 @@ driver_handle_option (struct gcc_options *opts,
       else
 	fatal_error (input_location, "%qs is an unknown %<-save-temps%> option",
 		     decoded->orig_option_with_args_text);
+      save_temps_overrides_dumpdir = true;
+      break;
+
+    case OPT_dumpdir:
+      free (dumpdir);
+      dumpdir = xstrdup (arg);
+      save_temps_overrides_dumpdir = false;
+      break;
+
+    case OPT_dumpbase:
+      free (dumpbase);
+      dumpbase = xstrdup (arg);
+      break;
+
+    case OPT_dumpbase_ext:
+      free (dumpbase_ext);
+      dumpbase_ext = xstrdup (arg);
       break;
 
     case OPT_no_canonical_prefixes:
@@ -4264,8 +4313,6 @@ driver_handle_option (struct gcc_options *opts,
       arg = convert_filename (arg, ! have_c, 0);
 #endif
       output_file = arg;
-      /* Save the output name in case -save-temps=obj was used.  */
-      save_temps_prefix = xstrdup (arg);
       /* On some systems, ld cannot handle "-o" without a space.  So
 	 split the option from its argument.  */
       save_switch ("-o", 1, &arg, validated, true);
@@ -4308,6 +4355,19 @@ driver_handle_option (struct gcc_options *opts,
   return true;
 }
 
+/* Return true if F2 is F1 followed by a single suffix, i.e., by a
+   period and additional characters other than a period.  */
+
+static inline bool
+adds_single_suffix_p (const char *f2, const char *f1)
+{
+  size_t len = strlen (f1);
+
+  return (strncmp (f1, f2, len) == 0
+	  && f2[len] == '.'
+	  && strchr (f2 + len + 1, '.') == NULL);
+}
+
 /* Put the driver's standard set of option handlers in *HANDLERS.  */
 
 static void
@@ -4324,6 +4384,32 @@ set_option_handlers (struct cl_option_handlers *handlers)
   handlers->handlers[2].mask = CL_TARGET;
 }
 
+
+/* Return the index into infiles for the single non-library
+   non-lto-wpa input file, -1 if there isn't any, or -2 if there is
+   more than one.  */
+static inline int
+single_input_file_index ()
+{
+  int ret = -1;
+
+  for (int i = 0; i < n_infiles; i++)
+    {
+      if (infiles[i].language
+	  && (infiles[i].language[0] == '*'
+	      || (flag_wpa
+		  && strcmp (infiles[i].language, "lto") == 0)))
+	continue;
+
+      if (ret != -1)
+	return -2;
+
+      ret = i;
+    }
+
+  return ret;
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
@@ -4636,23 +4722,371 @@ process_command (unsigned int decoded_options_count,
   if (output_file != NULL && output_file[0] == '\0')
     fatal_error (input_location, "output filename may not be empty");
 
+  /* -dumpdir and -save-temps=* both specify the location of aux/dump
+     outputs; the one that appears last prevails.  When compiling
+     multiple sources, an explicit dumpbase (minus -ext) may be
+     combined with an explicit or implicit dumpdir, whereas when
+     linking, a specified or implied link output name (minus
+     extension) may be combined with a prevailing -save-temps=* or an
+     otherwise implied dumpdir, but not override a prevailing
+     -dumpdir.  Primary outputs (e.g., linker output when linking
+     without -o, or .i, .s or .o outputs when processing multiple
+     inputs with -E, -S or -c, respectively) are NOT affected by these
+     -save-temps=/-dump* options, always landing in the current
+     directory and with the same basename as the input when an output
+     name is not given, but when they're intermediate outputs, they
+     are named like other aux outputs, so the options affect their
+     location and name.
+
+     Here are some examples.  There are several more in the
+     documentation of -o and -dump*, and some quite exhaustive tests
+     in gcc.misc-tests/outputs.exp.
+
+     When compiling any number of sources, no -dump* nor
+     -save-temps=*, all outputs in cwd without prefix:
+
+     # gcc -c b.c -gsplit-dwarf
+     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
+
+     # gcc -c b.c d.c -gsplit-dwarf
+     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
+     && cc1 [-dumpdir ./] -dumpbase d.c -dumpbase-ext .c # d.o d.dwo
+
+     When compiling and linking, no -dump* nor -save-temps=*, .o
+     outputs are temporary, aux outputs land in the dir of the output,
+     prefixed with the basename of the linker output:
+
+     # gcc b.c d.c -o ab -gsplit-dwarf
+     -> cc1 -dumpdir ab- -dumpbase b.c -dumpbase-ext .c # ab-b.dwo
+     && cc1 -dumpdir ab- -dumpbase d.c -dumpbase-ext .c # ab-d.dwo
+     && link ... -o ab
+
+     # gcc b.c d.c [-o a.out] -gsplit-dwarf
+     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.dwo
+     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.dwo
+     && link ... [-o a.out]
+
+     When compiling and linking, a prevailing -dumpdir fully overrides
+     the prefix of aux outputs given by the output name:
+
+     # gcc -dumpdir f b.c d.c -gsplit-dwarf [-o [dir/]whatever]
+     -> cc1 -dumpdir f -dumpbase b.c -dumpbase-ext .c # fb.dwo
+     && cc1 -dumpdir f -dumpbase d.c -dumpbase-ext .c # fd.dwo
+     && link ... [-o whatever]
+
+     When compiling multiple inputs, an explicit -dumpbase is combined
+     with -dumpdir, affecting aux outputs, but not the .o outputs:
+
+     # gcc -dumpdir f -dumpbase g- b.c d.c -gsplit-dwarf -c
+     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # b.o fg-b.dwo
+     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # d.o fg-d.dwo
+
+     When compiling and linking with -save-temps, the .o outputs that
+     would have been temporary become aux outputs, so they get
+     affected by -dump* flags:
+
+     # gcc -dumpdir f -dumpbase g- -save-temps b.c d.c
+     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # fg-b.o
+     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # fg-d.o
+     && link
+
+     If -save-temps=* prevails over -dumpdir, however, the explicit
+     -dumpdir is discarded, as if it wasn't there.  The basename of
+     the implicit linker output, a.out or a.exe, becomes a- as the aux
+     output prefix for all compilations:
+
+     # gcc [-dumpdir f] -save-temps=cwd b.c d.c
+     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.o
+     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.o
+     && link
+
+     A single -dumpbase, applying to multiple inputs, overrides the
+     linker output name, implied or explicit, as the aux output prefix:
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
+     && link
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c -o dir/h.out
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
+     && link -o dir/h.out
+
+     Now, if the linker output is NOT overridden as a prefix, but
+     -save-temps=* overrides implicit or explicit -dumpdir, the
+     effective dump dir combines the dir selected by the -save-temps=*
+     option with the basename of the specified or implied link output:
+
+     # gcc [-dumpdir f] -save-temps=cwd b.c d.c -o dir/h.out
+     -> cc1 -dumpdir h- -dumpbase b.c -dumpbase-ext .c # h-b.o
+     && cc1 -dumpdir h- -dumpbase d.c -dumpbase-ext .c # h-d.o
+     && link -o dir/h.out
+
+     # gcc [-dumpdir f] -save-temps=obj b.c d.c -o dir/h.out
+     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
+     && cc1 -dumpdir dir/h- -dumpbase d.c -dumpbase-ext .c # dir/h-d.o
+     && link -o dir/h.out
+
+     But then again, a single -dumpbase applying to multiple inputs
+     gets used instead of the linker output basename in the combined
+     dumpdir:
+
+     # gcc [-dumpdir f] -dumpbase g- -save-temps=obj b.c d.c -o dir/h.out
+     -> cc1 -dumpdir dir/g- -dumpbase b.c -dumpbase-ext .c # dir/g-b.o
+     && cc1 -dumpdir dir/g- -dumpbase d.c -dumpbase-ext .c # dir/g-d.o
+     && link -o dir/h.out
+
+     With a single input being compiled, the output basename does NOT
+     affect the dumpdir prefix.
+
+     # gcc -save-temps=obj b.c -gsplit-dwarf -c -o dir/b.o
+     -> cc1 -dumpdir dir/ -dumpbase b.c -dumpbase-ext .c # dir/b.o dir/b.dwo
+
+     but when compiling and linking even a single file, it does:
+
+     # gcc -save-temps=obj b.c -o dir/h.out
+     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
+
+     unless an explicit -dumpdir prevails:
+
+     # gcc -save-temps[=obj] -dumpdir g- b.c -o dir/h.out
+     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+
+  */
+
+  bool explicit_dumpdir = dumpdir;
+
+  if (!save_temps_overrides_dumpdir && explicit_dumpdir)
+    {
+      /* Do nothing.  */
+    }
+
   /* If -save-temps=obj and -o name, create the prefix to use for %b.
      Otherwise just make -save-temps=obj the same as -save-temps=cwd.  */
-  if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL)
+  else if (save_temps_flag != SAVE_TEMPS_CWD && output_file != NULL)
+    {
+      free (dumpdir);
+      dumpdir = NULL;
+      temp = lbasename (output_file);
+      if (temp != output_file)
+	dumpdir = xstrndup (output_file,
+			    strlen (output_file) - strlen (temp));
+    }
+  else if (dumpdir)
+    {
+      free (dumpdir);
+      dumpdir = NULL;
+    }
+
+  if (save_temps_flag)
+    save_temps_flag = SAVE_TEMPS_DUMP;
+
+  /* If there is any pathname component in an explicit -dumpbase, it
+     overrides dumpdir entirely, so discard it right away.  Although
+     the presence of an explicit -dumpdir matters for the driver, it
+     shouldn't matter for other processes, that get all that's needed
+     from the -dumpdir and -dumpbase always passed to them.  */
+  if (dumpdir && dumpbase && lbasename (dumpbase) != dumpbase)
     {
-      save_temps_length = strlen (save_temps_prefix);
-      temp = strrchr (lbasename (save_temps_prefix), '.');
-      if (temp)
+      free (dumpdir);
+      dumpdir = NULL;
+    }
+
+  /* Check that dumpbase_ext matches the end of dumpbase, drop it
+     otherwise.  */
+  if (dumpbase_ext && dumpbase && *dumpbase)
+    {
+      int lendb = strlen (dumpbase);
+      int lendbx = strlen (dumpbase_ext);
+
+      if (lendbx >= lendb
+	  || strcmp (dumpbase + lendb - lendbx, dumpbase_ext) != 0)
 	{
-	  save_temps_length -= strlen (temp);
-	  save_temps_prefix[save_temps_length] = '\0';
+	  free (dumpbase_ext);
+	  dumpbase_ext = NULL;
 	}
+    }
+
+  /* -dumpbase with multiple sources goes into dumpdir.  With a single
+     source, it does only if linking and if dumpdir was not explicitly
+     specified.  */
+  if (dumpbase && *dumpbase
+      && (single_input_file_index () == -2
+	  || (!have_c && !explicit_dumpdir)))
+    {
+      char *prefix;
 
+      if (dumpbase_ext)
+	/* We checked that they match above.  */
+	dumpbase[strlen (dumpbase) - strlen (dumpbase_ext)] = '\0';
+
+      if (dumpdir)
+	prefix = concat (dumpdir, dumpbase, "-", NULL);
+      else
+	prefix = concat (dumpbase, "-", NULL);
+
+      free (dumpdir);
+      free (dumpbase);
+      free (dumpbase_ext);
+      dumpbase = dumpbase_ext = NULL;
+      dumpdir = prefix;
+      dumpdir_trailing_dash_added = true;
+    }
+
+  /* If dumpbase was not brought into dumpdir but we're linking, bring
+     output_file into dumpdir unless dumpdir was explicitly specified.
+     The test for !explicit_dumpdir is further below, because we want
+     to use the obase computation for a ghost outbase, passed to
+     GCC_COLLECT_OPTIONS.  */
+  else if (!have_c && (!explicit_dumpdir || (dumpbase && !*dumpbase)))
+    {
+      /* If we get here, we know dumpbase was not specified, or it was
+	 specified as an empty string.  If it was anything else, it
+	 would have combined with dumpdir above, because the condition
+	 for dumpbase to be used when present is broader than the
+	 condition that gets us here.  */
+      gcc_assert (!dumpbase || !*dumpbase);
+
+      const char *obase;
+      char *tofree = NULL;
+      if (!output_file || not_actual_file_p (output_file))
+	obase = "a";
+      else
+	{
+	  obase = lbasename (output_file);
+	  size_t blen = strlen (obase), xlen;
+	  /* Drop the suffix if it's dumpbase_ext, if given,
+	     otherwise .exe or the target executable suffix, or if the
+	     output was explicitly named a.out, but not otherwise.  */
+	  if (dumpbase_ext
+	      ? (blen > (xlen = strlen (dumpbase_ext))
+		 && strcmp ((temp = (obase + blen - xlen)),
+			    dumpbase_ext) == 0)
+	      : ((temp = strrchr (obase + 1, '.'))
+		 && (xlen = strlen (temp))
+		 && (strcmp (temp, ".exe") == 0
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
+		     || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
+#endif
+		     || strcmp (obase, "a.out") == 0)))
+	    {
+	      tofree = xstrndup (obase, blen - xlen);
+	      obase = tofree;
+	    }
+	}
+
+      /* We wish to save this basename to the -dumpdir passed through
+	 GCC_COLLECT_OPTIONS within maybe_run_linker, for e.g. LTO,
+	 but we do NOT wish to add it to e.g. %b, so we keep
+	 outbase_length as zero.  */
+      gcc_assert (!outbase);
+      outbase_length = 0;
+
+      /* If we're building [dir1/]foo[.exe] out of a single input
+	 [dir2/]foo.c that shares the same basename, dump to
+	 [dir2/]foo.c.* rather than duplicating the basename into
+	 [dir2/]foo-foo.c.*.  */
+      int idxin;
+      if (dumpbase
+	  || ((idxin = single_input_file_index ()) >= 0
+	      && adds_single_suffix_p (lbasename (infiles[idxin].name),
+				       obase)))
+	{
+	  if (obase == tofree)
+	    outbase = tofree;
+	  else
+	    {
+	      outbase = xstrdup (obase);
+	      free (tofree);
+	    }
+	  obase = tofree = NULL;
+	}
+      else
+	{
+	  if (dumpdir)
+	    {
+	      char *p = concat (dumpdir, obase, "-", NULL);
+	      free (dumpdir);
+	      dumpdir = p;
+	    }
+	  else
+	    dumpdir = concat (obase, "-", NULL);
+
+	  dumpdir_trailing_dash_added = true;
+
+	  free (tofree);
+	  obase = tofree = NULL;
+	}
+
+      if (!explicit_dumpdir || dumpbase)
+	{
+	  /* Absent -dumpbase and present -dumpbase-ext have been applied
+	     to the linker output name, so compute fresh defaults for each
+	     compilation.  */
+	  free (dumpbase_ext);
+	  dumpbase_ext = NULL;
+	}
+    }
+
+  /* Now, if we're compiling, or if we haven't used the dumpbase
+     above, then outbase (%B) is derived from dumpbase, if given, or
+     from the output name, given or implied.  We can't precompute
+     implied output names, but that's ok, since they're derived from
+     input names.  Just make sure we skip this if dumpbase is the
+     empty string: we want to use input names then, so don't set
+     outbase.  */
+  if ((dumpbase || have_c)
+      && !(dumpbase && !*dumpbase))
+    {
+      gcc_assert (!outbase);
+
+      if (dumpbase)
+	{
+	  gcc_assert (single_input_file_index () != -2);
+	  /* We do not want lbasename here; dumpbase with dirnames
+	     overrides dumpdir entirely, even if dumpdir is
+	     specified.  */
+	  if (dumpbase_ext)
+	    /* We've already checked above that the suffix matches.  */
+	    outbase = xstrndup (dumpbase,
+				strlen (dumpbase) - strlen (dumpbase_ext));
+	  else
+	    outbase = xstrdup (dumpbase);
+	}
+      else if (output_file && !not_actual_file_p (output_file))
+	{
+	  outbase = xstrdup (lbasename (output_file));
+	  char *p = strrchr (outbase + 1, '.');
+	  if (p)
+	    *p = '\0';
+	}
+
+      if (outbase)
+	outbase_length = strlen (outbase);
     }
-  else if (save_temps_prefix != NULL)
+
+  /* If there is any pathname component in an explicit -dumpbase, do
+     not use dumpdir, but retain it to pass it on to the compiler.  */
+  if (dumpdir)
+    dumpdir_length = strlen (dumpdir);
+  else
+    dumpdir_length = 0;
+
+  /* Check that dumpbase_ext, if still present, still matches the end
+     of dumpbase, if present, and drop it otherwise.  We only retained
+     it above when dumpbase was absent to maybe use it to drop the
+     extension from output_name before combining it with dumpdir.  */
+  if (dumpbase_ext)
     {
-      free (save_temps_prefix);
-      save_temps_prefix = NULL;
+      if (!dumpbase)
+	{
+	  free (dumpbase_ext);
+	  dumpbase_ext = NULL;
+	}
+      else
+	gcc_assert (strcmp (dumpbase + strlen (dumpbase)
+			    - strlen (dumpbase_ext), dumpbase_ext) == 0);
     }
 
   if (save_temps_flag && use_pipes)
@@ -4848,6 +5282,28 @@ set_collect_gcc_options (void)
 	  obstack_grow (&collect_obstack, "'", 1);
 	}
     }
+
+  if (dumpdir)
+    {
+      if (!first_time)
+	obstack_grow (&collect_obstack, " ", 1);
+      first_time = FALSE;
+
+      obstack_grow (&collect_obstack, "'-dumpdir' '", 12);
+      const char *p, *q;
+
+      q = dumpdir;
+      while ((p = strchr (q, '\'')))
+	{
+	  obstack_grow (&collect_obstack, q, p - q);
+	  obstack_grow (&collect_obstack, "'\\''", 4);
+	  q = ++p;
+	}
+      obstack_grow (&collect_obstack, q, strlen (q));
+
+      obstack_grow (&collect_obstack, "'", 1);
+    }
+
   obstack_grow (&collect_obstack, "\0", 1);
   xputenv (XOBFINISH (&collect_obstack, char *));
 }
@@ -5366,22 +5822,33 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 	    fatal_error (input_location, "spec %qs invalid", spec);
 
 	  case 'b':
-	    if (save_temps_length)
-	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
-	    else
+	    /* Don't use %b in the linker command.  */
+	    gcc_assert (suffixed_basename_length);
+	    if (!this_is_output_file && dumpdir_length)
+	      obstack_grow (&obstack, dumpdir, dumpdir_length);
+	    if (this_is_output_file || !outbase_length)
 	      obstack_grow (&obstack, input_basename, basename_length);
+	    else
+	      obstack_grow (&obstack, outbase, outbase_length);
 	    if (compare_debug < 0)
 	      obstack_grow (&obstack, ".gk", 3);
 	    arg_going = 1;
 	    break;
 
 	  case 'B':
-	    if (save_temps_length)
-	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
+	    /* Don't use %B in the linker command.  */
+	    gcc_assert (suffixed_basename_length);
+	    if (!this_is_output_file && dumpdir_length)
+	      obstack_grow (&obstack, dumpdir, dumpdir_length);
+	    if (this_is_output_file || !outbase_length)
+	      obstack_grow (&obstack, input_basename, basename_length);
 	    else
-	      obstack_grow (&obstack, input_basename, suffixed_basename_length);
+	      obstack_grow (&obstack, outbase, outbase_length);
 	    if (compare_debug < 0)
 	      obstack_grow (&obstack, ".gk", 3);
+	    obstack_grow (&obstack, input_basename + basename_length,
+			  suffixed_basename_length - basename_length);
+
 	    arg_going = 1;
 	    break;
 
@@ -5534,42 +6001,44 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 		    suffix_length += 3;
 		  }
 
-		/* If -save-temps=obj and -o were specified, use that for the
+		/* If -save-temps was specified, use that for the
 		   temp file.  */
-		if (save_temps_length)
-		  {
-		    char *tmp;
-		    temp_filename_length
-		      = save_temps_length + suffix_length + 1;
-		    tmp = (char *) alloca (temp_filename_length);
-		    memcpy (tmp, save_temps_prefix, save_temps_length);
-		    memcpy (tmp + save_temps_length, suffix, suffix_length);
-		    tmp[save_temps_length + suffix_length] = '\0';
-		    temp_filename = save_string (tmp, save_temps_length
-						      + suffix_length);
-		    obstack_grow (&obstack, temp_filename,
-				  temp_filename_length);
-		    arg_going = 1;
-		    delete_this_arg = 0;
-		    break;
-		  }
-
-		/* If the gcc_input_filename has the same suffix specified
-		   for the %g, %u, or %U, and -save-temps is specified,
-		   we could end up using that file as an intermediate
-		   thus clobbering the user's source file (.e.g.,
-		   gcc -save-temps foo.s would clobber foo.s with the
-		   output of cpp0).  So check for this condition and
-		   generate a temp file as the intermediate.  */
-
 		if (save_temps_flag)
 		  {
 		    char *tmp;
-		    temp_filename_length = basename_length + suffix_length + 1;
+		    bool adjusted_suffix = false;
+		    if (suffix_length
+			&& !outbase_length && !basename_length
+			&& !dumpdir_trailing_dash_added)
+		      {
+			adjusted_suffix = true;
+			suffix++;
+			suffix_length--;
+		      }
+		    temp_filename_length
+		      = dumpdir_length + suffix_length + 1;
+		    if (!outbase_length)
+		      temp_filename_length += basename_length;
+		    else
+		      temp_filename_length += outbase_length;
 		    tmp = (char *) alloca (temp_filename_length);
-		    memcpy (tmp, input_basename, basename_length);
-		    memcpy (tmp + basename_length, suffix, suffix_length);
-		    tmp[basename_length + suffix_length] = '\0';
+		    if (dumpdir_length)
+		      memcpy (tmp, dumpdir, dumpdir_length);
+		    if (!outbase_length)
+		      memcpy (tmp + dumpdir_length, input_basename,
+			      basename_length);
+		    else
+		      memcpy (tmp + dumpdir_length, outbase,
+			      outbase_length);
+		    memcpy (tmp + temp_filename_length - suffix_length - 1,
+			    suffix, suffix_length);
+		    if (adjusted_suffix)
+		      {
+			adjusted_suffix = false;
+			suffix--;
+			suffix_length++;
+		      }
+		    tmp[temp_filename_length - 1] = '\0';
 		    temp_filename = tmp;
 
 		    if (filename_cmp (temp_filename, gcc_input_filename) != 0)
@@ -6080,6 +6549,14 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 	    }
 	    break;
 
+	  case '"':
+	    /* End a previous argument, if there is one, then issue an
+	       empty argument.  */
+	    end_going_arg ();
+	    arg_going = 1;
+	    end_going_arg ();
+	    break;
+
 	  default:
 	    error ("spec failure: unrecognized spec option %qc", c);
 	    break;
@@ -6090,6 +6567,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 	/* Backslash: treat next character as ordinary.  */
 	c = *p++;
 
+	/* When adding more cases that previously matched default, make
+	   sure to adjust quote_spec_char_p as well.  */
+
 	/* Fall through.  */
       default:
 	/* Ordinary character: put it into the current argument.  */
@@ -8296,6 +8776,40 @@ driver::maybe_run_linker (const char *argv0) const
     if (explicit_link_files[i] || outfiles[i] != NULL)
       num_linker_inputs++;
 
+  /* Arrange for temporary file names created during linking to take
+     on names related with the linker output rather than with the
+     inputs when appropriate.  */
+  if (outbase && *outbase)
+    {
+      if (dumpdir)
+	{
+	  char *tofree = dumpdir;
+	  gcc_checking_assert (strlen (dumpdir) == dumpdir_length);
+	  dumpdir = concat (dumpdir, outbase, ".", NULL);
+	  free (tofree);
+	}
+      else
+	dumpdir = concat (outbase, ".", NULL);
+      dumpdir_length += strlen (outbase) + 1;
+      dumpdir_trailing_dash_added = true;
+    }
+  else if (dumpdir_trailing_dash_added)
+    {
+      gcc_assert (dumpdir[dumpdir_length - 1] == '-');
+      dumpdir[dumpdir_length - 1] = '.';
+    }
+
+  if (dumpdir_trailing_dash_added)
+    {
+      gcc_assert (dumpdir_length > 0);
+      gcc_assert (dumpdir[dumpdir_length - 1] == '.');
+      dumpdir_length--;
+    }
+
+  free (outbase);
+  input_basename = outbase = NULL;
+  outbase_length = suffixed_basename_length = basename_length = 0;
+
   /* Run ld to link all the compiler output files.  */
 
   if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
@@ -9766,7 +10280,7 @@ compare_debug_dump_opt_spec_function (int arg,
   do_spec_1 (" ", 0, NULL);
 
   if (argbuf.length () > 0
-      && strcmp (argv[argbuf.length () - 1], "."))
+      && strcmp (argv[argbuf.length () - 1], ".") != 0)
     {
       if (!compare_debug)
 	return NULL;
@@ -9776,25 +10290,22 @@ compare_debug_dump_opt_spec_function (int arg,
     }
   else
     {
-      const char *ext = NULL;
-
       if (argbuf.length () > 0)
-	{
-	  do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}", NULL);
-	  ext = ".gkd";
-	}
+	do_spec_2 ("%B.gkd", NULL);
       else if (!compare_debug)
 	return NULL;
       else
-	do_spec_2 ("%g.gkd", NULL);
+	do_spec_2 ("%{!save-temps*:%g.gkd}%{save-temps*:%B.gkd}", NULL);
 
       do_spec_1 (" ", 0, NULL);
 
       gcc_assert (argbuf.length () > 0);
 
-      name = concat (argbuf.last (), ext, NULL);
+      name = xstrdup (argbuf.last ());
 
-      ret = concat ("-fdump-final-insns=", name, NULL);
+      char *arg = quote_spec (xstrdup (name));
+      ret = concat ("-fdump-final-insns=", arg, NULL);
+      free (arg);
     }
 
   which = compare_debug < 0;
@@ -9821,8 +10332,6 @@ compare_debug_dump_opt_spec_function (int arg,
   return ret;
 }
 
-static const char *debug_auxbase_opt;
-
 /* %:compare-debug-self-opt spec function.  Expands to the options
     that are to be passed in the second compilation of
     compare-debug.  */
@@ -9838,16 +10347,6 @@ compare_debug_self_opt_spec_function (int arg,
   if (compare_debug >= 0)
     return NULL;
 
-  do_spec_2 ("%{c|S:%{o*:%*}}", NULL);
-  do_spec_1 (" ", 0, NULL);
-
-  if (argbuf.length () > 0)
-    debug_auxbase_opt = concat ("-auxbase-strip ",
-				argbuf.last (),
-				NULL);
-  else
-    debug_auxbase_opt = NULL;
-
   return concat ("\
 %<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
 %<fdump-final-insns=* -w -S -o %j \
@@ -9855,50 +10354,6 @@ compare_debug_self_opt_spec_function (int arg,
 ", compare_debug_opt, NULL);
 }
 
-/* %:compare-debug-auxbase-opt spec function.  Expands to the auxbase
-    options that are to be passed in the second compilation of
-    compare-debug.  It expects, as an argument, the basename of the
-    current input file name, with the .gk suffix appended to it.  */
-
-static const char *
-compare_debug_auxbase_opt_spec_function (int arg,
-					 const char **argv)
-{
-  char *name;
-  int len;
-
-  if (arg == 0)
-    fatal_error (input_location,
-		 "too few arguments to %%:compare-debug-auxbase-opt");
-
-  if (arg != 1)
-    fatal_error (input_location,
-		 "too many arguments to %%:compare-debug-auxbase-opt");
-
-  if (compare_debug >= 0)
-    return NULL;
-
-  len = strlen (argv[0]);
-  if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
-    fatal_error (input_location, "argument to %%:compare-debug-auxbase-opt "
-		 "does not end in %<.gk%>");
-
-  if (debug_auxbase_opt)
-    return debug_auxbase_opt;
-
-#define OPT "-auxbase "
-
-  len -= 3;
-  name = (char*) xmalloc (sizeof (OPT) + len);
-  memcpy (name, OPT, sizeof (OPT) - 1);
-  memcpy (name + sizeof (OPT) - 1, argv[0], len);
-  name[sizeof (OPT) - 1 + len] = '\0';
-
-#undef OPT
-
-  return name;
-}
-
 /* %:pass-through-libs spec function.  Finds all -l options and input
    file names in the lib spec passed to it, and makes a list of them
    prepended with the plugin option to cause them to be passed through
@@ -9942,34 +10397,105 @@ pass_through_libs_spec_func (int argc, const char **argv)
   return prepended;
 }
 
-/* %:replace-extension spec function.  Replaces the extension of the
-   first argument with the second argument.  */
+static bool
+not_actual_file_p (const char *name)
+{
+  return (strcmp (name, "-") == 0
+	  || strcmp (output_file, HOST_BIT_BUCKET) == 0);
+}
 
+/* %:dumps spec function.  Take an optional argument that overrides
+   the default extension for -dumpbase and -dumpbase-ext.
+   Return -dumpdir, -dumpbase and -dumpbase-ext, if needed.  */
 const char *
-replace_extension_spec_func (int argc, const char **argv)
+dumps_spec_func (int argc, const char **argv ATTRIBUTE_UNUSED)
 {
-  char *name;
+  const char *ext = dumpbase_ext;
   char *p;
-  char *result;
-  int i;
 
-  if (argc != 2)
-    fatal_error (input_location, "too few arguments to %%:replace-extension");
+  char *args[3] = { NULL, NULL, NULL };
+  int nargs = 0;
 
-  name = xstrdup (argv[0]);
+  /* Do not compute a default for -dumpbase-ext when -dumpbase was
+     given explicitly.  */
+  if (dumpbase && *dumpbase && !ext)
+    ext = "";
 
-  for (i = strlen (name) - 1; i >= 0; i--)
-    if (IS_DIR_SEPARATOR (name[i]))
-      break;
+  if (argc == 1)
+    {
+      /* Do not override the explicitly-specified -dumpbase-ext with
+	 the specs-provided overrider.  */
+      if (!ext)
+	ext = argv[0];
+    }
+  else if (argc != 0)
+    fatal_error (input_location, "too many arguments for %%:dumps");
 
-  p = strrchr (name + i + 1, '.');
-  if (p != NULL)
-      *p = '\0';
+  if (dumpdir)
+    {
+      p = quote_spec_arg (xstrdup (dumpdir));
+      args[nargs++] = concat (" -dumpdir ", p, NULL);
+      free (p);
+    }
 
-  result = concat (name, argv[1], NULL);
+  if (!ext)
+    ext = input_basename + basename_length;
 
-  free (name);
-  return result;
+  /* Use the precomputed outbase, or compute dumpbase from
+     input_basename, just like %b would.  */
+  char *base;
+
+  if (dumpbase && *dumpbase)
+    {
+      base = xstrdup (dumpbase);
+      p = base + outbase_length;
+      gcc_checking_assert (strncmp (base, outbase, outbase_length) == 0);
+      gcc_checking_assert (strcmp (p, ext) == 0);
+    }
+  else if (outbase_length)
+    {
+      base = xstrndup (outbase, outbase_length);
+      p = NULL;
+    }
+  else
+    {
+      base = xstrndup (input_basename, suffixed_basename_length);
+      p = base + basename_length;
+    }
+
+  if (compare_debug < 0 || !p || strcmp (p, ext) != 0)
+    {
+      if (p)
+	*p = '\0';
+
+      const char *gk;
+      if (compare_debug < 0)
+	gk = ".gk";
+      else
+	gk = "";
+
+      p = concat (base, gk, ext, NULL);
+
+      free (base);
+      base = p;
+    }
+
+  base = quote_spec_arg (base);
+  args[nargs++] = concat (" -dumpbase ", base, NULL);
+  free (base);
+
+  if (*ext)
+    {
+      p = quote_spec_arg (xstrdup (ext));
+      args[nargs++] = concat (" -dumpbase-ext ", p, NULL);
+      free (p);
+    }
+
+  const char *ret = concat (args[0], args[1], args[2], NULL);
+  while (nargs > 0)
+    free (args[--nargs]);
+
+  return ret;
 }
 
 /* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
@@ -10075,6 +10601,44 @@ find_fortran_preinclude_file (int argc, const char **argv)
   return result;
 }
 
+/* If any character in ORIG fits QUOTE_P (_, P), reallocate the string
+   so as to precede every one of them with a backslash.  Return the
+   original string or the reallocated one.  */
+
+static inline char *
+quote_string (char *orig, bool (*quote_p)(char, void *), void *p)
+{
+  int len, number_of_space = 0;
+
+  for (len = 0; orig[len]; len++)
+    if (quote_p (orig[len], p))
+      number_of_space++;
+
+  if (number_of_space)
+    {
+      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
+      int j, k;
+      for (j = 0, k = 0; j <= len; j++, k++)
+	{
+	  if (quote_p (orig[j], p))
+	    new_spec[k++] = '\\';
+	  new_spec[k] = orig[j];
+	}
+      free (orig);
+      return new_spec;
+    }
+  else
+    return orig;
+}
+
+/* Return true iff C is any of the characters convert_white_space
+   should quote.  */
+
+static inline bool
+whitespace_to_convert_p (char c, void *)
+{
+  return (c == ' ' || c == '\t');
+}
 
 /* Insert backslash before spaces in ORIG (usually a file path), to 
    avoid being broken by spec parser.
@@ -10102,26 +10666,50 @@ find_fortran_preinclude_file (int argc, const char **argv)
 static char *
 convert_white_space (char *orig)
 {
-  int len, number_of_space = 0;
+  return quote_string (orig, whitespace_to_convert_p, NULL);
+}
 
-  for (len = 0; orig[len]; len++)
-    if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
+/* Return true iff C matches any of the spec active characters.  */
+static inline bool
+quote_spec_char_p (char c, void *)
+{
+  switch (c)
+    {
+    case ' ':
+    case '\t':
+    case '\n':
+    case '|':
+    case '%':
+    case '\\':
+      return true;
 
-  if (number_of_space)
+    default:
+      return false;
+    }
+}
+
+/* Like convert_white_space, but deactivate all active spec chars by
+   quoting them.  */
+
+static inline char *
+quote_spec (char *orig)
+{
+  return quote_string (orig, quote_spec_char_p, NULL);
+}
+
+/* Like quote_spec, but also turn an empty string into the spec for an
+   empty argument.  */
+
+static inline char *
+quote_spec_arg (char *orig)
+{
+  if (!*orig)
     {
-      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
-      int j, k;
-      for (j = 0, k = 0; j <= len; j++, k++)
-	{
-	  if (orig[j] == ' ' || orig[j] == '\t')
-	    new_spec[k++] = '\\';
-	  new_spec[k] = orig[j];
-	}
       free (orig);
-      return new_spec;
-  }
-  else
-    return orig;
+      return xstrdup ("%\"");
+    }
+
+  return quote_spec (orig);
 }
 
 /* Restore all state within gcc.c to the initial state, so that the driver
@@ -10158,8 +10746,14 @@ driver::finalize ()
   target_sysroot_suffix = 0;
   target_sysroot_hdrs_suffix = 0;
   save_temps_flag = SAVE_TEMPS_NONE;
-  save_temps_prefix = 0;
-  save_temps_length = 0;
+  save_temps_overrides_dumpdir = false;
+  dumpdir_trailing_dash_added = false;
+  free (dumpdir);
+  free (dumpbase);
+  free (dumpbase_ext);
+  free (outbase);
+  dumpdir = dumpbase = dumpbase_ext = outbase = NULL;
+  dumpdir_length = outbase_length = 0;
   spec_machine = DEFAULT_TARGET_MACHINE;
   greatest_status = 1;
 
@@ -10298,8 +10892,6 @@ driver::finalize ()
   mdswitches = NULL;
   n_mdswitches = 0;
 
-  debug_auxbase_opt = NULL;
-
   used_arg.finalize ();
 }
 
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index e34b697..d565b08 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -53,6 +53,13 @@ along with GCC; see the file COPYING3.  If not see
    driver to lto-wrapper.  */
 #define OFFLOAD_TARGET_NAMES_ENV	"OFFLOAD_TARGET_NAMES"
 
+/* By default there is no special suffix for target executables.  */
+#ifdef TARGET_EXECUTABLE_SUFFIX
+#define HAVE_TARGET_EXECUTABLE_SUFFIX
+#else
+#define TARGET_EXECUTABLE_SUFFIX ""
+#endif
+
 enum lto_mode_d {
   LTO_MODE_NONE,			/* Not doing LTO.  */
   LTO_MODE_LTO,				/* Normal LTO.  */
@@ -126,7 +133,7 @@ maybe_unlink (const char *file)
 }
 
 /* Template of LTRANS dumpbase suffix.  */
-#define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
+#define DUMPBASE_SUFFIX "ltrans18446744073709551615"
 
 /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
    environment.  */
@@ -1100,12 +1107,7 @@ debug_objcopy (const char *infile, bool rename)
     }
 
   if (save_temps)
-    {
-      outfile = (char *) xmalloc (strlen (orig_infile)
-				  + sizeof (".debug.temp.o") + 1);
-      strcpy (outfile, orig_infile);
-      strcat (outfile, ".debug.temp.o");
-    }
+    outfile = concat (orig_infile, ".debug.temp.o", NULL);
   else
     outfile = make_temp_file (".debug.temp.o");
   errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err, rename);
@@ -1296,6 +1298,8 @@ run_gcc (unsigned argc, char *argv[])
   bool linker_output_rel = false;
   bool skip_debug = false;
   unsigned n_debugobj;
+  const char *dumppfx = NULL, *incoming_dumppfx = NULL;
+  static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
 
   /* Get the driver and options.  */
   collect_gcc = getenv ("COLLECT_GCC");
@@ -1407,6 +1411,10 @@ run_gcc (unsigned argc, char *argv[])
 	  linker_output = option->arg;
 	  break;
 
+	  /* We don't have to distinguish between -save-temps=* and
+	     -save-temps, -dumpdir already carries that
+	     information.  */
+	case OPT_save_temps_:
 	case OPT_save_temps:
 	  save_temps = 1;
 	  break;
@@ -1452,6 +1460,10 @@ run_gcc (unsigned argc, char *argv[])
 	  skip_debug = option->arg && !strcmp (option->arg, "0");
 	  break;
 
+	case OPT_dumpdir:
+	  incoming_dumppfx = dumppfx = option->arg;
+	  break;
+
 	default:
 	  break;
 	}
@@ -1490,32 +1502,47 @@ run_gcc (unsigned argc, char *argv[])
 	}
     }
 
-  if (linker_output)
+  if (!dumppfx)
     {
-      char *output_dir, *base, *name;
-      bool bit_bucket = strcmp (linker_output, HOST_BIT_BUCKET) == 0;
-
-      output_dir = xstrdup (linker_output);
-      base = output_dir;
-      for (name = base; *name; name++)
-	if (IS_DIR_SEPARATOR (*name))
-	  base = name + 1;
-      *base = '\0';
-
-      linker_output = &linker_output[base - output_dir];
-      if (*output_dir == '\0')
-	{
-	  static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
-	  output_dir = current_dir;
-	}
-      if (!bit_bucket)
+      if (!linker_output
+	  || strcmp (linker_output, HOST_BIT_BUCKET) == 0)
+	dumppfx = "a.";
+      else
 	{
-	  obstack_ptr_grow (&argv_obstack, "-dumpdir");
-	  obstack_ptr_grow (&argv_obstack, output_dir);
+	  const char *obase = lbasename (linker_output), *temp;
+
+	  /* Strip the executable extension.  */
+	  size_t blen = strlen (obase), xlen;
+	  if ((temp = strrchr (obase + 1, '.'))
+	      && (xlen = strlen (temp))
+	      && (strcmp (temp, ".exe") == 0
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
+		  || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
+#endif
+		  || strcmp (obase, "a.out") == 0))
+	    dumppfx = xstrndup (linker_output,
+				obase - linker_output + blen - xlen + 1);
+	  else
+	    dumppfx = concat (linker_output, ".", NULL);
 	}
+    }
 
-      obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  /* If there's no directory component in the dumppfx, add one, so
+     that, when it is used as -dumpbase, it overrides any occurrence
+     of -dumpdir that might have been passed in.  */
+  if (!dumppfx || lbasename (dumppfx) == dumppfx)
+    dumppfx = concat (current_dir, dumppfx, NULL);
+
+  /* Make sure some -dumpdir is passed, so as to get predictable
+     -dumpbase overriding semantics.  If we got an incoming -dumpdir
+     argument, we'll pass it on, so don't bother with another one
+     then.  */
+  if (!incoming_dumppfx)
+    {
+      obstack_ptr_grow (&argv_obstack, "-dumpdir");
+      obstack_ptr_grow (&argv_obstack, "");
     }
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
 
   /* Remember at which point we can scrub args to re-use the commons.  */
   new_head_argc = obstack_object_size (&argv_obstack) / sizeof (void *);
@@ -1621,15 +1648,11 @@ cont1:
 
   if (lto_mode == LTO_MODE_LTO)
     {
-      if (linker_output)
-	{
-	  obstack_ptr_grow (&argv_obstack, linker_output);
-	  flto_out = (char *) xmalloc (strlen (linker_output)
-				       + sizeof (".lto.o") + 1);
-	  strcpy (flto_out, linker_output);
-	  strcat (flto_out, ".lto.o");
-	}
-      else
+      /* -dumpbase argument for LTO.  */
+      flto_out = concat (dumppfx, "lto.o", NULL);
+      obstack_ptr_grow (&argv_obstack, flto_out);
+
+      if (!save_temps)
 	flto_out = make_temp_file (".lto.o");
       obstack_ptr_grow (&argv_obstack, "-o");
       obstack_ptr_grow (&argv_obstack, flto_out);
@@ -1637,47 +1660,17 @@ cont1:
   else 
     {
       const char *list_option = "-fltrans-output-list=";
-      size_t list_option_len = strlen (list_option);
-      char *tmp;
 
-      if (linker_output)
-	{
-	  char *dumpbase = (char *) xmalloc (strlen (linker_output)
-					     + sizeof (".wpa") + 1);
-	  strcpy (dumpbase, linker_output);
-	  strcat (dumpbase, ".wpa");
-	  obstack_ptr_grow (&argv_obstack, dumpbase);
-	}
+      /* -dumpbase argument for WPA.  */
+      char *dumpbase = concat (dumppfx, "wpa", NULL);
+      obstack_ptr_grow (&argv_obstack, dumpbase);
 
-      if (linker_output && save_temps)
-	{
-	  ltrans_output_file = (char *) xmalloc (strlen (linker_output)
-						 + sizeof (".ltrans.out") + 1);
-	  strcpy (ltrans_output_file, linker_output);
-	  strcat (ltrans_output_file, ".ltrans.out");
-	}
+      if (save_temps)
+	ltrans_output_file = concat (dumppfx, "ltrans.out", NULL);
       else
-	{
-	  char *prefix = NULL;
-	  if (linker_output)
-	    {
-	      prefix = (char *) xmalloc (strlen (linker_output) + 2);
-	      strcpy (prefix, linker_output);
-	      strcat (prefix, ".");
-	    }
-
-	  ltrans_output_file = make_temp_file_with_prefix (prefix,
-							   ".ltrans.out");
-	  free (prefix);
-	}
-      list_option_full = (char *) xmalloc (sizeof (char) *
-		         (strlen (ltrans_output_file) + list_option_len + 1));
-      tmp = list_option_full;
-
-      obstack_ptr_grow (&argv_obstack, tmp);
-      strcpy (tmp, list_option);
-      tmp += list_option_len;
-      strcpy (tmp, ltrans_output_file);
+	ltrans_output_file = make_temp_file (".ltrans.out");
+      list_option_full = concat (list_option, ltrans_output_file, NULL);
+      obstack_ptr_grow (&argv_obstack, list_option_full);
 
       if (jobserver)
 	{
@@ -1833,16 +1826,10 @@ cont:
 	  output_name = XOBFINISH (&env_obstack, char *);
 
 	  /* Adjust the dumpbase if the linker output file was seen.  */
-	  if (linker_output)
-	    {
-	      char *dumpbase
-		  = (char *) xmalloc (strlen (linker_output)
-				      + sizeof (DUMPBASE_SUFFIX) + 1);
-	      snprintf (dumpbase,
-			strlen (linker_output) + sizeof (DUMPBASE_SUFFIX),
-			"%s.ltrans%u", linker_output, i);
-	      argv_ptr[0] = dumpbase;
-	    }
+	  int dumpbase_len = (strlen (dumppfx) + sizeof (DUMPBASE_SUFFIX));
+	  char *dumpbase = (char *) xmalloc (dumpbase_len + 1);
+	  snprintf (dumpbase, dumpbase_len, "%sltrans%u.ltrans", dumppfx, i);
+	  argv_ptr[0] = dumpbase;
 
 	  argv_ptr[1] = "-fltrans";
 	  argv_ptr[2] = "-o";
diff --git a/gcc/opts.c b/gcc/opts.c
index ec3ca07..340d9943 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -845,30 +845,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	/* We have a DUMP_DIR_NAME, prepend that.  */
 	opts->x_dump_base_name = opts_concat (opts->x_dump_dir_name,
 					      opts->x_dump_base_name, NULL);
-      else if (opts->x_aux_base_name
-	       && strcmp (opts->x_aux_base_name, HOST_BIT_BUCKET) != 0)
-	/* AUX_BASE_NAME is set and is not the bit bucket.  If it
-	   contains a directory component, prepend those directories.
-	   Typically this places things in the same directory as the
-	   object file.  */
-	{
-	  const char *aux_base;
-
-	  base_of_path (opts->x_aux_base_name, &aux_base);
-	  if (opts->x_aux_base_name != aux_base)
-	    {
-	      int dir_len = aux_base - opts->x_aux_base_name;
-	      char *new_dump_base_name
-		= XOBNEWVEC (&opts_obstack, char,
-			     strlen (opts->x_dump_base_name) + dir_len + 1);
-
-	      /* Copy directory component from OPTS->X_AUX_BASE_NAME.  */
-	      memcpy (new_dump_base_name, opts->x_aux_base_name, dir_len);
-	      /* Append existing OPTS->X_DUMP_BASE_NAME.  */
-	      strcpy (new_dump_base_name + dir_len, opts->x_dump_base_name);
-	      opts->x_dump_base_name = new_dump_base_name;
-	    }
-	}
 
       /* It is definitely prefixed now.  */
       opts->x_dump_base_name_prefixed = true;
@@ -2346,17 +2322,6 @@ common_handle_option (struct gcc_options *opts,
       opts->x_flag_gen_aux_info = 1;
       break;
 
-    case OPT_auxbase_strip:
-      {
-	char *tmp = xstrdup (arg);
-	strip_off_ending (tmp, strlen (tmp));
-	if (tmp[0])
-	  opts->x_aux_base_name = tmp;
-	else
-	  free (tmp);
-      }
-      break;
-
     case OPT_d:
       decode_d_option (arg, opts, loc, dc);
       break;
diff --git a/gcc/testsuite/gcc.misc-tests/outputs-0.c b/gcc/testsuite/gcc.misc-tests/outputs-0.c
new file mode 100644
index 00000000..ca2ac4a
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/outputs-0.c
@@ -0,0 +1 @@
+int main () {}
diff --git a/gcc/testsuite/gcc.misc-tests/outputs-1.c b/gcc/testsuite/gcc.misc-tests/outputs-1.c
new file mode 100644
index 00000000..35f19cf
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/outputs-1.c
@@ -0,0 +1,4 @@
+extern void f();
+int main() {
+  f();
+}
diff --git a/gcc/testsuite/gcc.misc-tests/outputs-2.c b/gcc/testsuite/gcc.misc-tests/outputs-2.c
new file mode 100644
index 00000000..109733d
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/outputs-2.c
@@ -0,0 +1,2 @@
+void f() {
+}
diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp
new file mode 100644
index 00000000..9823710
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
@@ -0,0 +1,695 @@
+# Copyright (C) 2005-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file contains a set of test that check that options intended to
+# control the location and name of GCC outputs behave as expected.
+
+load_lib gcc-defs.exp
+
+set b "outputs"
+
+# These tests don't run runtest_file_p consistently if it
+# doesn't return the same values, so disable parallelization
+# of this *.exp file.  The first parallel runtest to reach
+# this will run all the tests serially.
+if {![gcc_parallel_test_run_p $b] || [is_remote host]} {
+    return
+}
+gcc_parallel_test_enable 0
+
+set gsplit_dwarf "-gsplit-dwarf"
+if ![check_no_compiler_messages gsplitdwarf object {
+    void foo (void) { }
+} "$gsplit_dwarf"] {
+    set gsplit_dwarf ""
+}
+
+# Prepare additional options to be used for linking.
+# We do not compile to an executable, because that requires naming an output.
+set link_options ""
+set dest [target_info name]
+foreach i { ldflags libs ldscripts } {
+    if {[board_info $dest exists $i]} {
+	set skip ""
+	foreach opt [split [board_info $dest $i]] {
+	    if { $skip != "" } then {
+		set skip ""
+	    } elseif { $opt == "-Xlinker" } then {
+		set skip $opt
+	    } elseif { ![string match "-*" $opt] && [file isfile $opt] } {
+	    	set opt "-Wl,$opt"
+	    }
+	    append link_options " additional_flags=$opt"
+	}
+    }
+}
+if {[board_info $dest exists output_format]} {
+    append link_options " additional_flags=-Wl,-oformat,[board_info $dest output_format]"
+}
+
+# For the test named TEST, run the compiler with SOURCES and OPTS, and
+# look in DIRS for OUTPUTS.  SOURCES is a list of suffixes for source
+# files starting with $b in $srcdir/$subdir, OPTS is a string with
+# options to be passed to the compiler, DIRS and OUTPUTS are lists.
+# DIRS is a list of output directories, children before parent, and
+# for each element of DIRS, there should be a corresponding sublist in
+# OUTPUTS.  If OUTPUTS has an additional trailing sublist, that's the
+# output list for the current directory.  Each element of the sublists
+# in OUTPUT is a file name or glob pattern to be checked for; a name
+# starting with a dash or a period is taken as a suffix for $b; with a
+# double dash, or a dash followed by a period, the first dash is
+# replaced with $b-$b; names starting with "a--" or "a-." have "$b"
+# inserted after the first dash.  The glob pattern may expand to more
+# than one file, but then the test will pass when there any number of
+# matches.  So, it's safe to use for a.{out,exe}, but .{i,s,o} and
+# .[iso] will pass even if only the .o is present.
+proc outest { test sources opts dirs outputs } {
+    global b
+    global srcdir
+    global subdir
+    global gsplit_dwarf
+    set src {}
+    foreach s $sources {
+	lappend src $srcdir/$subdir/$b$s
+    }
+    foreach f [glob -nocomplain -path $b -- *] {
+	file delete $f
+    }
+    foreach d $dirs {
+	file mkdir $d
+	foreach f [glob -nocomplain -path $d -- *] {
+	    file delete $d$f
+	}
+    }
+    set options ""
+    foreach opt [split $opts " "] {
+	append options " additional_flags=$opt"
+    }
+    # Add linker flags if we're linking
+    if {![string match "* -\[ESc\] *" " $opts "]} {
+	global link_options
+	append options "$link_options"
+    }
+    set gcc_output [gcc_target_compile $src "" none "$options"]
+    set outs {}
+    foreach d $dirs olist $outputs {
+	foreach og $olist {
+	    if { [string index $og 0] == "-" } then {
+		if { [string index $og 1] == "-" \
+		     || [string index $og 1] == "." } then {
+		    set o "$b-$b[string range $og 1 end]"
+		} else {
+		    set o "$b$og"
+		}
+	    } elseif { [string index $og 0] == "." } then {
+		set o "$b$og"
+	    } elseif { [string range $og 0 2] == "a--" } then {
+		set o "a-$b-[string range $og 3 end]"
+	    } elseif { [string range $og 0 2] == "a-." } then {
+		set o "a-$b.[string range $og 3 end]"
+	    } else {
+		set o "$og"
+	    }
+	    if { "$gsplit_dwarf" == "" \
+		 && [string match "*.dwo" "$og"] } then {
+		continue
+	    }
+	    if { [file exists $d$o] } then {
+		pass "$test: $d$o"
+		file delete $d$o
+	    } else {
+	        set ogl [glob -nocomplain -path $d -- $o]
+		if { $ogl != {} } {
+		    pass "$test: $d$o"
+		    file delete $ogl
+		} else {
+		    fail "$test: $d$o"
+		}
+	    }
+	}
+	foreach ol [glob -nocomplain -path $d$b -- *] {
+	    lappend outs $ol
+	}
+	foreach ol [glob -nocomplain -path $d -- a{-,.}*] {
+	    lappend outs $ol
+	}
+    }
+
+    foreach f $outs {
+	file delete $f
+    }
+    foreach d $dirs {
+	file delete -force $d
+    }
+
+    if { [llength $outs] == 0 } then {
+	pass "$test: extra"
+    } else {
+	fail "$test: extra\n$outs"
+    }
+
+    if { [string equal "$gcc_output" ""] } then {
+	pass "$test: std out"
+    } else {
+	fail "$test: std out\n$gcc_output"
+    }
+
+}
+
+set sing {-0.c}
+set mult {-1.c -2.c}
+
+# Driver-chosen outputs.
+outest "$b asm default 1" $sing "-S" {} {{-0.s}}
+outest "$b asm default 2" $mult "-S" {} {{-1.s -2.s}}
+
+outest "$b obj default 1" $sing "-c" {} {{-0.o}}
+outest "$b obj default 2" $mult "-c" {} {{-1.o -2.o}}
+
+outest "$b exe default 1" $sing "" {} {{a.{out,exe}}}
+outest "$b exe default 2" $mult "" {} {{a.{out,exe}}}
+
+# Driver-chosen aux outputs.
+outest "$b asm savetmp 1" $sing "-S -save-temps" {} {{-0.i -0.s}}
+outest "$b asm savetmp 2" $mult "-S -save-temps" {} {{-1.i -1.s -2.i -2.s}}
+outest "$b obj savetmp unnamed1" $sing "-c -save-temps" {} {{-0.i -0.s -0.o}}
+outest "$b obj savetmp unnamed2" $mult "-c -save-temps" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
+
+# Aux outputs computed within the driver, based on output name (and
+# input).
+outest "$b cpp savetmp named0" $sing "-E -o $b-0.i -save-temps" {} {{-0.i}}
+outest "$b asm savetmp named0" $sing "-S -o $b-0.s -save-temps" {} {{-0.i -0.s}}
+outest "$b obj savetmp named0" $sing "-c -o $b-0.o -save-temps" {} {{-0.i -0.s -0.o}}
+outest "$b cpp savetmp namedb" $sing "-E -o $b.i -save-temps" {} {{.i}}
+outest "$b asm savetmp namedb" $sing "-S -o $b.s -save-temps" {} {{.i .s}}
+outest "$b obj savetmp namedb" $sing "-c -o $b.o -save-temps" {} {{.i .s .o}}
+
+# When linking, the executable name gets prepended to aux output
+# basenames, except when executable and single input share the same
+# basename.
+outest "$b exe savetmp unnamed1" $sing "-save-temps" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
+outest "$b exe savetmp unnamed2" $mult "-save-temps" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe savetmp named0" $sing "-o $b-0.exe -save-temps" {} {{-0.i -0.s -0.o -0.exe}}
+outest "$b exe savetmp namedb" $sing "-o $b.exe -save-temps" {} {{--0.i --0.s --0.o .exe}}
+outest "$b exe savetmp named2" $mult "-o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
+
+# Setting the main output to a dir selects it as the default aux&dump
+# location.
+outest "$b cpp savetmp namedir0" $sing "-E -o o/$b-0.i -save-temps" {o/} {{-0.i} {}}
+outest "$b asm savetmp namedir0" $sing "-S -o o/$b-0.s -save-temps" {o/} {{-0.i -0.s} {}}
+outest "$b obj savetmp namedir0" $sing "-c -o o/$b-0.o -save-temps" {o/} {{-0.i -0.s -0.o} {}}
+outest "$b cpp savetmp namedir" $sing "-E -o o/$b.i -save-temps" {o/} {{.i} {}}
+outest "$b asm savetmp namedir" $sing "-S -o o/$b.s -save-temps" {o/} {{.i .s} {}}
+outest "$b obj savetmp namedir" $sing "-c -o o/$b.o -save-temps" {o/} {{.i .s .o} {}}
+outest "$b exe savetmp namedir0" $sing "-o o/$b-0.exe -save-temps" {o/} {{-0.i -0.s -0.o -0.exe} {}}
+outest "$b exe savetmp namedirb" $sing "-o o/$b.exe -save-temps" {o/} {{--0.i --0.s --0.o .exe} {}}
+outest "$b exe savetmp namedir2" $mult "-o o/$b.exe -save-temps" {o/} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe} {}}
+
+# -save-temps=cwd overrides the aux output location to the current dir.
+outest "$b obj savecwd unnamed1" $sing "-c -save-temps=cwd" {} {{-0.i -0.s -0.o}}
+outest "$b obj savecwd unnamed2" $mult "-c -save-temps=cwd" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
+outest "$b cpp savecwd named0" $sing "-E -o $b-0.i -save-temps=cwd" {} {{-0.i}}
+outest "$b asm savecwd named0" $sing "-S -o $b-0.s -save-temps=cwd" {} {{-0.i -0.s}}
+outest "$b obj savecwd named0" $sing "-c -o $b-0.o -save-temps=cwd" {} {{-0.i -0.s -0.o}}
+outest "$b cpp savecwd namedb" $sing "-E -o $b.i -save-temps=cwd" {} {{.i}}
+outest "$b asm savecwd namedb" $sing "-S -o $b.s -save-temps=cwd" {} {{.i .s}}
+outest "$b obj savecwd namedb" $sing "-c -o $b.o -save-temps=cwd" {} {{.i .s .o}}
+outest "$b exe savecwd unnamed1" $sing "-save-temps=cwd" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
+outest "$b exe savecwd unnamed2" $mult "-save-temps=cwd" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe savecwd named0" $sing "-o $b-0.exe -save-temps=cwd" {} {{-0.i -0.s -0.o -0.exe}}
+outest "$b exe savecwd namedb" $sing "-o $b.exe -save-temps=cwd" {} {{--0.i --0.s --0.o .exe}}
+outest "$b exe savecwd named2" $mult "-o $b.exe -save-temps=cwd" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
+
+outest "$b cpp savecwd namedir0" $sing "-E -o o/$b-0.i -save-temps=cwd" {o/} {{-0.i} {}}
+outest "$b asm savecwd namedir0" $sing "-S -o o/$b-0.s -save-temps=cwd" {o/} {{-0.s} {-0.i}}
+outest "$b obj savecwd namedir0" $sing "-c -o o/$b-0.o -save-temps=cwd" {o/} {{-0.o} {-0.i -0.s}}
+outest "$b cpp savecwd namedir" $sing "-E -o o/$b.i -save-temps=cwd" {o/} {{.i} {}}
+outest "$b asm savecwd namedir" $sing "-S -o o/$b.s -save-temps=cwd" {o/} {{.s} {.i}}
+outest "$b obj savecwd namedir" $sing "-c -o o/$b.o -save-temps=cwd" {o/} {{.o} {.i .s}}
+outest "$b exe savecwd namedir0" $sing "-o o/$b-0.exe -save-temps=cwd" {o/} {{-0.exe} {-0.i -0.s -0.o}}
+outest "$b exe savecwd namedirb" $sing "-o o/$b.exe -save-temps=cwd" {o/} {{.exe} {--0.i --0.s --0.o}}
+outest "$b exe savecwd namedir2" $mult "-o o/$b.exe -save-temps=cwd" {o/} {{.exe} {--1.i --1.s --1.o --2.i --2.s --2.o}}
+
+# -save-temps=obj overrides the aux output location to that of the
+# main output
+outest "$b obj saveobj unnamed1" $sing "-c -save-temps=obj" {} {{-0.i -0.s -0.o}}
+outest "$b obj saveobj unnamed2" $mult "-c -save-temps=obj" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
+outest "$b cpp saveobj named0" $sing "-E -o $b-0.i -save-temps=obj" {} {{-0.i}}
+outest "$b asm saveobj named0" $sing "-S -o $b-0.s -save-temps=obj" {} {{-0.i -0.s}}
+outest "$b obj saveobj named0" $sing "-c -o $b-0.o -save-temps=obj" {} {{-0.i -0.s -0.o}}
+outest "$b cpp saveobj namedb" $sing "-E -o $b.i -save-temps=obj" {} {{.i}}
+outest "$b asm saveobj namedb" $sing "-S -o $b.s -save-temps=obj" {} {{.i .s}}
+outest "$b obj saveobj namedb" $sing "-c -o $b.o -save-temps=obj" {} {{.i .s .o}}
+outest "$b exe saveobj unnamed1" $sing "-save-temps=obj" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
+outest "$b exe saveobj unnamed2" $mult "-save-temps=obj" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe saveobj named0" $sing "-o $b-0.exe -save-temps=obj" {} {{-0.i -0.s -0.o -0.exe}}
+outest "$b exe saveobj namedb" $sing "-o $b.exe -save-temps=obj" {} {{--0.i --0.s --0.o .exe}}
+outest "$b exe saveobj named2" $mult "-o $b.exe -save-temps=obj" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
+
+outest "$b cpp saveobj namedir0" $sing "-E -o o/$b-0.i -save-temps=obj" {o/} {{-0.i} {}}
+outest "$b asm saveobj namedir0" $sing "-S -o o/$b-0.s -save-temps=obj" {o/} {{-0.i -0.s} {}}
+outest "$b obj saveobj namedir0" $sing "-c -o o/$b-0.o -save-temps=obj" {o/} {{-0.i -0.s -0.o} {}}
+outest "$b cpp saveobj namedir" $sing "-E -o o/$b.i -save-temps=obj" {o/} {{.i} {}}
+outest "$b asm saveobj namedir" $sing "-S -o o/$b.s -save-temps=obj" {o/} {{.i .s} {}}
+outest "$b obj saveobj namedir" $sing "-c -o o/$b.o -save-temps=obj" {o/} {{.i .s .o} {}}
+outest "$b exe saveobj namedir0" $sing "-o o/$b-0.exe -save-temps=obj" {o/} {{-0.i -0.s -0.o -0.exe} {}}
+outest "$b exe saveobj namedirb" $sing "-o o/$b.exe -save-temps=obj" {o/} {{--0.i --0.s --0.o .exe} {}}
+outest "$b exe saveobj namedir2" $mult "-o o/$b.exe -save-temps=obj" {o/} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe} {}}
+
+# Check -dumpdir overriding by -save-temps=*, and -save-temps
+# non-overriding, with one catch: the presence of a given dumpdir,
+# even if ultimately overridden, still disables the prepending of the
+# executable basename to the aux&dump output basenames (or rather the
+# appending of the executable basename to the dumpdir).
+outest "$b exe sobjovr namedir0" $sing "-o o/$b-0.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-0.i -0.s -0.o -0.exe} {}}
+outest "$b exe sobjovr namedirb" $sing "-o o/$b.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-0.i -0.s -0.o .exe} {}}
+outest "$b exe sobjovr namedir2" $mult "-o o/$b.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o .exe} {}}
+outest "$b exe scwdovr namedir0" $sing "-o o/$b-0.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{-0.exe} {-0.i -0.s -0.o}}
+outest "$b exe scwdovr namedirb" $sing "-o o/$b.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{.exe} {-0.i -0.s -0.o}}
+outest "$b exe scwdovr namedir2" $mult "-o o/$b.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{.exe} {-1.i -1.s -1.o -2.i -2.s -2.o}}
+outest "$b exe ddstovr namedir0" $sing "-o $b-0.exe -dumpdir o/ -save-temps" {o/} {{-0.i -0.s -0.o} {-0.exe}}
+outest "$b exe ddstovr namedirb" $sing "-o $b.exe -dumpdir o/ -save-temps" {o/} {{-0.i -0.s -0.o} {.exe}}
+outest "$b exe ddstovr namedir2" $mult "-o $b.exe -dumpdir o/ -save-temps" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o} {.exe}}
+
+# Check -dumpdir prevailing over -save-temps*.  Even though -dumpdir
+# overrides the -save-temps=* directory selection, -save-temps remains
+# enabled.
+outest "$b exe soddovr namedir0" $sing "-o o/$b-0.exe -save-temps=obj -dumpdir ./" {o/} {{-0.exe} {-0.i -0.s -0.o}}
+outest "$b exe soddovr namedirb" $sing "-o o/$b.exe -save-temps=obj -dumpdir ./" {o/} {{.exe} {-0.i -0.s -0.o}}
+outest "$b exe soddovr namedir2" $mult "-o o/$b.exe -save-temps=obj -dumpdir ./" {o/} {{.exe} {-1.i -1.s -1.o -2.i -2.s -2.o}}
+outest "$b exe scddovr namedir0" $sing "-o o/$b-0.exe -save-temps=cwd -dumpdir o/" {o/} {{-0.i -0.s -0.o -0.exe} {}}
+outest "$b exe scddovr namedirb" $sing "-o o/$b.exe -save-temps=cwd -dumpdir o/" {o/} {{-0.i -0.s -0.o .exe} {}}
+outest "$b exe scddovr namedir2" $mult "-o o/$b.exe -save-temps=cwd -dumpdir o/" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o .exe} {}}
+outest "$b exe ddstovr namedir0" $sing "-o $b-0.exe -save-temps -dumpdir o/" {o/} {{-0.i -0.s -0.o} {-0.exe}}
+outest "$b exe ddstovr namedirb" $sing "-o $b.exe -save-temps -dumpdir o/" {o/} {{-0.i -0.s -0.o} {.exe}}
+outest "$b exe ddstovr namedir2" $mult "-o $b.exe -save-temps -dumpdir o/" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o} {.exe}}
+
+
+# Compiler- and driver-generated aux and dump outputs.
+# -fdump-rtl-final creates a .c.???r.final dump in the compiler.
+# -fstack-usage creates a .su aux output in the compiler.
+# $gsplit_dwarf extracts a .dwo aux output from the .o in the driver.
+outest "$b asm auxdump 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.s}}
+outest "$b asm auxdump 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-1.c.???r.final -1.su -1.s -2.c.???r.final -2.su -2.s}}
+outest "$b obj auxdump unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+outest "$b obj auxdump unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-1.c.???r.final -1.su -1.dwo -1.o -2.c.???r.final -2.su -2.dwo -2.o}}
+
+outest "$b cpp auxdump named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.i}}
+outest "$b asm auxdump named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.s}}
+outest "$b obj auxdump named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.i}}
+outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .s}}
+outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .dwo .o}}
+
+outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
+outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
+outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
+outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
+outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
+
+outest "$b cpp auxdump namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.i} {}}
+outest "$b asm auxdump namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.s} {}}
+outest "$b obj auxdump namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.o} {}}
+outest "$b cpp auxdump namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.i} {}}
+outest "$b asm auxdump namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.c.???r.final .su .s} {}}
+outest "$b obj auxdump namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.c.???r.final .su .dwo .o} {}}
+outest "$b exe auxdump namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.exe} {}}
+outest "$b exe auxdump namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{--0.c.???r.final --0.su --0.dwo .exe} {}}
+outest "$b exe auxdump namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
+
+# Check that -save-temps doesn't break compiler aux or dumps as it
+# changes temp file names.
+outest "$b asm auxdmps 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
+outest "$b asm auxdmps 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -2.i -2.c.???r.final -2.su -2.s}}
+outest "$b obj auxdmps unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
+outest "$b obj auxdmps unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -1.dwo -1.o -2.i -2.c.???r.final -2.su -2.s -2.dwo -2.o}}
+
+outest "$b cpp auxdmps named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i}}
+outest "$b asm auxdmps named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
+outest "$b obj auxdmps named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
+outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i}}
+outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
+outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
+
+outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
+outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
+outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
+outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
+outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
+
+outest "$b cpp auxdmps namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i} {}}
+outest "$b asm auxdmps namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s} {}}
+outest "$b obj auxdmps namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o} {}}
+outest "$b cpp auxdmps namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i} {}}
+outest "$b asm auxdmps namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i .c.???r.final .su .s} {}}
+outest "$b obj auxdmps namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i .c.???r.final .su .s .dwo .o} {}}
+outest "$b exe auxdmps namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe} {}}
+outest "$b exe auxdmps namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe} {}}
+outest "$b exe auxdmps namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe} {}}
+
+
+# Check that dumpdir changes the location of non-primary outputs
+outest "$b asm dumpdir 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
+outest "$b asm dumpdir 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -2.c.???r.final -2.su} {-1.s -2.s}}
+outest "$b obj dumpdir unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
+outest "$b obj dumpdir unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dumpdir named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{} {-0.i}}
+outest "$b asm dumpdir named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
+outest "$b obj dumpdir named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
+outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{} {.i}}
+outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
+outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
+
+outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
+outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
+outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
+outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
+outest "$b exe dumpdira namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dumpdira named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+outest "$b exe dumpdirb namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
+outest "$b exe dumpdirb named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+
+outest "$b cpp dumpdir namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dumpdir namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su} {-0.s} {}}
+outest "$b obj dumpdir namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.o} {}}
+outest "$b cpp dumpdir namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{} {.i} {}}
+outest "$b asm dumpdir namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su} {.s} {}}
+outest "$b obj dumpdir namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su .dwo} {.o} {}}
+outest "$b exe dumpdir namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe} {}}
+outest "$b exe dumpdir namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {.exe} {}}
+outest "$b exe dumpdir namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe} {}}
+outest "$b exe dumpdira namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
+outest "$b exe dumpdira namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+outest "$b exe dumpdirb namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
+outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+
+# Check that a -dumpbase with a dir component disregards the -dumpdir
+# prefix.  Also, start testing -dumpbase-ext to distinguish between
+# aux and dump files: only the latter retain the named extension.
+# -dumpbase-ext, if absent or used in combination with -dumpbase for
+# an executable name, defaults to the extension of the source file.
+# The specified dumpbase is combined with the dumpdir prefix when
+# processing more than one input (we couldn't use the same dumpbase
+# for them all), or when linking (the specified dumpbase is then used
+# as prefix instead of the linker output, and a new dumpbase is
+# computed per source).
+outest "$b asm dbsovrdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbsovrddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbsovrdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbsovrdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbsovrdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbsovrddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbsovrdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbsovrddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbsovrdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbsovrdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {-0.i}}
+outest "$b asm dbsovrdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbsovrdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbsovrdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {.i}}
+outest "$b asm dbsovrdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
+
+# Nit: -dumpdir affects whether the specified dumpbase is combined
+# into dumpdir or taken as the output basename, even if dumpbase will
+# ultimately override it.
+outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
+outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
+outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
+outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbsovrdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbsovrddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbsovrdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbsovrdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbsovrdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbsovrdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbsovrdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbsovrdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbsovrdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbsovrdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
+outest "$b exe dbsovrdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
+outest "$b exe dbsovrdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbsovrdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
+outest "$b exe dbsovrdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+
+
+# Check that a -dumpbase without a dir component adds to the -dumpdir
+# prefix.
+outest "$b asm dbswthdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbswthddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbswthdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbswthdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbswthdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbswthddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbswthdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbswthddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbswthdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbswthdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {-0.i}}
+outest "$b asm dbswthdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbswthdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbswthdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {.i}}
+outest "$b asm dbswthdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {.o}}
+
+# Nitty details: -dumpdir affects whether the specified dumpbase is
+# combined into dumpdir or taken as the output basename, even if
+# dumpbase will ultimately override it.
+outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
+outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
+outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
+outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbswthdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbswthddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
+outest "$b exe dbswthdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbswthdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbswthdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbswthdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbswthdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbswthdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbswthdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbswthdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
+outest "$b exe dbswthdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
+outest "$b exe dbswthdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbswthdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
+outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+
+
+# Check for the minor differences when -dumpbase is used without
+# -dumpdir.  The main difference between dbwoutdd and dbswthdd tests
+# is in the single-input link tests: with the dump dir/ prefix moved
+# to dumpbase, and without -dumpdir we end up using -dumpbase as the
+# executable prefix rather than as the dumpbase for the single input.
+outest "$b asm dbwoutdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b asm dbwoutddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
+outest "$b asm dbwoutdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
+outest "$b asm dbwoutdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
+outest "$b asm dbwoutdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b asm dbwoutddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
+outest "$b obj dbwoutdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbwoutddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
+outest "$b obj dbwoutdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+outest "$b cpp dbwoutdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{} {-0.i}}
+outest "$b asm dbwoutdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
+outest "$b obj dbwoutdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
+outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{} {.i}}
+outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
+outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
+
+outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
+outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
+outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
+outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
+outest "$b exe dbwoutdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
+outest "$b exe dbwoutdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dbwoutddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
+outest "$b exe dbwoutdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
+
+outest "$b cpp dbwoutdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
+outest "$b asm dbwoutdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
+outest "$b obj dbwoutdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
+outest "$b cpp dbwoutdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{} {.i} {}}
+outest "$b asm dbwoutdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
+outest "$b obj dbwoutdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
+outest "$b exe dbwoutdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe} {}}
+outest "$b exe dbwoutdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
+outest "$b exe dbwoutdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
+outest "$b exe dbwoutdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
+outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
+
+# -fcompare-debug
+outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
+outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
+
+# -flto
+outest "$b lto sing unnamed" $sing "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto mult unnamed" $mult "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.c.???i.icf a--2.c.???i.icf  a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing named" $sing "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
+outest "$b lto mult named" $mult "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
+outest "$b lto sing nameddir" $sing "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
+outest "$b lto mult nameddir" $mult "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
+
+# -dumpbase without -dumpdir.  The trailing dumppfx dash after it is
+# combined with dumpbase turns into a period when passed to lto as
+# -dumpdir, because the dash is introduced by the compiler driver.
+outest "$b lto sing dumpbase unnamed" $sing "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto mult dumpbase unnamed" $mult "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing dumpbase named" $sing "-dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto mult dumpbase named" $mult "-dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto sing dumpbase namedb" $sing "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+outest "$b lto mult dumpbase namedb" $mult "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+
+# -dumpdir without -dumpbase.  The trailing dash in -dumpdir is given
+# by the user, thus not replaced with a dot.
+outest "$b lto sing dumpdir unnamed" $sing "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto mult dumpdir unnamed" $mult "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto sing dumpdir namedb" $sing "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
+outest "$b lto mult dumpdir namedb" $mult "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
+
+# -dumpdir and non-overriding -dumpbase.
+outest "$b lto dbswthdd sing unnamed" $sing "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbswthdd mult unnamed" $mult "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbswthdd sing named" $sing "-dumpdir dir/ -dumpbase $b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto dbswthdd mult named" $mult "-dumpdir dir/ -dumpbase $b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto dbswthdd sing namedb" $sing "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+outest "$b lto dbswthdd mult namedb" $mult "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+
+# -dumpdir and an overriding -dumpbase.
+outest "$b lto dbsovrdd sing unnamed" $sing "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbsovrdd mult unnamed" $mult "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbsovrdd sing named" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto dbsovrdd mult named" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto dbsovrdd sing namedb" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+outest "$b lto dbsovrdd mult namedb" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
+
+# Check that -dumpbase '' gets source names as dumpbases for
+# compilation, and output name as dumpbase for linking, regardless of
+# how many source files.
+outest "$b lto sing empty dumpbase unnamed" $sing "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto mult empty dumpbase unnamed" $mult "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing empty dumpbase named" $sing "-dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.exe} {}}
+outest "$b lto mult empty dumpbase named" $mult "-dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.exe} {}}
+outest "$b lto sing empty dumpbase namedb" $sing "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
+outest "$b lto mult empty dumpbase namedb" $mult "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
+
+# Now with -dumpdir too.
+outest "$b lto sing empty dumpbase dumpdir unnamed" $sing "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto mult empty dumpbase dumpdir unnamed" $mult "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing empty dumpbase dumpdir named" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf --0.wpa.???i.icf --0.ltrans0.ltrans.???r.final --0.ltrans0.ltrans.su} {-0.exe}}
+outest "$b lto mult empty dumpbase dumpdir named" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf --1.wpa.???i.icf --1.ltrans0.ltrans.???r.final --1.ltrans0.ltrans.su} {-1.exe}}
+outest "$b lto sing empty dumpbase dumpdir namedb" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
+outest "$b lto mult empty dumpbase dumpdir namedb" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
+
+# And also with an empty -dumpdir.  That's equivalent to -dumpdir ./,
+# overriding any dumpdir implied by the output.
+outest "$b lto sing empty dumpdir empty dumpbase unnamed" $sing "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto mult empty dumpdir empty dumpbase unnamed" $mult "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing empty dumpdir empty dumpbase named" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.exe} {-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su}}
+outest "$b lto mult empty dumpdir empty dumpbase named" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.exe} {-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su}}
+outest "$b lto sing empty dumpdir empty dumpbase namedb" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
+outest "$b lto mult empty dumpdir empty dumpbase namedb" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
+
+# Now -flto with -save-temps, not exhaustive.
+outest "$b lto st sing empty dumpbase unnamed" $sing "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.i -0.s -0.o -0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st mult empty dumpbase unnamed" $mult "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st sing dumpdir empty dumpbase named" $sing "-dumpdir dir/ -dumpbase \"\" -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf -0.lto_wrapper_args -0.wpa.???i.icf -0.ltrans.out -0.res -0.ltrans0.o -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.ltrans0.ltrans.s -0.ltrans0.ltrans.o} {-0.exe}}
+outest "$b lto st mult dumpdir empty dumpbase named" $mult "-dumpdir dir/ -dumpbase \"\" -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf -1.lto_wrapper_args -1.wpa.???i.icf -1.ltrans.out -1.res -1.ltrans0.o -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.ltrans0.ltrans.s -1.ltrans0.ltrans.o} {-1.exe}}
+outest "$b lto st sing empty dumpbase namedb" $sing "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
+outest "$b lto st mult empty dumpbase namedb" $mult "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
+
+# lto save-temps without -dumpbase.
+outest "$b lto st sing unnamed" $sing "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.i a--0.s a--0.o a--0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st mult unnamed" $mult "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.i a--1.s a--1.o a--1.c.???i.icf a--2.i a--2.s a--2.o a--2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-0.exe}}
+outest "$b lto st mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-1.exe}}
+outest "$b lto st sing namedb" $sing "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
+outest "$b lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
+
+# Below are examples taken from the documentation.
+# They are likely redundant with earlier test,
+# but we want to make sure behavior matches the docs.
+
+# gcc -c foo.c ...
+outest "$b doc single  -c !-o" $sing "-c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
+
+# gcc -c foo.c -o dir/foobar.o ...
+outest "$b doc single  -c +-o" $sing "-c -o dir/$b.o -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo .o} {}}
+
+# gcc foo.c bar.c -o dir/foobar ...
+outest "$b doc double !-c  -o" $mult "-o dir/$b.exe -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
+
+# gcc foo.c -o dir/foo ...
+outest "$b doc single !-c  -o" $sing "-o dir/$b-0 -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo -0} {}}
+
+# gcc -save-temps -S foo.c
+outest "$b doc single  -S -st" $sing "-save-temps -S" {} {{-0.i -0.s}}
+
+# gcc -save-temps -dumpbase save-foo -c foo.c
+outest "$b doc single  -c -st -db" $sing "-save-temps -dumpbase $b -c" {} {{.i .s -0.o}}
+
+# gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
+#   -dumpdir pfx- -save-temps=cwd ...
+outest "$b doc single  -c  -o -db" $sing "-c -o dir/$b.o -dumpbase alt/$b -dumpdir pfx- -save-temps=cwd -fdump-rtl-final -fstack-usage $gsplit_dwarf" {alt/ dir/} {{.i .s .???r.final .su .dwo} {.o} {}}
+
+# gcc foo.c bar.c -c -dumpbase main ...
+outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo -1.o --2.c.???r.final --2.su --2.dwo -2.o}}
+
+# gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
+outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
+
+# gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
+outest "$b doc double !-c  -o -db'' -flto" $mult "-o dir/$b.exe -dumpbase \"\" -flto -O2 -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
+
+
+# gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
+outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
+
+# gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
+outest "$b doc double !-c  -o -dbx" $mult "-o $b.out -dumpbase-ext .out -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .out}}
+
+# gcc -dumpdir pfx- -c foo.c ...
+outest "$b doc single  -c !-o -dd" $sing "-dumpdir $b- -c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo -0.o}}
+
+# gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
+outest "$b doc single  -c  -o -dd" $sing "-dumpdir dir/ -c -o obj/$b.o -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/ obj/} {{.c.???r.final .su .dwo} {.o} {}}
+
+# gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
+outest "$b doc single  -c  -o -dd -st=" $sing "-dumpdir $b- -c -save-temps=obj -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.i -0.s -0.o}}
+
+# gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
+outest "$b doc double  -c !-o -dd -db" $mult "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
+
+# gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
+outest "$b doc single  -c !-o -dd -db" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
+
+# gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
+outest "$b doc double !-c  -o -dd" $mult "-dumpdir dir/ -o $b.exe -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
+
+# gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
+outest "$b doc single !-c  -o -dd -st=" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
+
+
+gcc_parallel_test_enable 1
diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
index 180a9ab..fc7e8e2 100644
--- a/gcc/testsuite/lib/gcc-defs.exp
+++ b/gcc/testsuite/lib/gcc-defs.exp
@@ -285,11 +285,53 @@ proc dg-additional-files { args } {
     set additional_files [lindex $args 1]
 }
 
+set gcc_adjusted_linker_flags 0
+
+# Add -Wl, before any file names in ldflags, libs, and ldscripts, so
+# that default object files or libraries do not change the names of
+# gcc auxiliary outputs.
+
+proc gcc_adjust_linker_flags {} {
+    global gcc_adjusted_linker_flags
+    if {$gcc_adjusted_linker_flags} {
+	return
+    }
+    set gcc_adjusted_linker_flags 1
+
+    if {![is_remote host]} {
+	set dest [target_info name]
+	foreach i { ldflags libs ldscripts } {
+	    if {[board_info $dest exists $i]} {
+		set opts [board_info $dest $i]
+		set nopts {}
+		set skip ""
+		foreach opt [split $opts] {
+		    if { $skip != "" } then {
+			set skip ""
+		    } elseif { $opt == "-Xlinker" } then {
+			set skip $opt
+		    } elseif { ![string match "-*" $opt] \
+				&& [file isfile $opt] } {
+			set opt "-Wl,$opt"
+		    }
+		    lappend nopts $opt
+		}
+		if { $nopts != $opts } {
+		    unset_currtarget_info $i
+		    set_currtarget_info $i "$nopts"
+		}
+	    }
+	}
+    }
+}
+
 # Return an updated version of OPTIONS that mentions any additional
 # source files registered with dg-additional-sources.  SOURCE is the
 # name of the test case.
 
 proc dg-additional-files-options { options source } {
+    gcc_adjust_linker_flags
+
     global additional_sources
     global additional_sources_used
     global additional_files
@@ -305,6 +347,10 @@ proc dg-additional-files-options { options source } {
 	set to_download [concat $to_download $additional_sources]
 	set additional_sources_used "$additional_sources"
 	set additional_sources ""
+	# This option restores naming of aux and dump output files
+	# after input files when multiple input files are named,
+	# instead of getting them combined with the output name.
+	lappend options "additional_flags=-dumpbase \"\""
     }
     if { $additional_files != "" } then { 
 	regsub -all "^| " $additional_files " [file dirname $source]/" additional_files
diff --git a/gcc/testsuite/lib/profopt.exp b/gcc/testsuite/lib/profopt.exp
index 0b853a1..af1fd62f 100644
--- a/gcc/testsuite/lib/profopt.exp
+++ b/gcc/testsuite/lib/profopt.exp
@@ -353,6 +353,10 @@ proc profopt-execute { src } {
 
     set count 0
     foreach option $prof_option_list {
+	# We pass -dumpbase-ext ${execext}[123] to the compile&link
+	# commands so as to avoid the combination of the executable
+	# with the source name in the aux outputs.
+	set execext ".x${count}"
 	set execname1 "${executable}${count}1"
 	set execname2 "${executable}${count}2"
 	set execname3 "${executable}${count}3"
@@ -402,7 +406,7 @@ proc profopt-execute { src } {
 	# Compile for profiling.
 
 	set options "$extra_options"
-	lappend options "additional_flags=$option $extra_flags $profile_option"
+	lappend options "additional_flags=$option $extra_flags $profile_option -dumpbase-ext ${execext}1"
 	set optstr "$option $profile_option"
 	set comp_output [${tool}_target_compile "$src" "$execname1" executable $options]
 	if ![${tool}_check_compile "$testcase compilation" $optstr $execname1 $comp_output] {
@@ -491,7 +495,7 @@ proc profopt-execute { src } {
 	# Compile with feedback-directed optimizations.
 
 	set options "$extra_options"
-	lappend options "additional_flags=$option $extra_flags $feedback_option"
+	lappend options "additional_flags=$option $extra_flags $feedback_option -dumpbase-ext ${execext}2"
 	set optstr "$option $feedback_option"
 	if { [string first "-fauto-profile" $options] >= 0} {
 	    set options [regsub -- "-fauto-profile" $options "-fauto-profile=$tmpdir/$bprefix$base.$ext"]
@@ -548,7 +552,7 @@ proc profopt-execute { src } {
 	# Compile with normal optimizations.
 
 	set options "$extra_options"
-	lappend options "additional_flags=$option"
+	lappend options "additional_flags=$option -dumpbase-ext ${execext}3"
 	set optstr "$option"
 	set comp_output [${tool}_target_compile "$src" "$execname3" "executable" $options]
 	if ![${tool}_check_compile "$testcase compilation" $optstr $execname3 $comp_output] {
diff --git a/gcc/testsuite/lib/scandump.exp b/gcc/testsuite/lib/scandump.exp
index d6ba350..2479c89 100644
--- a/gcc/testsuite/lib/scandump.exp
+++ b/gcc/testsuite/lib/scandump.exp
@@ -32,6 +32,9 @@ proc dump-suffix { arg } {
 proc dump-base { args } {
     set src [lindex $args 0]
     set dumpbase_suf [lindex $args 1]
+    # The dump basename may vary depending on the output name, on
+    # whether there are multiple sources.  We use -dumpbase "" in
+    # gcc-defs to base compilation dumps only on the source basename.
     set dumpbase $src
     if { [string length $dumpbase_suf] != 0 } {
 	regsub {[.][^.]*$} $src $dumpbase_suf dumpbase
diff --git a/gcc/testsuite/lib/scanltranstree.exp b/gcc/testsuite/lib/scanltranstree.exp
index cff956b..6d35bef 100644
--- a/gcc/testsuite/lib/scanltranstree.exp
+++ b/gcc/testsuite/lib/scanltranstree.exp
@@ -37,11 +37,11 @@ proc scan-ltrans-tree-dump { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump "ltrans-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
+		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
 		  [lindex $args 2]
     } else {
 	scan-dump "ltrans-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
+		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
     }
 }
 
@@ -63,10 +63,10 @@ proc scan-ltrans-tree-dump-times { args } {
     if { [llength $args] >= 4 } {
 	scan-dump-times "ltrans-tree" [lindex $args 0] [lindex $args 1] \
 			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" \
-			".exe.ltrans0" [lindex $args 3]
+			".ltrans0.ltrans" [lindex $args 3]
     } else {
 	scan-dump-times "ltrans-tree" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" ".exe.ltrans0"
+			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" ".ltrans0.ltrans"
     }
 }
 
@@ -87,11 +87,11 @@ proc scan-ltrans-tree-dump-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-not "ltrans-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
+		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
 		      [lindex $args 2]
     } else {
 	scan-dump-not "ltrans-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
+		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
     }
 }
 
@@ -113,11 +113,11 @@ proc scan-ltrans-tree-dump-dem { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem "ltrans-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
+		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
 		      [lindex $args 2]
     } else {
 	scan-dump-dem "ltrans-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
+		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
     }
 }
 
@@ -139,10 +139,10 @@ proc scan-ltrans-tree-dump-dem-not { args } {
     if { [llength $args] >= 3 } {
 	scan-dump-dem-not "ltrans-tree" [lindex $args 0] \
 			  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" \
-			  ".exe.ltrans0" [lindex $args 2]
+			  ".ltrans0.ltrans" [lindex $args 2]
     } else {
 	scan-dump-dem-not "ltrans-tree" [lindex $args 0] \
 			  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" \
-			  ".exe.ltrans0"
+			  ".ltrans0.ltrans"
     }
 }
diff --git a/gcc/testsuite/lib/scanwpaipa.exp b/gcc/testsuite/lib/scanwpaipa.exp
index 2f58823..cc50cc4 100644
--- a/gcc/testsuite/lib/scanwpaipa.exp
+++ b/gcc/testsuite/lib/scanwpaipa.exp
@@ -37,11 +37,11 @@ proc scan-wpa-ipa-dump { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump "wpa-ipa" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
+		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
 		  [lindex $args 2]
     } else {
 	scan-dump "wpa-ipa" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
+		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
     }
 }
 
@@ -85,11 +85,11 @@ proc scan-wpa-ipa-dump-times { args } {
     }
     if { [llength $args] >= 4 } {
 	scan-dump-times "wpa-ipa" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".exe.wpa" \
+			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".wpa" \
 			[lindex $args 3]
     } else {
 	scan-dump-times "wpa-ipa" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".exe.wpa"
+			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".wpa"
     }
 }
 
@@ -110,11 +110,11 @@ proc scan-wpa-ipa-dump-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-not "wpa-ipa" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
+		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
 		      [lindex $args 2]
     } else {
 	scan-dump-not "wpa-ipa" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
+		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
     }
 }
 
@@ -136,11 +136,11 @@ proc scan-wpa-ipa-dump-dem { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem "wpa-ipa" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
+		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
 		      [lindex $args 2]
     } else {
 	scan-dump-dem "wpa-ipa" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
+		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
     }
 }
 
@@ -161,10 +161,10 @@ proc scan-wpa-ipa-dump-dem-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem-not "wpa-ipa" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
+			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
 			  [lindex $args 2]
     } else {
 	scan-dump-dem-not "wpa-ipa" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
+			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
     }
 }
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 96316fb..1a75485 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -796,8 +796,8 @@ print_switch_values (print_switch_fn_type print_fn)
 	case OPT_o:
 	case OPT_d:
 	case OPT_dumpbase:
+	case OPT_dumpbase_ext:
 	case OPT_dumpdir:
-	case OPT_auxbase:
 	case OPT_quiet:
 	case OPT_version:
 	  /* Ignore these.  */
@@ -1410,11 +1410,19 @@ process_options (void)
   /* Set aux_base_name if not already set.  */
   if (aux_base_name)
     ;
-  else if (main_input_filename)
+  else if (dump_base_name)
     {
-      char *name = xstrdup (lbasename (main_input_filename));
+      const char *name = dump_base_name;
+      int nlen, len;
+
+      if (dump_base_ext && (len = strlen (dump_base_ext))
+	  && (nlen = strlen (name)) && nlen > len
+	  && strcmp (name + nlen - len, dump_base_ext) == 0)
+	{
+	  char *p = xstrndup (name, nlen - len);
+	  name = p;
+	}
 
-      strip_off_ending (name, strlen (name));
       aux_base_name = name;
     }
   else
@@ -1964,8 +1972,21 @@ static int
 lang_dependent_init (const char *name)
 {
   location_t save_loc = input_location;
-  if (dump_base_name == 0)
-    dump_base_name = name && name[0] ? name : "gccdump";
+  if (!dump_base_name)
+    {
+      dump_base_name = name && name[0] ? name : "gccdump";
+
+      /* We do not want to derive a non-empty dumpbase-ext from an
+	 explicit -dumpbase argument, only from a defaulted
+	 dumpbase.  */
+      if (!dump_base_ext)
+	{
+	  const char *base = lbasename (dump_base_name);
+	  const char *ext = strrchr (base, '.');
+	  if (ext)
+	    dump_base_ext = ext;
+	}
+    }
 
   /* Other front-end initialization.  */
   input_location = BUILTINS_LOCATION;
@@ -1977,20 +1998,25 @@ lang_dependent_init (const char *name)
     {
       init_asm_output (name);
 
-      /* If stack usage information is desired, open the output file.  */
-      if (flag_stack_usage && !flag_generate_lto)
-	stack_usage_file = open_auxiliary_file ("su");
-
-      /* If call graph information is desired, open the output file.  */
-      if (flag_callgraph_info && !flag_generate_lto)
+      if (!flag_generate_lto && !flag_compare_debug)
 	{
-	  callgraph_info_file = open_auxiliary_file ("ci");
-	  /* Write the file header.  */
-	  fprintf (callgraph_info_file,
-		   "graph: { title: \"%s\"\n", main_input_filename);
-	  bitmap_obstack_initialize (NULL);
-	  callgraph_info_external_printed = BITMAP_ALLOC (NULL);
+	  /* If stack usage information is desired, open the output file.  */
+	  if (flag_stack_usage)
+	    stack_usage_file = open_auxiliary_file ("su");
+
+	  /* If call graph information is desired, open the output file.  */
+	  if (flag_callgraph_info)
+	    {
+	      callgraph_info_file = open_auxiliary_file ("ci");
+	      /* Write the file header.  */
+	      fprintf (callgraph_info_file,
+		       "graph: { title: \"%s\"\n", main_input_filename);
+	      bitmap_obstack_initialize (NULL);
+	      callgraph_info_external_printed = BITMAP_ALLOC (NULL);
+	    }
 	}
+      else
+	flag_stack_usage = flag_callgraph_info = false;
     }
 
   /* This creates various _DECL nodes, so needs to be called after the
diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c
index 37f4bda..a65c280 100644
--- a/lto-plugin/lto-plugin.c
+++ b/lto-plugin/lto-plugin.c
@@ -203,6 +203,10 @@ static bool linker_output_known;
 static bool linker_output_auto_nolto_rel;
 static const char *link_output_name = NULL;
 
+/* This indicates link_output_name already contains the dot of the
+   suffix, so we can skip it in extensions.  */
+static int skip_in_suffix = 0;
+
 /* The version of gold being used, or -1 if not gold.  The number is
    MAJOR * 100 + MINOR.  */
 static int gold_version = -1;
@@ -621,14 +625,11 @@ exec_lto_wrapper (char *argv[])
   /* Write argv to a file to avoid a command line that is too long
      Save the file locally on save-temps.  */
   if (save_temps && link_output_name)
-    {
-      arguments_file_name = (char *) xmalloc (strlen (link_output_name)
-				  + sizeof (".lto_wrapper_args") + 1);
-      strcpy (arguments_file_name, link_output_name);
-      strcat (arguments_file_name, ".lto_wrapper_args");
-    }
+    arguments_file_name = concat (link_output_name,
+				  ".lto_wrapper_args"
+				  + skip_in_suffix, NULL);
   else
-     arguments_file_name = make_temp_file (".lto_wrapper_args");
+    arguments_file_name = make_temp_file (".lto_wrapper_args");
   check (arguments_file_name, LDPL_FATAL,
          "Failed to generate a temorary file name");
 
@@ -1439,12 +1440,82 @@ onload (struct ld_plugin_tv *tv)
       if (strstr (collect_gcc_options, "'-fno-use-linker-plugin'"))
 	return LDPS_ERR;
 
-      if ( strstr (collect_gcc_options, "'-save-temps'"))
+      if (strstr (collect_gcc_options, "'-save-temps'"))
 	save_temps = true;
 
       if (strstr (collect_gcc_options, "'-v'")
           || strstr (collect_gcc_options, "'--verbose'"))
 	verbose = true;
+
+      const char *p;
+      if ((p = strstr (collect_gcc_options, "'-dumpdir'")))
+	{
+	  p += sizeof ("'-dumpdir'");
+	  while (*p == ' ')
+	    p++;
+	  const char *start = p;
+	  int ticks = 0, escapes = 0;
+	  /* Count ticks (') and escaped (\.) characters.  Stop at the
+	     end of the options or at a blank after an even number of
+	     ticks (not counting escaped ones.  */
+	  for (p = start; *p; p++)
+	    {
+	      if (*p == '\'')
+		{
+		  ticks++;
+		  continue;
+		}
+	      else if ((ticks % 2) != 0)
+		{
+		  if (*p == ' ')
+		    break;
+		  if (*p == '\\')
+		    {
+		      if (*++p)
+			escapes++;
+		      else
+			p--;
+		    }
+		}
+	    }
+
+	  /* Now allocate a new link_output_name and decode dumpdir
+	     into it.  The loop uses the same logic, except it counts
+	     ticks and escapes backwards (so ticks is adjusted if we
+	     find an odd number of them), and it copies characters
+	     that are escaped or not otherwise skipped.  */
+	  int len = p - start - ticks - escapes + 1;
+	  char *q = xmalloc (len);
+	  link_output_name = q;
+	  int oddticks = (ticks % 2);
+	  ticks += oddticks;
+	  for (p = start; *p; p++)
+	    {
+	      if (*p == '\'')
+		{
+		  ticks--;
+		  continue;
+		}
+	      else if ((ticks % 2) != 0)
+		{
+		  if (*p == ' ')
+		    break;
+		  if (*p == '\\')
+		    {
+		      if (*++p)
+			escapes--;
+		      else
+			p--;
+		    }
+		}
+	      *q++ = *p;
+	    }
+	  *q = '\0';
+	  assert (escapes == 0);
+	  assert (ticks == oddticks);
+	  assert (q - link_output_name == len - 1);
+	  skip_in_suffix = 1;
+	}
     }
 
   return LDPS_OK;
Richard Biener May 26, 2020, 8:52 a.m. UTC | #57
On Tue, 26 May 2020, Alexandre Oliva wrote:

> On May 22, 2020, Richard Biener <rguenther@suse.de> wrote:
> 
> >> https://gcc.gnu.org/pipermail/gcc-patches/2020-May/546015.html
> >> 
> >> Did you by any chance miss it, or choose not to review it?
> 
> > I looked at it shortly but decided somebody else may have more knowledge
> > there - I'd simply trust you'd done things correctly...
> 
> > So unless anybody comes up to review and ack it consider it approved
> > by me after the weekend ;)
> 
> Thanks, here's the combined patch I'm checking in.
> 
> revamp dump and aux output names

I'm seeing a lot of issues.  First any LTO invocations end up with

xgcc: error: unrecognized command-line option '-dumpbase'^M
lto-wrapper: fatal error: /home/rguenther/obj/gcc/xgcc returned 1 exit 
status^M
compilation terminated.^M

and debug tests have

xg++: error: unrecognized command-line option '-dA'; did you mean '-A'

excess errors.

All visible by testing on x86_64-linux.

Did you maybe install a wrong patch or miss some changes?

Thanks,
Richard.

> From: Alexandre Oliva <oliva@adacore.com>
> 
> This patch simplifies (!!!) the logic governing the naming of dump
> files and auxiliary output files in the driver, in the compiler, and
> in the LTO wrapper.  No changes are made to the naming of primary
> outputs, there are often ways to restore past behavior, and a number
> of inconsistencies are fixed.  Some internal options are removed
> (-auxbase and -auxbase-strip), sensible existing uses of -dumpdir and
> -dumpbase options remain unchanged, additional useful cases are added,
> making for what is still admittedly quite complex.  Extensive
> documentation and testcases provide numerous examples, from normal to
> corner cases.
> 
> The most visible changes are:
> 
> - aux and dump files now always go in the same directory, that
> defaults to the directory of the primary output, but that can be
> overridden with -dumpdir, -save-temps=*, or, preserving past behavior,
> with a -dumpbase with a directory component.
> 
> - driver and compiler now have the same notion of naming of auxiliary
> outputs, e.g. .dwo files will no longer be in one location while the
> debug info suggests they are elsewhere, and -save-temps and .dwo
> auxiliary outputs now go in the same location as .su, .ci and
> coverage data, with consistent naming.
> 
> - explicitly-specified primary output names guide not only the
> location of aux and dump outputs: the output base name is also used in
> their base name, as a prefix when also linking (e.g. foo.c bar.c -o
> foobar creates foobar-foo.dwo and foobar-bar.dwo with -gsplit-dwarf),
> or as the base name instead of the input name (foo.c -c -o whatever.o
> creates whatever.su rather than foo.su with -fstack-usage).  The
> preference for the input file base name, quite useful for our
> testsuite, can be restored with -dumpbase "".  When compiling and
> linking tests in the testsuite with additional inputs, we now use this
> flag.  Files named in dejagnu board ldflags, libs, and ldscripts are
> now quoted in the gcc testsuite with -Wl, so that they are not counted
> as additional inputs by the compiler driver.
> 
> - naming a -dumpbase when compiling multiple sources used to cause
> dumps from later compiles to overwrite those of earlier ones; it is
> now used as a prefix when compiling multiple sources, like an
> executable name above.
> 
> - the dumpbase, explicitly specified or computed from output or input
> names, now also governs the naming of aux outputs; since aux outputs
> usually replaced the suffix from the input name, while dump outputs
> append their own additional suffixes, a -dumpbase-ext option is
> introduced to enable a chosen suffix to be dropped from dumpbase to
> form aux output names.
> 
> - LTO dump and aux outputs were quite a mess, sometimes leaking
> temporary output names into -save-temps output names, sometimes
> conversely generating desirable aux outputs in temporary locations.
> They now obey the same logic of compiler aux and dump outputs, landing
> in the expected location and taking the linker output name or an
> explicit dumpbase overrider into account.
> 
> - Naming of -fdump-final-insns outputs now follows the dump file
> naming logic for the .gkd files, and the .gk dump files generated in
> the second -fcompare-debug compilation get the .gk inserted before the
> suffix that -dumpbase-ext drops in aux outputs.
> 
> 
> gcc/ChangeLog:
> 
> 	* common.opt (aux_base_name): Define.
> 	(dumpbase, dumpdir): Mark as Driver options.
> 	(-dumpbase, -dumpdir): Likewise.
> 	(dumpbase-ext, -dumpbase-ext): New.
> 	(auxbase, auxbase-strip): Drop.
> 	* doc/invoke.texi (-dumpbase, -dumpbase-ext, -dumpdir):
> 	Document.
> 	(-o): Introduce the notion of primary output, mention it
> 	influences auxiliary and dump output names as well, add
> 	examples.
> 	(-save-temps): Adjust, move examples into -dump*.
> 	(-save-temps=cwd, -save-temps=obj): Likewise.
> 	(-fdump-final-insns): Adjust.
> 	* dwarf2out.c (gen_producer_string): Drop auxbase and
> 	auxbase_strip; add dumpbase_ext.
> 	* gcc.c (enum save_temps): Add SAVE_TEMPS_DUMP.
> 	(save_temps_prefix, save_temps_length): Drop.
> 	(save_temps_overrides_dumpdir): New.
> 	(dumpdir, dumpbase, dumpbase_ext): New.
> 	(dumpdir_length, dumpdir_trailing_dash_added): New.
> 	(outbase, outbase_length): New.
> 	(The Specs Language): Introduce %".  Adjust %b and %B.
> 	(ASM_FINAL_SPEC): Use %b.dwo for an aux output name always.
> 	Precede object file with %w when it's the primary output.
> 	(cpp_debug_options): Do not pass on incoming -dumpdir,
> 	-dumpbase and -dumpbase-ext options; recompute them with
> 	%:dumps.
> 	(cc1_options): Drop auxbase with and without compare-debug;
> 	use cpp_debug_options instead of dumpbase.  Mark asm output
> 	with %w when it's the primary output.
> 	(static_spec_functions): Drop %:compare-debug-auxbase-opt and
> 	%:replace-exception.  Add %:dumps.
> 	(driver_handle_option): Implement -save-temps=*/-dumpdir
> 	mutual overriding logic.  Save dumpdir, dumpbase and
> 	dumpbase-ext options.  Do not save output_file in
> 	save_temps_prefix.
> 	(adds_single_suffix_p): New.
> 	(single_input_file_index): New.
> 	(process_command): Combine output dir, output base name, and
> 	dumpbase into dumpdir and outbase.
> 	(set_collect_gcc_options): Pass a possibly-adjusted -dumpdir.
> 	(do_spec_1): Optionally dumpdir instead of save_temps_prefix,
> 	and outbase instead of input_basename in %b, %B and in
> 	-save-temps aux files.  Handle empty argument %".
> 	(driver::maybe_run_linker): Adjust dumpdir and auxbase.
> 	(compare_debug_dump_opt_spec_function): Adjust gkd dump file
> 	naming.  Spec-quote the computed -fdump-final-insns file name.
> 	(debug_auxbase_opt): Drop.
> 	(compare_debug_self_opt_spec_function): Drop auxbase-strip
> 	computation.
> 	(compare_debug_auxbase_opt_spec_function): Drop.
> 	(not_actual_file_p): New.
> 	(replace_extension_spec_func): Drop.
> 	(dumps_spec_func): New.
> 	(convert_white_space): Split-out parts into...
> 	(quote_string, whitespace_to_convert_p): ... these.  New.
> 	(quote_spec_char_p, quote_spec, quote_spec_arg): New.
> 	(driver::finalize): Release and reset new variables; drop
> 	removed ones.
> 	* lto-wrapper.c (HAVE_TARGET_EXECUTABLE_SUFFIX): Define if...
> 	(TARGET_EXECUTABLE_SUFFIX): ... is defined; define this to the
> 	empty string otherwise.
> 	(DUMPBASE_SUFFIX): Drop leading period.
> 	(debug_objcopy): Use concat.
> 	(run_gcc): Recognize -save-temps=* as -save-temps too.  Obey
> 	-dumpdir.  Pass on empty dumpdir and dumpbase with a directory
> 	component.  Simplify temp file names.
> 	* opts.c (finish_options): Drop aux base name handling.
> 	(common_handle_option): Drop auxbase-strip handling.
> 	* toplev.c (print_switch_values): Drop auxbase, add
> 	dumpbase-ext.
> 	(process_options): Derive aux_base_name from dump_base_name
> 	and dump_base_ext.
> 	(lang_dependent_init): Compute dump_base_ext along with
> 	dump_base_name.  Disable stack usage and callgraph-info	during
> 	lto generation and compare-debug recompilation.
> 
> gcc/fortran/ChangeLog:
> 
> 	* options.c (gfc_get_option_string): Drop auxbase, add
> 	dumpbase_ext.
> 
> gcc/ada/ChangeLog:
> 
> 	* gcc-interface/lang-specs.h: Drop auxbase and auxbase-strip.
> 	Use %:dumps instead of -dumpbase.  Add %w for implicit .s
> 	primary output.
> 	* switch.adb (Is_Internal_GCC_Switch): Recognize dumpdir and
> 	dumpbase-ext.  Drop auxbase and auxbase-strip.
> 
> lto-plugin/ChangeLog:
> 
> 	* lto-plugin.c (skip_in_suffix): New.
> 	(exec_lto_wrapper): Use skip_in_suffix and concat to build
> 	non-temporary output names.
> 	(onload): Look for -dumpdir in COLLECT_GCC_OPTIONS, and
> 	override link_output_name with it.
> 
> contrib/ChangeLog:
> 
> 	* compare-debug: Adjust for .gkd files named as dump files,
> 	with the source suffix rather than the object suffix.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.misc-tests/outputs.exp: New.
> 	* gcc.misc-tests/outputs-0.c: New.
> 	* gcc.misc-tests/outputs-1.c: New.
> 	* gcc.misc-tests/outputs-2.c: New.
> 	* lib/gcc-defs.exp (gcc_adjusted_linker_flags): New.
> 	(gcc_adjust_linker_flags): New.
> 	(dg-additional-files-options): Call it.  Pass -dumpbase ""
> 	when there are additional sources.
> 	* lib/profopt.exp (profopt-execute): Pass the executable
> 	suffix with -dumpbase-ext.
> 	* lib/scandump.exp (dump-base): Mention -dumpbase "" use.
> 	* lib/scanltranstree.exp: Adjust dump suffix expectation.
> 	* lib/scanwpaipa.exp: Likewise.
> ---
>  contrib/compare-debug                    |   26 +
>  gcc/ada/gcc-interface/lang-specs.h       |   16 -
>  gcc/ada/switch.adb                       |    4 
>  gcc/common.opt                           |   27 +
>  gcc/doc/invoke.texi                      |  385 +++++++++++-
>  gcc/dwarf2out.c                          |    3 
>  gcc/fortran/options.c                    |    4 
>  gcc/gcc.c                                |  938 ++++++++++++++++++++++++------
>  gcc/lto-wrapper.c                        |  157 ++---
>  gcc/opts.c                               |   35 -
>  gcc/testsuite/gcc.misc-tests/outputs-0.c |    1 
>  gcc/testsuite/gcc.misc-tests/outputs-1.c |    4 
>  gcc/testsuite/gcc.misc-tests/outputs-2.c |    2 
>  gcc/testsuite/gcc.misc-tests/outputs.exp |  695 ++++++++++++++++++++++
>  gcc/testsuite/lib/gcc-defs.exp           |   46 +
>  gcc/testsuite/lib/profopt.exp            |   10 
>  gcc/testsuite/lib/scandump.exp           |    3 
>  gcc/testsuite/lib/scanltranstree.exp     |   20 -
>  gcc/testsuite/lib/scanwpaipa.exp         |   20 -
>  gcc/toplev.c                             |   62 +-
>  lto-plugin/lto-plugin.c                  |   87 +++
>  21 files changed, 2126 insertions(+), 419 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-0.c
>  create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-1.c
>  create mode 100644 gcc/testsuite/gcc.misc-tests/outputs-2.c
>  create mode 100644 gcc/testsuite/gcc.misc-tests/outputs.exp
> 
> diff --git a/contrib/compare-debug b/contrib/compare-debug
> index 22870cf..cf80ae3 100755
> --- a/contrib/compare-debug
> +++ b/contrib/compare-debug
> @@ -2,7 +2,7 @@
>  
>  # Compare stripped copies of two given object files.
>  
> -# Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation
> +# Copyright (C) 2007, 2008, 2009, 2010, 2012, 2020 Free Software Foundation
>  # Originally by Alexandre Oliva <aoliva@redhat.com>
>  
>  # This file is part of GCC.
> @@ -183,8 +183,28 @@ $rm "$1.$suf1" "$2.$suf2"
>  
>  trap "exit $status; exit" 0 1 2 15
>  
> -if test -f "$1".gkd || test -f "$2".gkd; then
> -  if cmp "$1".gkd "$2".gkd; then
> +# Replace the suffix in $1 and $2 with .*.gkd, compare them if a
> +# single file is found by the globbing.
> +base1=`echo "$1" | sed '$s,\.[^.]*$,,'` gkd1=
> +for f in "$base1".*.gkd; do
> +  if test "x$gkd1" != x; then
> +    gkd1=
> +    break
> +  elif test -f "$f"; then
> +    gkd1=$f
> +  fi
> +done
> +base2=`echo "$2" | sed '$s,\.[^.]*$,,'` gkd2=
> +for f in "$base2".*.gkd; do
> +  if test "x$gkd2" != x; then
> +    gkd2=
> +    break
> +  elif test -f "$f"; then
> +    gkd2=$f
> +  fi
> +done
> +if test "x$gkd1" != x || test "x$gkd2" != x; then
> +  if cmp "${gkd1-/dev/null}" "${gkd2-/dev/null}"; then
>      :
>    else
>      status=$?
> diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
> index 10f8473..12b7cf5e 100644
> --- a/gcc/ada/gcc-interface/lang-specs.h
> +++ b/gcc/ada/gcc-interface/lang-specs.h
> @@ -34,17 +34,15 @@
>   %{!S:%{!c:%e-c or -S required for Ada}}\
>   gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
> -    %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b) -gnatd_A} \
> -    %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}}} \
> -    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} \
> +    %{fcompare-debug-second:-gnatd_A} \
> +    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
>      %{coverage:-fprofile-arcs -ftest-coverage} "
>  #if defined(TARGET_VXWORKS_RTP)
>     "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
>  #endif
>     "%{gnatea:-gnatez} %{g*&m*&f*} "
>     "%1 %{!S:%{o*:%w%*-gnatO}} \
> -    %i %{S:%W{o*}%{!o*:-o %b.s}} \
> +    %i %{S:%W{o*}%{!o*:-o %w%b.s}} \
>      %{gnatc*|gnats*: -o %j} %{-param*} \
>      %{!gnatc*:%{!gnats*:%(invoke_as)}}", 0, 0, 0},
>  
> @@ -53,9 +51,7 @@
>   %{!c:%e-c required for gnat2why}\
>   gnat1why %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
> -    %{o*:-auxbase-strip %*}%{!o*:-auxbase %b} \
> -    %{a} %{d*} \
> +    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
>      %{gnatea:-gnatez} %{g*&m*&f*} \
>      %1 %{o*:%w%*-gnatO} \
>      %i \
> @@ -66,9 +62,7 @@
>   %{!c:%e-c required for gnat2scil}\
>   gnat1scil %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    -dumpbase %{.adb:%b.adb}%{.ads:%b.ads}%{!.adb:%{!.ads:%b.ada}}\
> -    %{o*:-auxbase-strip %*}%{!o*:-auxbase %b} \
> -    %{a} %{d*} \
> +    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
>      %{gnatea:-gnatez} %{g*&m*&f*} \
>      %1 %{o*:%w%*-gnatO} \
>      %i \
> diff --git a/gcc/ada/switch.adb b/gcc/ada/switch.adb
> index 7cdaa196..b6f4e00 100644
> --- a/gcc/ada/switch.adb
> +++ b/gcc/ada/switch.adb
> @@ -163,9 +163,9 @@ package body Switch is
>        return Is_Switch (Switch_Chars)
>          and then
>            (Switch_Chars (First .. Last) = "-param"        or else
> +           Switch_Chars (First .. Last) = "dumpdir"       or else
>             Switch_Chars (First .. Last) = "dumpbase"      or else
> -           Switch_Chars (First .. Last) = "auxbase-strip" or else
> -           Switch_Chars (First .. Last) = "auxbase");
> +           Switch_Chars (First .. Last) = "dumpbase-ext");
>     end Is_Internal_GCC_Switch;
>  
>     ---------------
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 4464049..1b770bc 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -188,6 +188,12 @@ const char *main_input_basename
>  Variable
>  int main_input_baselength
>  
> +; The base name used for auxiliary output files.
> +; dump_base_name minus dump_base_ext.
> +
> +Variable
> +const char *aux_base_name
> +
>  ; Which options have been printed by --help.
>  Variable
>  char *help_printed
> @@ -252,10 +258,13 @@ Common Separate Alias(d)
>  Common Joined Alias(d)
>  
>  -dumpbase
> -Common Separate Alias(dumpbase)
> +Driver Common Separate Alias(dumpbase)
> +
> +-dumpbase-ext
> +Driver Common Separate Alias(dumpbase-ext)
>  
>  -dumpdir
> -Common Separate Alias(dumpdir)
> +Driver Common Separate Alias(dumpdir)
>  
>  -entry
>  Driver Separate Alias(e)
> @@ -852,12 +861,6 @@ Common Separate Var(aux_info_file_name)
>  aux-info=
>  Common Joined Alias(aux-info)
>  
> -auxbase
> -Common Separate RejectDriver Var(aux_base_name)
> -
> -auxbase-strip
> -Common Separate RejectDriver
> -
>  coverage
>  Driver
>  
> @@ -869,11 +872,15 @@ Common Joined
>  -d<letters>	Enable dumps from specific passes of the compiler.
>  
>  dumpbase
> -Common Separate Var(dump_base_name)
> +Driver Common Separate Var(dump_base_name)
>  -dumpbase <file>	Set the file basename to be used for dumps.
>  
> +dumpbase-ext
> +Driver Common Separate Var(dump_base_ext)
> +-dumpbase-ext .<ext>    Drop a trailing .<ext> from the dump basename to name auxiliary output files.
> +
>  dumpdir
> -Common Separate Var(dump_dir_name)
> +Driver Common Separate Var(dump_dir_name)
>  -dumpdir <dir>	Set the directory name to be used for dumps.
>  
>  dumpmachine
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 8b9935d..78c2f50 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -185,7 +185,9 @@ in the following sections.
>  @table @emph
>  @item Overall Options
>  @xref{Overall Options,,Options Controlling the Kind of Output}.
> -@gccoptlist{-c  -S  -E  -o @var{file}  -x @var{language}  @gol
> +@gccoptlist{-c  -S  -E  -o @var{file} @gol
> +-dumpbase @var{dumpbase}  -dumpbase-ext @var{auxdropsuf} @gol
> +-dumpdir @var{dumppfx}  -x @var{language}  @gol
>  -v  -###  --help@r{[}=@var{class}@r{[},@dots{}@r{]]}  --target-help  --version @gol
>  -pass-exit-codes  -pipe  -specs=@var{file}  -wrapper  @gol
>  @@@var{file}  -ffile-prefix-map=@var{old}=@var{new}  @gol
> @@ -1602,9 +1604,9 @@ Input files that don't require preprocessing are ignored.
>  @cindex output file option
>  @item -o @var{file}
>  @opindex o
> -Place output in file @var{file}.  This applies to whatever
> -sort of output is being produced, whether it be an executable file,
> -an object file, an assembler file or preprocessed C code.
> +Place the primary output in file @var{file}.  This applies to whatever
> +sort of output is being produced, whether it be an executable file, an
> +object file, an assembler file or preprocessed C code.
>  
>  If @option{-o} is not specified, the default is to put an executable
>  file in @file{a.out}, the object file for
> @@ -1613,6 +1615,314 @@ assembler file in @file{@var{source}.s}, a precompiled header file in
>  @file{@var{source}.@var{suffix}.gch}, and all preprocessed C source on
>  standard output.
>  
> +Though @option{-o} names only the primary output, it also affects the
> +naming of auxiliary and dump outputs.  See the examples below.  Unless
> +overridden, both auxiliary outputs and dump outputs are placed in the
> +same directory as the primary output.  In auxiliary outputs, the suffix
> +of the input file is replaced with that of the auxiliary output file
> +type; in dump outputs, the suffix of the dump file is appended to the
> +input file suffix.  In compilation commands, the base name of both
> +auxiliary and dump outputs is that of the primary output; in compile and
> +link commands, the primary output name, minus the executable suffix, is
> +combined with the input file name.  If both share the same base name,
> +disregarding the suffix, the result of the combination is that base
> +name, otherwise, they are concatenated, separated by a dash.
> +
> +@smallexample
> +gcc -c foo.c ...
> +@end smallexample
> +
> +will use @file{foo.o} as the primary output, and place aux outputs and
> +dumps next to it, e.g., aux file @file{foo.dwo} for
> +@option{-gsplit-dwarf}, and dump file @file{foo.c.???r.final} for
> +@option{-fdump-rtl-final}.
> +
> +If a non-linker output file is explicitly specified, aux and dump files
> +by default take the same base name:
> +
> +@smallexample
> +gcc -c foo.c -o dir/foobar.o ...
> +@end smallexample
> +
> +will name aux outputs @file{dir/foobar.*} and dump outputs
> +@file{dir/foobar.c.*}.
> +
> +A linker output will instead prefix aux and dump outputs:
> +
> +@smallexample
> +gcc foo.c bar.c -o dir/foobar ...
> +@end smallexample
> +
> +will generally name aux outputs @file{dir/foobar-foo.*} and
> +@file{dir/foobar-bar.*}, and dump outputs @file{dir/foobar-foo.c.*} and
> +@file{dir/foobar-bar.c.*}.
> +
> +The one exception to the above is when the executable shares the base
> +name with the single input:
> +
> +@smallexample
> +gcc foo.c -o dir/foo ...
> +@end smallexample
> +
> +in which case aux outputs are named @file{dir/foo.*} and dump outputs
> +named @file{dir/foo.c.*}.
> +
> +The location and the names of auxiliary and dump outputs can be adjusted
> +by the options @option{-dumpbase}, @option{-dumpbase-ext},
> +@option{-dumpdir}, @option{-save-temps=cwd}, and
> +@option{-save-temps=obj}.
> +
> +
> +@item -dumpbase @var{dumpbase}
> +@opindex dumpbase
> +This option sets the base name for auxiliary and dump output files.  It
> +does not affect the name of the primary output file.  Intermediate
> +outputs, when preserved, are not regarded as primary outputs, but as
> +auxiliary outputs:
> +
> +@smallexample
> +gcc -save-temps -S foo.c
> +@end smallexample
> +
> +saves the (no longer) temporary preprocessed file in @file{foo.i}, and
> +then compiles to the (implied) output file @file{foo.s}, whereas:
> +
> +@smallexample
> +gcc -save-temps -dumpbase save-foo -c foo.c
> +@end smallexample
> +
> +preprocesses to in @file{save-foo.i}, compiles to @file{save-foo.s} (now
> +an intermediate, thus auxiliary output), and then assembles to the
> +(implied) output file @file{foo.o}.
> +
> +Absent this option, dump and aux files take their names from the input
> +file, or from the (non-linker) output file, if one is explicitly
> +specified: dump output files (e.g. those requested by @option{-fdump-*}
> +options) with the input name suffix, and aux output files (those
> +requested by other non-dump options, e.g. @code{-save-temps},
> +@code{-gsplit-dwarf}, @code{-fcallgraph-info}) without it.
> +
> +Similar suffix differentiation of dump and aux outputs can be attained
> +for explicitly-given @option{-dumpbase basename.suf} by also specifying
> +@option{-dumpbase-ext .suf}.
> +
> +If @var{dumpbase} is explicitly specified with any directory component,
> +any @var{dumppfx} specification (e.g. @option{-dumpdir} or
> +@option{-save-temps=*}) is ignored, and instead of appending to it,
> +@var{dumpbase} fully overrides it:
> +
> +@smallexample
> +gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
> +  -dumpdir pfx- -save-temps=cwd ...
> +@end smallexample
> +
> +creates auxiliary and dump outputs named @file{alt/foo.*}, disregarding
> +@file{dir/} in @option{-o}, the @file{./} prefix implied by
> +@option{-save-temps=cwd}, and @file{pfx-} in @option{-dumpdir}.
> +
> +When @option{-dumpbase} is specified in a command that compiles multiple
> +inputs, or that compiles and then links, it may be combined with
> +@var{dumppfx}, as specified under @option{-dumpdir}.  Then, each input
> +file is compiled using the combined @var{dumppfx}, and default values
> +for @var{dumpbase} and @var{auxdropsuf} are computed for each input
> +file:
> +
> +@smallexample
> +gcc foo.c bar.c -c -dumpbase main ...
> +@end smallexample
> +
> +creates @file{foo.o} and @file{bar.o} as primary outputs, and avoids
> +overwriting the auxiliary and dump outputs by using the @var{dumpbase}
> +as a prefix, creating auxiliary and dump outputs named @file{main-foo.*}
> +and @file{main-bar.*}.
> +
> +An empty string specified as @var{dumpbase} avoids the influence of the
> +output basename in the naming of auxiliary and dump outputs during
> +compilation, computing default values :
> +
> +@smallexample
> +gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
> +@end smallexample
> +
> +will name aux outputs @file{dir/foo.*} and dump outputs
> +@file{dir/foo.c.*}.  Note how their basenames are taken from the input
> +name, but the directory still defaults to that of the output.
> +
> +The empty-string dumpbase does not prevent the use of the output
> +basename for outputs during linking:
> +
> +@smallexample
> +gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
> +@end smallexample
> +
> +The compilation of the source files will name auxiliary outputs
> +@file{dir/foo.*} and @file{dir/bar.*}, and dump outputs
> +@file{dir/foo.c.*} and @file{dir/bar.c.*}.  LTO recompilation during
> +linking will use @file{dir/foobar.} as the prefix for dumps and
> +auxiliary files.
> +
> +
> +@item -dumpbase-ext @var{auxdropsuf}
> +@opindex dumpbase-ext
> +When forming the name of an auxiliary (but not a dump) output file, drop
> +trailing @var{auxdropsuf} from @var{dumpbase} before appending any
> +suffixes.  If not specified, this option defaults to the suffix of a
> +default @var{dumpbase}, i.e., the suffix of the input file when
> +@option{-dumpbase} is not present in the command line, or @var{dumpbase}
> +is combined with @var{dumppfx}.
> +
> +@smallexample
> +gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
> +@end smallexample
> +
> +creates @file{dir/foo.o} as the main output, and generates auxiliary
> +outputs in @file{dir/x-foo.*}, taking the location of the primary
> +output, and dropping the @file{.c} suffix from the @var{dumpbase}.  Dump
> +outputs retain the suffix: @file{dir/x-foo.c.*}.
> +
> +This option is disregarded if it does not match the suffix of a
> +specified @var{dumpbase}, except as an alternative to the executable
> +suffix when appending the linker output base name to @var{dumppfx}, as
> +specified below:
> +
> +@smallexample
> +gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
> +@end smallexample
> +
> +creates @file{main.out} as the primary output, and avoids overwriting
> +the auxiliary and dump outputs by using the executable name minus
> +@var{auxdropsuf} as a prefix, creating auxiliary outputs named
> +@file{main-foo.*} and @file{main-bar.*} and dump outputs named
> +@file{main-foo.c.*} and @file{main-bar.c.*}.
> +
> +
> +@item -dumpdir @var{dumppfx}
> +@opindex dumpdir
> +When forming the name of an auxiliary or dump output file, use
> +@var{dumppfx} as a prefix:
> +
> +@smallexample
> +gcc -dumpdir pfx- -c foo.c ...
> +@end smallexample
> +
> +creates @file{foo.o} as the primary output, and auxiliary outputs named
> +@file{pfx-foo.*}, combining the given @var{dumppfx} with the default
> +@var{dumpbase} derived from the default primary output, derived in turn
> +from the input name.  Dump outputs also take the input name suffix:
> +@file{pfx-foo.c.*}.
> +
> +If @var{dumppfx} is to be used as a directory name, it must end with a
> +directory separator:
> +
> +@smallexample
> +gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
> +@end smallexample
> +
> +creates @file{obj/bar.o} as the primary output, and auxiliary outputs
> +named @file{dir/bar.*}, combining the given @var{dumppfx} with the
> +default @var{dumpbase} derived from the primary output name.  Dump
> +outputs also take the input name suffix: @file{dir/bar.c.*}.
> +
> +It defaults to the location of the output file; options
> +@option{-save-temps=cwd} and @option{-save-temps=obj} override this
> +default, just like an explicit @option{-dumpdir} option.  In case
> +multiple such options are given, the last one prevails:
> +
> +@smallexample
> +gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
> +@end smallexample
> +
> +outputs @file{foo.o}, with auxiliary outputs named @file{foo.*} because
> +@option{-save-temps=*} overrides the @var{dumppfx} given by the earlier
> +@option{-dumpdir} option.  It does not matter that @option{=obj} is the
> +default for @option{-save-temps}, nor that the output directory is
> +implicitly the current directory.  Dump outputs are named
> +@file{foo.c.*}.
> +
> +When compiling from multiple input files, if @option{-dumpbase} is
> +specified, @var{dumpbase}, minus a @var{auxdropsuf} suffix, and a dash
> +are appended to (or override, if containing any directory components) an
> +explicit or defaulted @var{dumppfx}, so that each of the multiple
> +compilations gets differently-named aux and dump outputs.
> +
> +@smallexample
> +gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
> +@end smallexample
> +
> +outputs auxiliary dumps to @file{dir/pfx-main-foo.*} and
> +@file{dir/pfx-main-bar.*}, appending @var{dumpbase}- to @var{dumppfx}.
> +Dump outputs retain the input file suffix: @file{dir/pfx-main-foo.c.*}
> +and @file{dir/pfx-main-bar.c.*}, respectively.  Contrast with the
> +single-input compilation:
> +
> +@smallexample
> +gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
> +@end smallexample
> +
> +that, applying @option{-dumpbase} to a single source, does not compute
> +and append a separate @var{dumpbase} per input file.  Its auxiliary and
> +dump outputs go in @file{dir/pfx-main.*}.
> +
> +When compiling and then linking from multiple input files, a defaulted
> +or explicitly specified @var{dumppfx} also undergoes the @var{dumpbase}-
> +transformation above (e.g. the compilation of @file{foo.c} and
> +@file{bar.c} above, but without @option{-c}).  If neither
> +@option{-dumpdir} nor @option{-dumpbase} are given, the linker output
> +base name, minus @var{auxdropsuf}, if specified, or the executable
> +suffix otherwise, plus a dash is appended to the default @var{dumppfx}
> +instead.  Note, however, that unlike earlier cases of linking:
> +
> +@smallexample
> +gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
> +@end smallexample
> +
> +does not append the output name @file{main} to @var{dumppfx}, because
> +@option{-dumpdir} is explicitly specified.  The goal is that the
> +explicitly-specified @var{dumppfx} may contain the specified output name
> +as part of the prefix, if desired; only an explicitly-specified
> +@option{-dumpbase} would be combined with it, in order to avoid simply
> +discarding a meaningful option.
> +
> +When compiling and then linking from a single input file, the linker
> +output base name will only be appended to the default @var{dumppfx} as
> +above if it does not share the base name with the single input file
> +name.  This has been covered in single-input linking cases above, but
> +not with an explicit @option{-dumpdir} that inhibits the combination,
> +even if overridden by @option{-save-temps=*}:
> +
> +@smallexample
> +gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
> +@end smallexample
> +
> +Auxiliary outputs are named @file{foo.*}, and dump outputs
> +@file{foo.c.*}, in the current working directory as ultimately requested
> +by @option{-save-temps=cwd}.
> +
> +Summing it all up for an intuitive though slightly imprecise data flow:
> +the primary output name is broken into a directory part and a basename
> +part; @var{dumppfx} is set to the former, unless overridden by
> +@option{-dumpdir} or @option{-save-temps=*}, and @var{dumpbase} is set
> +to the latter, unless overriden by @option{-dumpbase}.  If there are
> +multiple inputs or linking, this @var{dumpbase} may be combined with
> +@var{dumppfx} and taken from each input file.  Auxiliary output names
> +for each input are formed by combining @var{dumppfx}, @var{dumpbase}
> +minus suffix, and the auxiliary output suffix; dump output names are
> +only different in that the suffix from @var{dumpbase} is retained.
> +
> +When it comes to auxiliary and dump outputs created during LTO
> +recompilation, a combination of @var{dumppfx} and @var{dumpbase}, as
> +given or as derived from the linker output name but not from inputs,
> +even in cases in which this combination would not otherwise be used as
> +such, is passed down with a trailing period replacing the compiler-added
> +dash, if any, as a @option{-dumpdir} option to @command{lto-wrapper};
> +being involved in linking, this program does not normally get any
> +@option{-dumpbase} and @option{-dumpbase-ext}, and it ignores them.
> +
> +When running sub-compilers, @command{lto-wrapper} appends LTO stage
> +names to the received @var{dumppfx}, ensures it contains a directory
> +component so that it overrides any @option{-dumpdir}, and passes that as
> +@option{-dumpbase} to sub-compilers.
> +
>  @item -v
>  @opindex v
>  Print (on standard error output) the commands executed to run the stages
> @@ -16279,54 +16589,28 @@ computing CRC32).
>  The @var{string} should be different for every file you compile.
>  
>  @item -save-temps
> -@itemx -save-temps=cwd
>  @opindex save-temps
> -Store the usual ``temporary'' intermediate files permanently; place them
> -in the current directory and name them based on the source file.  Thus,
> -compiling @file{foo.c} with @option{-c -save-temps} produces files
> -@file{foo.i} and @file{foo.s}, as well as @file{foo.o}.  This creates a
> -preprocessed @file{foo.i} output file even though the compiler now
> -normally uses an integrated preprocessor.
> +Store the usual ``temporary'' intermediate files permanently; name them
> +as auxiliary output files, as specified described under
> +@option{-dumpbase} and @option{-dumpdir}.
>  
>  When used in combination with the @option{-x} command-line option,
> -@option{-save-temps} is sensible enough to avoid over writing an
> +@option{-save-temps} is sensible enough to avoid overwriting an
>  input source file with the same extension as an intermediate file.
>  The corresponding intermediate file may be obtained by renaming the
>  source file before using @option{-save-temps}.
>  
> -If you invoke GCC in parallel, compiling several different source
> -files that share a common base name in different subdirectories or the
> -same source file compiled for multiple output destinations, it is
> -likely that the different parallel compilers will interfere with each
> -other, and overwrite the temporary files.  For instance:
> -
> -@smallexample
> -gcc -save-temps -o outdir1/foo.o indir1/foo.c&
> -gcc -save-temps -o outdir2/foo.o indir2/foo.c&
> -@end smallexample
> -
> -may result in @file{foo.i} and @file{foo.o} being written to
> -simultaneously by both compilers.
> +@item -save-temps=cwd
> +@opindex save-temps=cwd
> +Equivalent to @option{-save-temps -dumpdir ./}.
>  
>  @item -save-temps=obj
>  @opindex save-temps=obj
> -Store the usual ``temporary'' intermediate files permanently.  If the
> -@option{-o} option is used, the temporary files are based on the
> -object file.  If the @option{-o} option is not used, the
> -@option{-save-temps=obj} switch behaves like @option{-save-temps}.
> -
> -For example:
> -
> -@smallexample
> -gcc -save-temps=obj -c foo.c
> -gcc -save-temps=obj -c bar.c -o dir/xbar.o
> -gcc -save-temps=obj foobar.c -o dir2/yfoobar
> -@end smallexample
> -
> -@noindent
> -creates @file{foo.i}, @file{foo.s}, @file{dir/xbar.i},
> -@file{dir/xbar.s}, @file{dir2/yfoobar.i}, @file{dir2/yfoobar.s}, and
> -@file{dir2/yfoobar.o}.
> +Equivalent to @option{-save-temps -dumpdir @file{outdir/}}, where
> +@file{outdir/} is the directory of the output file specified after the
> +@option{-o} option, including any directory separators.  If the
> +@option{-o} option is not used, the @option{-save-temps=obj} switch
> +behaves like @option{-save-temps=cwd}.
>  
>  @item -time@r{[}=@var{file}@r{]}
>  @opindex time
> @@ -16363,7 +16647,7 @@ can later tell what file was being compiled, and with which options.
>  Dump the final internal representation (RTL) to @var{file}.  If the
>  optional argument is omitted (or if @var{file} is @code{.}), the name
>  of the dump file is determined by appending @code{.gkd} to the
> -compilation output file name.
> +dump base name, see @option{-dumpbase}.
>  
>  @item -fcompare-debug@r{[}=@var{opts}@r{]}
>  @opindex fcompare-debug
> @@ -30630,17 +30914,24 @@ together or combine them with constant text in a single argument.
>  @item %%
>  Substitute one @samp{%} into the program name or argument.
>  
> +@item %"
> +Substitute an empty argument.
> +
>  @item %i
>  Substitute the name of the input file being processed.
>  
>  @item %b
> -Substitute the basename of the input file being processed.
> -This is the substring up to (and not including) the last period
> -and not including the directory.
> +Substitute the basename for outputs related with the input file being
> +processed.  This is often the substring up to (and not including) the
> +last period and not including the directory but, unless %w is active, it
> +expands to the basename for auxiliary outputs, which may be influenced
> +by an explicit output name, and by various other options that control
> +how auxiliary outputs are named.
>  
>  @item %B
>  This is the same as @samp{%b}, but include the file suffix (text after
> -the last period).
> +the last period).  Without %w, it expands to the basename for dump
> +outputs.
>  
>  @item %d
>  Marks the argument containing or following the @samp{%d} as a
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index fad5eb4..9deca03 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -24351,9 +24351,8 @@ gen_producer_string (void)
>        case OPT_o:
>        case OPT_d:
>        case OPT_dumpbase:
> +      case OPT_dumpbase_ext:
>        case OPT_dumpdir:
> -      case OPT_auxbase:
> -      case OPT_auxbase_strip:
>        case OPT_quiet:
>        case OPT_version:
>        case OPT_v:
> diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
> index 4cc8a90..d844fa9 100644
> --- a/gcc/fortran/options.c
> +++ b/gcc/fortran/options.c
> @@ -838,8 +838,8 @@ gfc_get_option_string (void)
>          case OPT_o:
>          case OPT_d:
>          case OPT_dumpbase:
> +        case OPT_dumpbase_ext:
>          case OPT_dumpdir:
> -        case OPT_auxbase:
>          case OPT_quiet:
>          case OPT_version:
>          case OPT_fintrinsic_modules_path:
> @@ -864,8 +864,8 @@ gfc_get_option_string (void)
>          case OPT_o:
>          case OPT_d:
>          case OPT_dumpbase:
> +        case OPT_dumpbase_ext:
>          case OPT_dumpdir:
> -        case OPT_auxbase:
>          case OPT_quiet:
>          case OPT_version:
>          case OPT_fintrinsic_modules_path:
> diff --git a/gcc/gcc.c b/gcc/gcc.c
> index b0d0308..8c851d7 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -270,12 +270,36 @@ static const char *target_sysroot_hdrs_suffix = 0;
>  static enum save_temps {
>    SAVE_TEMPS_NONE,		/* no -save-temps */
>    SAVE_TEMPS_CWD,		/* -save-temps in current directory */
> +  SAVE_TEMPS_DUMP,              /* -save-temps in dumpdir */
>    SAVE_TEMPS_OBJ		/* -save-temps in object directory */
>  } save_temps_flag;
>  
> -/* Output file to use to get the object directory for -save-temps=obj  */
> -static char *save_temps_prefix = 0;
> -static size_t save_temps_length = 0;
> +/* Set this iff the dumppfx implied by a -save-temps=* option is to
> +   override a -dumpdir option, if any.  */
> +static bool save_temps_overrides_dumpdir = false;
> +
> +/* -dumpdir, -dumpbase and -dumpbase-ext flags passed in, possibly
> +   rearranged as they are to be passed down, e.g., dumpbase and
> +   dumpbase_ext may be cleared if integrated with dumpdir or
> +   dropped.  */
> +static char *dumpdir, *dumpbase, *dumpbase_ext;
> +
> +/* Usually the length of the string in dumpdir.  However, during
> +   linking, it may be shortened to omit a driver-added trailing dash,
> +   by then replaced with a trailing period, that is still to be passed
> +   to sub-processes in -dumpdir, but not to be generally used in spec
> +   filename expansions.  See maybe_run_linker.  */
> +static size_t dumpdir_length = 0;
> +
> +/* Set if the last character in dumpdir is (or was) a dash that the
> +   driver added to dumpdir after dumpbase or linker output name.  */
> +static bool dumpdir_trailing_dash_added = false;
> +
> +/* Basename of dump and aux outputs, computed from dumpbase (given or
> +   derived from output name), to override input_basename in non-%w %b
> +   et al.  */
> +static char *outbase;
> +static size_t outbase_length = 0;
>  
>  /* The compiler version.  */
>  
> @@ -402,13 +426,16 @@ static const char *find_plugindir_spec_function (int, const char **);
>  static const char *print_asm_header_spec_function (int, const char **);
>  static const char *compare_debug_dump_opt_spec_function (int, const char **);
>  static const char *compare_debug_self_opt_spec_function (int, const char **);
> -static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
>  static const char *pass_through_libs_spec_func (int, const char **);
> -static const char *replace_extension_spec_func (int, const char **);
> +static const char *dumps_spec_func (int, const char **);
>  static const char *greater_than_spec_func (int, const char **);
>  static const char *debug_level_greater_than_spec_func (int, const char **);
>  static const char *find_fortran_preinclude_file (int, const char **);
>  static char *convert_white_space (char *);
> +static char *quote_spec (char *);
> +static char *quote_spec_arg (char *);
> +static bool not_actual_file_p (const char *);
> +
>  
>  /* The Specs Language
>  
> @@ -426,12 +453,19 @@ expanding these sequences; therefore, you can concatenate them together
>  or with constant text in a single argument.
>  
>   %%	substitute one % into the program name or argument.
> + %"     substitute an empty argument.
>   %i     substitute the name of the input file being processed.
> - %b     substitute the basename of the input file being processed.
> -	This is the substring up to (and not including) the last period
> -	and not including the directory unless -save-temps was specified
> -	to put temporaries in a different location.
> - %B	same as %b, but include the file suffix (text after the last period).
> + %b     substitute the basename for outputs related with the input file
> +	being processed.  This is often a substring of the input file name,
> +	up to (and not including) the last period but, unless %w is active,
> +	it is affected by the directory selected by -save-temps=*, by
> +	-dumpdir, and, in case of multiple compilations, even by -dumpbase
> +	and -dumpbase-ext and, in case of linking, by the linker output
> +	name.  When %w is active, it derives the main output name only from
> +	the input file base name; when it is not, it names aux/dump output
> +	file.
> + %B	same as %b, but include the input file suffix (text after the last
> +	period).
>   %gSUFFIX
>  	substitute a file name that has suffix SUFFIX and is chosen
>  	once per compilation, and mark the argument a la %d.  To reduce
> @@ -641,10 +675,10 @@ proper position among the other output files.  */
>  #define ASM_FINAL_SPEC \
>    "%{gsplit-dwarf: \n\
>         objcopy --extract-dwo \
> -	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> -	 %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
> +	 %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
> +	 %b.dwo \n\
>         objcopy --strip-dwo \
> -	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +	 %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
>      }"
>  #endif
>  
> @@ -1144,22 +1178,20 @@ static const char *cpp_options =
>  
>  /* This contains cpp options which are not passed when the preprocessor
>     output will be used by another program.  */
> -static const char *cpp_debug_options = "%{d*}";
> +static const char *cpp_debug_options = "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps()";
>  
>  /* NB: This is shared amongst all front-ends, except for Ada.  */
>  static const char *cc1_options =
>  "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
>   %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
> - %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
> - %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
> - %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
> + %1 %{!Q:-quiet} %(cpp_debug_options) %{m*} %{aux-info*}\
>   %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
>   %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
>   %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
>   %{-target-help:--target-help}\
>   %{-version:--version}\
>   %{-help=*:--help=%*}\
> - %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
> + %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}}\
>   %{fsyntax-only:-o %j} %{-param*}\
>   %{coverage:-fprofile-arcs -ftest-coverage}\
>   %{fprofile-arcs|fprofile-generate*|coverage:\
> @@ -1647,9 +1679,8 @@ static const struct spec_function static_spec_functions[] =
>    { "print-asm-header",		print_asm_header_spec_function },
>    { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
>    { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
> -  { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
>    { "pass-through-libs",	pass_through_libs_spec_func },
> -  { "replace-extension",	replace_extension_spec_func },
> +  { "dumps",                    dumps_spec_func },
>    { "gt",			greater_than_spec_func },
>    { "debug-level-gt",		debug_level_greater_than_spec_func },
>    { "fortran-preinclude-file",	find_fortran_preinclude_file},
> @@ -4145,7 +4176,8 @@ driver_handle_option (struct gcc_options *opts,
>        return true;
>  
>      case OPT_save_temps:
> -      save_temps_flag = SAVE_TEMPS_CWD;
> +      if (!save_temps_flag)
> +	save_temps_flag = SAVE_TEMPS_DUMP;
>        validated = true;
>        break;
>  
> @@ -4158,6 +4190,23 @@ driver_handle_option (struct gcc_options *opts,
>        else
>  	fatal_error (input_location, "%qs is an unknown %<-save-temps%> option",
>  		     decoded->orig_option_with_args_text);
> +      save_temps_overrides_dumpdir = true;
> +      break;
> +
> +    case OPT_dumpdir:
> +      free (dumpdir);
> +      dumpdir = xstrdup (arg);
> +      save_temps_overrides_dumpdir = false;
> +      break;
> +
> +    case OPT_dumpbase:
> +      free (dumpbase);
> +      dumpbase = xstrdup (arg);
> +      break;
> +
> +    case OPT_dumpbase_ext:
> +      free (dumpbase_ext);
> +      dumpbase_ext = xstrdup (arg);
>        break;
>  
>      case OPT_no_canonical_prefixes:
> @@ -4264,8 +4313,6 @@ driver_handle_option (struct gcc_options *opts,
>        arg = convert_filename (arg, ! have_c, 0);
>  #endif
>        output_file = arg;
> -      /* Save the output name in case -save-temps=obj was used.  */
> -      save_temps_prefix = xstrdup (arg);
>        /* On some systems, ld cannot handle "-o" without a space.  So
>  	 split the option from its argument.  */
>        save_switch ("-o", 1, &arg, validated, true);
> @@ -4308,6 +4355,19 @@ driver_handle_option (struct gcc_options *opts,
>    return true;
>  }
>  
> +/* Return true if F2 is F1 followed by a single suffix, i.e., by a
> +   period and additional characters other than a period.  */
> +
> +static inline bool
> +adds_single_suffix_p (const char *f2, const char *f1)
> +{
> +  size_t len = strlen (f1);
> +
> +  return (strncmp (f1, f2, len) == 0
> +	  && f2[len] == '.'
> +	  && strchr (f2 + len + 1, '.') == NULL);
> +}
> +
>  /* Put the driver's standard set of option handlers in *HANDLERS.  */
>  
>  static void
> @@ -4324,6 +4384,32 @@ set_option_handlers (struct cl_option_handlers *handlers)
>    handlers->handlers[2].mask = CL_TARGET;
>  }
>  
> +
> +/* Return the index into infiles for the single non-library
> +   non-lto-wpa input file, -1 if there isn't any, or -2 if there is
> +   more than one.  */
> +static inline int
> +single_input_file_index ()
> +{
> +  int ret = -1;
> +
> +  for (int i = 0; i < n_infiles; i++)
> +    {
> +      if (infiles[i].language
> +	  && (infiles[i].language[0] == '*'
> +	      || (flag_wpa
> +		  && strcmp (infiles[i].language, "lto") == 0)))
> +	continue;
> +
> +      if (ret != -1)
> +	return -2;
> +
> +      ret = i;
> +    }
> +
> +  return ret;
> +}
> +
>  /* Create the vector `switches' and its contents.
>     Store its length in `n_switches'.  */
>  
> @@ -4636,23 +4722,371 @@ process_command (unsigned int decoded_options_count,
>    if (output_file != NULL && output_file[0] == '\0')
>      fatal_error (input_location, "output filename may not be empty");
>  
> +  /* -dumpdir and -save-temps=* both specify the location of aux/dump
> +     outputs; the one that appears last prevails.  When compiling
> +     multiple sources, an explicit dumpbase (minus -ext) may be
> +     combined with an explicit or implicit dumpdir, whereas when
> +     linking, a specified or implied link output name (minus
> +     extension) may be combined with a prevailing -save-temps=* or an
> +     otherwise implied dumpdir, but not override a prevailing
> +     -dumpdir.  Primary outputs (e.g., linker output when linking
> +     without -o, or .i, .s or .o outputs when processing multiple
> +     inputs with -E, -S or -c, respectively) are NOT affected by these
> +     -save-temps=/-dump* options, always landing in the current
> +     directory and with the same basename as the input when an output
> +     name is not given, but when they're intermediate outputs, they
> +     are named like other aux outputs, so the options affect their
> +     location and name.
> +
> +     Here are some examples.  There are several more in the
> +     documentation of -o and -dump*, and some quite exhaustive tests
> +     in gcc.misc-tests/outputs.exp.
> +
> +     When compiling any number of sources, no -dump* nor
> +     -save-temps=*, all outputs in cwd without prefix:
> +
> +     # gcc -c b.c -gsplit-dwarf
> +     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
> +
> +     # gcc -c b.c d.c -gsplit-dwarf
> +     -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
> +     && cc1 [-dumpdir ./] -dumpbase d.c -dumpbase-ext .c # d.o d.dwo
> +
> +     When compiling and linking, no -dump* nor -save-temps=*, .o
> +     outputs are temporary, aux outputs land in the dir of the output,
> +     prefixed with the basename of the linker output:
> +
> +     # gcc b.c d.c -o ab -gsplit-dwarf
> +     -> cc1 -dumpdir ab- -dumpbase b.c -dumpbase-ext .c # ab-b.dwo
> +     && cc1 -dumpdir ab- -dumpbase d.c -dumpbase-ext .c # ab-d.dwo
> +     && link ... -o ab
> +
> +     # gcc b.c d.c [-o a.out] -gsplit-dwarf
> +     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.dwo
> +     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.dwo
> +     && link ... [-o a.out]
> +
> +     When compiling and linking, a prevailing -dumpdir fully overrides
> +     the prefix of aux outputs given by the output name:
> +
> +     # gcc -dumpdir f b.c d.c -gsplit-dwarf [-o [dir/]whatever]
> +     -> cc1 -dumpdir f -dumpbase b.c -dumpbase-ext .c # fb.dwo
> +     && cc1 -dumpdir f -dumpbase d.c -dumpbase-ext .c # fd.dwo
> +     && link ... [-o whatever]
> +
> +     When compiling multiple inputs, an explicit -dumpbase is combined
> +     with -dumpdir, affecting aux outputs, but not the .o outputs:
> +
> +     # gcc -dumpdir f -dumpbase g- b.c d.c -gsplit-dwarf -c
> +     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # b.o fg-b.dwo
> +     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # d.o fg-d.dwo
> +
> +     When compiling and linking with -save-temps, the .o outputs that
> +     would have been temporary become aux outputs, so they get
> +     affected by -dump* flags:
> +
> +     # gcc -dumpdir f -dumpbase g- -save-temps b.c d.c
> +     -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # fg-b.o
> +     && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # fg-d.o
> +     && link
> +
> +     If -save-temps=* prevails over -dumpdir, however, the explicit
> +     -dumpdir is discarded, as if it wasn't there.  The basename of
> +     the implicit linker output, a.out or a.exe, becomes a- as the aux
> +     output prefix for all compilations:
> +
> +     # gcc [-dumpdir f] -save-temps=cwd b.c d.c
> +     -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.o
> +     && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.o
> +     && link
> +
> +     A single -dumpbase, applying to multiple inputs, overrides the
> +     linker output name, implied or explicit, as the aux output prefix:
> +
> +     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c
> +     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
> +     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
> +     && link
> +
> +     # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c -o dir/h.out
> +     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
> +     && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
> +     && link -o dir/h.out
> +
> +     Now, if the linker output is NOT overridden as a prefix, but
> +     -save-temps=* overrides implicit or explicit -dumpdir, the
> +     effective dump dir combines the dir selected by the -save-temps=*
> +     option with the basename of the specified or implied link output:
> +
> +     # gcc [-dumpdir f] -save-temps=cwd b.c d.c -o dir/h.out
> +     -> cc1 -dumpdir h- -dumpbase b.c -dumpbase-ext .c # h-b.o
> +     && cc1 -dumpdir h- -dumpbase d.c -dumpbase-ext .c # h-d.o
> +     && link -o dir/h.out
> +
> +     # gcc [-dumpdir f] -save-temps=obj b.c d.c -o dir/h.out
> +     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
> +     && cc1 -dumpdir dir/h- -dumpbase d.c -dumpbase-ext .c # dir/h-d.o
> +     && link -o dir/h.out
> +
> +     But then again, a single -dumpbase applying to multiple inputs
> +     gets used instead of the linker output basename in the combined
> +     dumpdir:
> +
> +     # gcc [-dumpdir f] -dumpbase g- -save-temps=obj b.c d.c -o dir/h.out
> +     -> cc1 -dumpdir dir/g- -dumpbase b.c -dumpbase-ext .c # dir/g-b.o
> +     && cc1 -dumpdir dir/g- -dumpbase d.c -dumpbase-ext .c # dir/g-d.o
> +     && link -o dir/h.out
> +
> +     With a single input being compiled, the output basename does NOT
> +     affect the dumpdir prefix.
> +
> +     # gcc -save-temps=obj b.c -gsplit-dwarf -c -o dir/b.o
> +     -> cc1 -dumpdir dir/ -dumpbase b.c -dumpbase-ext .c # dir/b.o dir/b.dwo
> +
> +     but when compiling and linking even a single file, it does:
> +
> +     # gcc -save-temps=obj b.c -o dir/h.out
> +     -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
> +
> +     unless an explicit -dumpdir prevails:
> +
> +     # gcc -save-temps[=obj] -dumpdir g- b.c -o dir/h.out
> +     -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
> +
> +  */
> +
> +  bool explicit_dumpdir = dumpdir;
> +
> +  if (!save_temps_overrides_dumpdir && explicit_dumpdir)
> +    {
> +      /* Do nothing.  */
> +    }
> +
>    /* If -save-temps=obj and -o name, create the prefix to use for %b.
>       Otherwise just make -save-temps=obj the same as -save-temps=cwd.  */
> -  if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL)
> +  else if (save_temps_flag != SAVE_TEMPS_CWD && output_file != NULL)
> +    {
> +      free (dumpdir);
> +      dumpdir = NULL;
> +      temp = lbasename (output_file);
> +      if (temp != output_file)
> +	dumpdir = xstrndup (output_file,
> +			    strlen (output_file) - strlen (temp));
> +    }
> +  else if (dumpdir)
> +    {
> +      free (dumpdir);
> +      dumpdir = NULL;
> +    }
> +
> +  if (save_temps_flag)
> +    save_temps_flag = SAVE_TEMPS_DUMP;
> +
> +  /* If there is any pathname component in an explicit -dumpbase, it
> +     overrides dumpdir entirely, so discard it right away.  Although
> +     the presence of an explicit -dumpdir matters for the driver, it
> +     shouldn't matter for other processes, that get all that's needed
> +     from the -dumpdir and -dumpbase always passed to them.  */
> +  if (dumpdir && dumpbase && lbasename (dumpbase) != dumpbase)
>      {
> -      save_temps_length = strlen (save_temps_prefix);
> -      temp = strrchr (lbasename (save_temps_prefix), '.');
> -      if (temp)
> +      free (dumpdir);
> +      dumpdir = NULL;
> +    }
> +
> +  /* Check that dumpbase_ext matches the end of dumpbase, drop it
> +     otherwise.  */
> +  if (dumpbase_ext && dumpbase && *dumpbase)
> +    {
> +      int lendb = strlen (dumpbase);
> +      int lendbx = strlen (dumpbase_ext);
> +
> +      if (lendbx >= lendb
> +	  || strcmp (dumpbase + lendb - lendbx, dumpbase_ext) != 0)
>  	{
> -	  save_temps_length -= strlen (temp);
> -	  save_temps_prefix[save_temps_length] = '\0';
> +	  free (dumpbase_ext);
> +	  dumpbase_ext = NULL;
>  	}
> +    }
> +
> +  /* -dumpbase with multiple sources goes into dumpdir.  With a single
> +     source, it does only if linking and if dumpdir was not explicitly
> +     specified.  */
> +  if (dumpbase && *dumpbase
> +      && (single_input_file_index () == -2
> +	  || (!have_c && !explicit_dumpdir)))
> +    {
> +      char *prefix;
>  
> +      if (dumpbase_ext)
> +	/* We checked that they match above.  */
> +	dumpbase[strlen (dumpbase) - strlen (dumpbase_ext)] = '\0';
> +
> +      if (dumpdir)
> +	prefix = concat (dumpdir, dumpbase, "-", NULL);
> +      else
> +	prefix = concat (dumpbase, "-", NULL);
> +
> +      free (dumpdir);
> +      free (dumpbase);
> +      free (dumpbase_ext);
> +      dumpbase = dumpbase_ext = NULL;
> +      dumpdir = prefix;
> +      dumpdir_trailing_dash_added = true;
> +    }
> +
> +  /* If dumpbase was not brought into dumpdir but we're linking, bring
> +     output_file into dumpdir unless dumpdir was explicitly specified.
> +     The test for !explicit_dumpdir is further below, because we want
> +     to use the obase computation for a ghost outbase, passed to
> +     GCC_COLLECT_OPTIONS.  */
> +  else if (!have_c && (!explicit_dumpdir || (dumpbase && !*dumpbase)))
> +    {
> +      /* If we get here, we know dumpbase was not specified, or it was
> +	 specified as an empty string.  If it was anything else, it
> +	 would have combined with dumpdir above, because the condition
> +	 for dumpbase to be used when present is broader than the
> +	 condition that gets us here.  */
> +      gcc_assert (!dumpbase || !*dumpbase);
> +
> +      const char *obase;
> +      char *tofree = NULL;
> +      if (!output_file || not_actual_file_p (output_file))
> +	obase = "a";
> +      else
> +	{
> +	  obase = lbasename (output_file);
> +	  size_t blen = strlen (obase), xlen;
> +	  /* Drop the suffix if it's dumpbase_ext, if given,
> +	     otherwise .exe or the target executable suffix, or if the
> +	     output was explicitly named a.out, but not otherwise.  */
> +	  if (dumpbase_ext
> +	      ? (blen > (xlen = strlen (dumpbase_ext))
> +		 && strcmp ((temp = (obase + blen - xlen)),
> +			    dumpbase_ext) == 0)
> +	      : ((temp = strrchr (obase + 1, '.'))
> +		 && (xlen = strlen (temp))
> +		 && (strcmp (temp, ".exe") == 0
> +#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
> +		     || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
> +#endif
> +		     || strcmp (obase, "a.out") == 0)))
> +	    {
> +	      tofree = xstrndup (obase, blen - xlen);
> +	      obase = tofree;
> +	    }
> +	}
> +
> +      /* We wish to save this basename to the -dumpdir passed through
> +	 GCC_COLLECT_OPTIONS within maybe_run_linker, for e.g. LTO,
> +	 but we do NOT wish to add it to e.g. %b, so we keep
> +	 outbase_length as zero.  */
> +      gcc_assert (!outbase);
> +      outbase_length = 0;
> +
> +      /* If we're building [dir1/]foo[.exe] out of a single input
> +	 [dir2/]foo.c that shares the same basename, dump to
> +	 [dir2/]foo.c.* rather than duplicating the basename into
> +	 [dir2/]foo-foo.c.*.  */
> +      int idxin;
> +      if (dumpbase
> +	  || ((idxin = single_input_file_index ()) >= 0
> +	      && adds_single_suffix_p (lbasename (infiles[idxin].name),
> +				       obase)))
> +	{
> +	  if (obase == tofree)
> +	    outbase = tofree;
> +	  else
> +	    {
> +	      outbase = xstrdup (obase);
> +	      free (tofree);
> +	    }
> +	  obase = tofree = NULL;
> +	}
> +      else
> +	{
> +	  if (dumpdir)
> +	    {
> +	      char *p = concat (dumpdir, obase, "-", NULL);
> +	      free (dumpdir);
> +	      dumpdir = p;
> +	    }
> +	  else
> +	    dumpdir = concat (obase, "-", NULL);
> +
> +	  dumpdir_trailing_dash_added = true;
> +
> +	  free (tofree);
> +	  obase = tofree = NULL;
> +	}
> +
> +      if (!explicit_dumpdir || dumpbase)
> +	{
> +	  /* Absent -dumpbase and present -dumpbase-ext have been applied
> +	     to the linker output name, so compute fresh defaults for each
> +	     compilation.  */
> +	  free (dumpbase_ext);
> +	  dumpbase_ext = NULL;
> +	}
> +    }
> +
> +  /* Now, if we're compiling, or if we haven't used the dumpbase
> +     above, then outbase (%B) is derived from dumpbase, if given, or
> +     from the output name, given or implied.  We can't precompute
> +     implied output names, but that's ok, since they're derived from
> +     input names.  Just make sure we skip this if dumpbase is the
> +     empty string: we want to use input names then, so don't set
> +     outbase.  */
> +  if ((dumpbase || have_c)
> +      && !(dumpbase && !*dumpbase))
> +    {
> +      gcc_assert (!outbase);
> +
> +      if (dumpbase)
> +	{
> +	  gcc_assert (single_input_file_index () != -2);
> +	  /* We do not want lbasename here; dumpbase with dirnames
> +	     overrides dumpdir entirely, even if dumpdir is
> +	     specified.  */
> +	  if (dumpbase_ext)
> +	    /* We've already checked above that the suffix matches.  */
> +	    outbase = xstrndup (dumpbase,
> +				strlen (dumpbase) - strlen (dumpbase_ext));
> +	  else
> +	    outbase = xstrdup (dumpbase);
> +	}
> +      else if (output_file && !not_actual_file_p (output_file))
> +	{
> +	  outbase = xstrdup (lbasename (output_file));
> +	  char *p = strrchr (outbase + 1, '.');
> +	  if (p)
> +	    *p = '\0';
> +	}
> +
> +      if (outbase)
> +	outbase_length = strlen (outbase);
>      }
> -  else if (save_temps_prefix != NULL)
> +
> +  /* If there is any pathname component in an explicit -dumpbase, do
> +     not use dumpdir, but retain it to pass it on to the compiler.  */
> +  if (dumpdir)
> +    dumpdir_length = strlen (dumpdir);
> +  else
> +    dumpdir_length = 0;
> +
> +  /* Check that dumpbase_ext, if still present, still matches the end
> +     of dumpbase, if present, and drop it otherwise.  We only retained
> +     it above when dumpbase was absent to maybe use it to drop the
> +     extension from output_name before combining it with dumpdir.  */
> +  if (dumpbase_ext)
>      {
> -      free (save_temps_prefix);
> -      save_temps_prefix = NULL;
> +      if (!dumpbase)
> +	{
> +	  free (dumpbase_ext);
> +	  dumpbase_ext = NULL;
> +	}
> +      else
> +	gcc_assert (strcmp (dumpbase + strlen (dumpbase)
> +			    - strlen (dumpbase_ext), dumpbase_ext) == 0);
>      }
>  
>    if (save_temps_flag && use_pipes)
> @@ -4848,6 +5282,28 @@ set_collect_gcc_options (void)
>  	  obstack_grow (&collect_obstack, "'", 1);
>  	}
>      }
> +
> +  if (dumpdir)
> +    {
> +      if (!first_time)
> +	obstack_grow (&collect_obstack, " ", 1);
> +      first_time = FALSE;
> +
> +      obstack_grow (&collect_obstack, "'-dumpdir' '", 12);
> +      const char *p, *q;
> +
> +      q = dumpdir;
> +      while ((p = strchr (q, '\'')))
> +	{
> +	  obstack_grow (&collect_obstack, q, p - q);
> +	  obstack_grow (&collect_obstack, "'\\''", 4);
> +	  q = ++p;
> +	}
> +      obstack_grow (&collect_obstack, q, strlen (q));
> +
> +      obstack_grow (&collect_obstack, "'", 1);
> +    }
> +
>    obstack_grow (&collect_obstack, "\0", 1);
>    xputenv (XOBFINISH (&collect_obstack, char *));
>  }
> @@ -5366,22 +5822,33 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>  	    fatal_error (input_location, "spec %qs invalid", spec);
>  
>  	  case 'b':
> -	    if (save_temps_length)
> -	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
> -	    else
> +	    /* Don't use %b in the linker command.  */
> +	    gcc_assert (suffixed_basename_length);
> +	    if (!this_is_output_file && dumpdir_length)
> +	      obstack_grow (&obstack, dumpdir, dumpdir_length);
> +	    if (this_is_output_file || !outbase_length)
>  	      obstack_grow (&obstack, input_basename, basename_length);
> +	    else
> +	      obstack_grow (&obstack, outbase, outbase_length);
>  	    if (compare_debug < 0)
>  	      obstack_grow (&obstack, ".gk", 3);
>  	    arg_going = 1;
>  	    break;
>  
>  	  case 'B':
> -	    if (save_temps_length)
> -	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
> +	    /* Don't use %B in the linker command.  */
> +	    gcc_assert (suffixed_basename_length);
> +	    if (!this_is_output_file && dumpdir_length)
> +	      obstack_grow (&obstack, dumpdir, dumpdir_length);
> +	    if (this_is_output_file || !outbase_length)
> +	      obstack_grow (&obstack, input_basename, basename_length);
>  	    else
> -	      obstack_grow (&obstack, input_basename, suffixed_basename_length);
> +	      obstack_grow (&obstack, outbase, outbase_length);
>  	    if (compare_debug < 0)
>  	      obstack_grow (&obstack, ".gk", 3);
> +	    obstack_grow (&obstack, input_basename + basename_length,
> +			  suffixed_basename_length - basename_length);
> +
>  	    arg_going = 1;
>  	    break;
>  
> @@ -5534,42 +6001,44 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>  		    suffix_length += 3;
>  		  }
>  
> -		/* If -save-temps=obj and -o were specified, use that for the
> +		/* If -save-temps was specified, use that for the
>  		   temp file.  */
> -		if (save_temps_length)
> -		  {
> -		    char *tmp;
> -		    temp_filename_length
> -		      = save_temps_length + suffix_length + 1;
> -		    tmp = (char *) alloca (temp_filename_length);
> -		    memcpy (tmp, save_temps_prefix, save_temps_length);
> -		    memcpy (tmp + save_temps_length, suffix, suffix_length);
> -		    tmp[save_temps_length + suffix_length] = '\0';
> -		    temp_filename = save_string (tmp, save_temps_length
> -						      + suffix_length);
> -		    obstack_grow (&obstack, temp_filename,
> -				  temp_filename_length);
> -		    arg_going = 1;
> -		    delete_this_arg = 0;
> -		    break;
> -		  }
> -
> -		/* If the gcc_input_filename has the same suffix specified
> -		   for the %g, %u, or %U, and -save-temps is specified,
> -		   we could end up using that file as an intermediate
> -		   thus clobbering the user's source file (.e.g.,
> -		   gcc -save-temps foo.s would clobber foo.s with the
> -		   output of cpp0).  So check for this condition and
> -		   generate a temp file as the intermediate.  */
> -
>  		if (save_temps_flag)
>  		  {
>  		    char *tmp;
> -		    temp_filename_length = basename_length + suffix_length + 1;
> +		    bool adjusted_suffix = false;
> +		    if (suffix_length
> +			&& !outbase_length && !basename_length
> +			&& !dumpdir_trailing_dash_added)
> +		      {
> +			adjusted_suffix = true;
> +			suffix++;
> +			suffix_length--;
> +		      }
> +		    temp_filename_length
> +		      = dumpdir_length + suffix_length + 1;
> +		    if (!outbase_length)
> +		      temp_filename_length += basename_length;
> +		    else
> +		      temp_filename_length += outbase_length;
>  		    tmp = (char *) alloca (temp_filename_length);
> -		    memcpy (tmp, input_basename, basename_length);
> -		    memcpy (tmp + basename_length, suffix, suffix_length);
> -		    tmp[basename_length + suffix_length] = '\0';
> +		    if (dumpdir_length)
> +		      memcpy (tmp, dumpdir, dumpdir_length);
> +		    if (!outbase_length)
> +		      memcpy (tmp + dumpdir_length, input_basename,
> +			      basename_length);
> +		    else
> +		      memcpy (tmp + dumpdir_length, outbase,
> +			      outbase_length);
> +		    memcpy (tmp + temp_filename_length - suffix_length - 1,
> +			    suffix, suffix_length);
> +		    if (adjusted_suffix)
> +		      {
> +			adjusted_suffix = false;
> +			suffix--;
> +			suffix_length++;
> +		      }
> +		    tmp[temp_filename_length - 1] = '\0';
>  		    temp_filename = tmp;
>  
>  		    if (filename_cmp (temp_filename, gcc_input_filename) != 0)
> @@ -6080,6 +6549,14 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>  	    }
>  	    break;
>  
> +	  case '"':
> +	    /* End a previous argument, if there is one, then issue an
> +	       empty argument.  */
> +	    end_going_arg ();
> +	    arg_going = 1;
> +	    end_going_arg ();
> +	    break;
> +
>  	  default:
>  	    error ("spec failure: unrecognized spec option %qc", c);
>  	    break;
> @@ -6090,6 +6567,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>  	/* Backslash: treat next character as ordinary.  */
>  	c = *p++;
>  
> +	/* When adding more cases that previously matched default, make
> +	   sure to adjust quote_spec_char_p as well.  */
> +
>  	/* Fall through.  */
>        default:
>  	/* Ordinary character: put it into the current argument.  */
> @@ -8296,6 +8776,40 @@ driver::maybe_run_linker (const char *argv0) const
>      if (explicit_link_files[i] || outfiles[i] != NULL)
>        num_linker_inputs++;
>  
> +  /* Arrange for temporary file names created during linking to take
> +     on names related with the linker output rather than with the
> +     inputs when appropriate.  */
> +  if (outbase && *outbase)
> +    {
> +      if (dumpdir)
> +	{
> +	  char *tofree = dumpdir;
> +	  gcc_checking_assert (strlen (dumpdir) == dumpdir_length);
> +	  dumpdir = concat (dumpdir, outbase, ".", NULL);
> +	  free (tofree);
> +	}
> +      else
> +	dumpdir = concat (outbase, ".", NULL);
> +      dumpdir_length += strlen (outbase) + 1;
> +      dumpdir_trailing_dash_added = true;
> +    }
> +  else if (dumpdir_trailing_dash_added)
> +    {
> +      gcc_assert (dumpdir[dumpdir_length - 1] == '-');
> +      dumpdir[dumpdir_length - 1] = '.';
> +    }
> +
> +  if (dumpdir_trailing_dash_added)
> +    {
> +      gcc_assert (dumpdir_length > 0);
> +      gcc_assert (dumpdir[dumpdir_length - 1] == '.');
> +      dumpdir_length--;
> +    }
> +
> +  free (outbase);
> +  input_basename = outbase = NULL;
> +  outbase_length = suffixed_basename_length = basename_length = 0;
> +
>    /* Run ld to link all the compiler output files.  */
>  
>    if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
> @@ -9766,7 +10280,7 @@ compare_debug_dump_opt_spec_function (int arg,
>    do_spec_1 (" ", 0, NULL);
>  
>    if (argbuf.length () > 0
> -      && strcmp (argv[argbuf.length () - 1], "."))
> +      && strcmp (argv[argbuf.length () - 1], ".") != 0)
>      {
>        if (!compare_debug)
>  	return NULL;
> @@ -9776,25 +10290,22 @@ compare_debug_dump_opt_spec_function (int arg,
>      }
>    else
>      {
> -      const char *ext = NULL;
> -
>        if (argbuf.length () > 0)
> -	{
> -	  do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}", NULL);
> -	  ext = ".gkd";
> -	}
> +	do_spec_2 ("%B.gkd", NULL);
>        else if (!compare_debug)
>  	return NULL;
>        else
> -	do_spec_2 ("%g.gkd", NULL);
> +	do_spec_2 ("%{!save-temps*:%g.gkd}%{save-temps*:%B.gkd}", NULL);
>  
>        do_spec_1 (" ", 0, NULL);
>  
>        gcc_assert (argbuf.length () > 0);
>  
> -      name = concat (argbuf.last (), ext, NULL);
> +      name = xstrdup (argbuf.last ());
>  
> -      ret = concat ("-fdump-final-insns=", name, NULL);
> +      char *arg = quote_spec (xstrdup (name));
> +      ret = concat ("-fdump-final-insns=", arg, NULL);
> +      free (arg);
>      }
>  
>    which = compare_debug < 0;
> @@ -9821,8 +10332,6 @@ compare_debug_dump_opt_spec_function (int arg,
>    return ret;
>  }
>  
> -static const char *debug_auxbase_opt;
> -
>  /* %:compare-debug-self-opt spec function.  Expands to the options
>      that are to be passed in the second compilation of
>      compare-debug.  */
> @@ -9838,16 +10347,6 @@ compare_debug_self_opt_spec_function (int arg,
>    if (compare_debug >= 0)
>      return NULL;
>  
> -  do_spec_2 ("%{c|S:%{o*:%*}}", NULL);
> -  do_spec_1 (" ", 0, NULL);
> -
> -  if (argbuf.length () > 0)
> -    debug_auxbase_opt = concat ("-auxbase-strip ",
> -				argbuf.last (),
> -				NULL);
> -  else
> -    debug_auxbase_opt = NULL;
> -
>    return concat ("\
>  %<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
>  %<fdump-final-insns=* -w -S -o %j \
> @@ -9855,50 +10354,6 @@ compare_debug_self_opt_spec_function (int arg,
>  ", compare_debug_opt, NULL);
>  }
>  
> -/* %:compare-debug-auxbase-opt spec function.  Expands to the auxbase
> -    options that are to be passed in the second compilation of
> -    compare-debug.  It expects, as an argument, the basename of the
> -    current input file name, with the .gk suffix appended to it.  */
> -
> -static const char *
> -compare_debug_auxbase_opt_spec_function (int arg,
> -					 const char **argv)
> -{
> -  char *name;
> -  int len;
> -
> -  if (arg == 0)
> -    fatal_error (input_location,
> -		 "too few arguments to %%:compare-debug-auxbase-opt");
> -
> -  if (arg != 1)
> -    fatal_error (input_location,
> -		 "too many arguments to %%:compare-debug-auxbase-opt");
> -
> -  if (compare_debug >= 0)
> -    return NULL;
> -
> -  len = strlen (argv[0]);
> -  if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
> -    fatal_error (input_location, "argument to %%:compare-debug-auxbase-opt "
> -		 "does not end in %<.gk%>");
> -
> -  if (debug_auxbase_opt)
> -    return debug_auxbase_opt;
> -
> -#define OPT "-auxbase "
> -
> -  len -= 3;
> -  name = (char*) xmalloc (sizeof (OPT) + len);
> -  memcpy (name, OPT, sizeof (OPT) - 1);
> -  memcpy (name + sizeof (OPT) - 1, argv[0], len);
> -  name[sizeof (OPT) - 1 + len] = '\0';
> -
> -#undef OPT
> -
> -  return name;
> -}
> -
>  /* %:pass-through-libs spec function.  Finds all -l options and input
>     file names in the lib spec passed to it, and makes a list of them
>     prepended with the plugin option to cause them to be passed through
> @@ -9942,34 +10397,105 @@ pass_through_libs_spec_func (int argc, const char **argv)
>    return prepended;
>  }
>  
> -/* %:replace-extension spec function.  Replaces the extension of the
> -   first argument with the second argument.  */
> +static bool
> +not_actual_file_p (const char *name)
> +{
> +  return (strcmp (name, "-") == 0
> +	  || strcmp (output_file, HOST_BIT_BUCKET) == 0);
> +}
>  
> +/* %:dumps spec function.  Take an optional argument that overrides
> +   the default extension for -dumpbase and -dumpbase-ext.
> +   Return -dumpdir, -dumpbase and -dumpbase-ext, if needed.  */
>  const char *
> -replace_extension_spec_func (int argc, const char **argv)
> +dumps_spec_func (int argc, const char **argv ATTRIBUTE_UNUSED)
>  {
> -  char *name;
> +  const char *ext = dumpbase_ext;
>    char *p;
> -  char *result;
> -  int i;
>  
> -  if (argc != 2)
> -    fatal_error (input_location, "too few arguments to %%:replace-extension");
> +  char *args[3] = { NULL, NULL, NULL };
> +  int nargs = 0;
>  
> -  name = xstrdup (argv[0]);
> +  /* Do not compute a default for -dumpbase-ext when -dumpbase was
> +     given explicitly.  */
> +  if (dumpbase && *dumpbase && !ext)
> +    ext = "";
>  
> -  for (i = strlen (name) - 1; i >= 0; i--)
> -    if (IS_DIR_SEPARATOR (name[i]))
> -      break;
> +  if (argc == 1)
> +    {
> +      /* Do not override the explicitly-specified -dumpbase-ext with
> +	 the specs-provided overrider.  */
> +      if (!ext)
> +	ext = argv[0];
> +    }
> +  else if (argc != 0)
> +    fatal_error (input_location, "too many arguments for %%:dumps");
>  
> -  p = strrchr (name + i + 1, '.');
> -  if (p != NULL)
> -      *p = '\0';
> +  if (dumpdir)
> +    {
> +      p = quote_spec_arg (xstrdup (dumpdir));
> +      args[nargs++] = concat (" -dumpdir ", p, NULL);
> +      free (p);
> +    }
>  
> -  result = concat (name, argv[1], NULL);
> +  if (!ext)
> +    ext = input_basename + basename_length;
>  
> -  free (name);
> -  return result;
> +  /* Use the precomputed outbase, or compute dumpbase from
> +     input_basename, just like %b would.  */
> +  char *base;
> +
> +  if (dumpbase && *dumpbase)
> +    {
> +      base = xstrdup (dumpbase);
> +      p = base + outbase_length;
> +      gcc_checking_assert (strncmp (base, outbase, outbase_length) == 0);
> +      gcc_checking_assert (strcmp (p, ext) == 0);
> +    }
> +  else if (outbase_length)
> +    {
> +      base = xstrndup (outbase, outbase_length);
> +      p = NULL;
> +    }
> +  else
> +    {
> +      base = xstrndup (input_basename, suffixed_basename_length);
> +      p = base + basename_length;
> +    }
> +
> +  if (compare_debug < 0 || !p || strcmp (p, ext) != 0)
> +    {
> +      if (p)
> +	*p = '\0';
> +
> +      const char *gk;
> +      if (compare_debug < 0)
> +	gk = ".gk";
> +      else
> +	gk = "";
> +
> +      p = concat (base, gk, ext, NULL);
> +
> +      free (base);
> +      base = p;
> +    }
> +
> +  base = quote_spec_arg (base);
> +  args[nargs++] = concat (" -dumpbase ", base, NULL);
> +  free (base);
> +
> +  if (*ext)
> +    {
> +      p = quote_spec_arg (xstrdup (ext));
> +      args[nargs++] = concat (" -dumpbase-ext ", p, NULL);
> +      free (p);
> +    }
> +
> +  const char *ret = concat (args[0], args[1], args[2], NULL);
> +  while (nargs > 0)
> +    free (args[--nargs]);
> +
> +  return ret;
>  }
>  
>  /* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
> @@ -10075,6 +10601,44 @@ find_fortran_preinclude_file (int argc, const char **argv)
>    return result;
>  }
>  
> +/* If any character in ORIG fits QUOTE_P (_, P), reallocate the string
> +   so as to precede every one of them with a backslash.  Return the
> +   original string or the reallocated one.  */
> +
> +static inline char *
> +quote_string (char *orig, bool (*quote_p)(char, void *), void *p)
> +{
> +  int len, number_of_space = 0;
> +
> +  for (len = 0; orig[len]; len++)
> +    if (quote_p (orig[len], p))
> +      number_of_space++;
> +
> +  if (number_of_space)
> +    {
> +      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
> +      int j, k;
> +      for (j = 0, k = 0; j <= len; j++, k++)
> +	{
> +	  if (quote_p (orig[j], p))
> +	    new_spec[k++] = '\\';
> +	  new_spec[k] = orig[j];
> +	}
> +      free (orig);
> +      return new_spec;
> +    }
> +  else
> +    return orig;
> +}
> +
> +/* Return true iff C is any of the characters convert_white_space
> +   should quote.  */
> +
> +static inline bool
> +whitespace_to_convert_p (char c, void *)
> +{
> +  return (c == ' ' || c == '\t');
> +}
>  
>  /* Insert backslash before spaces in ORIG (usually a file path), to 
>     avoid being broken by spec parser.
> @@ -10102,26 +10666,50 @@ find_fortran_preinclude_file (int argc, const char **argv)
>  static char *
>  convert_white_space (char *orig)
>  {
> -  int len, number_of_space = 0;
> +  return quote_string (orig, whitespace_to_convert_p, NULL);
> +}
>  
> -  for (len = 0; orig[len]; len++)
> -    if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
> +/* Return true iff C matches any of the spec active characters.  */
> +static inline bool
> +quote_spec_char_p (char c, void *)
> +{
> +  switch (c)
> +    {
> +    case ' ':
> +    case '\t':
> +    case '\n':
> +    case '|':
> +    case '%':
> +    case '\\':
> +      return true;
>  
> -  if (number_of_space)
> +    default:
> +      return false;
> +    }
> +}
> +
> +/* Like convert_white_space, but deactivate all active spec chars by
> +   quoting them.  */
> +
> +static inline char *
> +quote_spec (char *orig)
> +{
> +  return quote_string (orig, quote_spec_char_p, NULL);
> +}
> +
> +/* Like quote_spec, but also turn an empty string into the spec for an
> +   empty argument.  */
> +
> +static inline char *
> +quote_spec_arg (char *orig)
> +{
> +  if (!*orig)
>      {
> -      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
> -      int j, k;
> -      for (j = 0, k = 0; j <= len; j++, k++)
> -	{
> -	  if (orig[j] == ' ' || orig[j] == '\t')
> -	    new_spec[k++] = '\\';
> -	  new_spec[k] = orig[j];
> -	}
>        free (orig);
> -      return new_spec;
> -  }
> -  else
> -    return orig;
> +      return xstrdup ("%\"");
> +    }
> +
> +  return quote_spec (orig);
>  }
>  
>  /* Restore all state within gcc.c to the initial state, so that the driver
> @@ -10158,8 +10746,14 @@ driver::finalize ()
>    target_sysroot_suffix = 0;
>    target_sysroot_hdrs_suffix = 0;
>    save_temps_flag = SAVE_TEMPS_NONE;
> -  save_temps_prefix = 0;
> -  save_temps_length = 0;
> +  save_temps_overrides_dumpdir = false;
> +  dumpdir_trailing_dash_added = false;
> +  free (dumpdir);
> +  free (dumpbase);
> +  free (dumpbase_ext);
> +  free (outbase);
> +  dumpdir = dumpbase = dumpbase_ext = outbase = NULL;
> +  dumpdir_length = outbase_length = 0;
>    spec_machine = DEFAULT_TARGET_MACHINE;
>    greatest_status = 1;
>  
> @@ -10298,8 +10892,6 @@ driver::finalize ()
>    mdswitches = NULL;
>    n_mdswitches = 0;
>  
> -  debug_auxbase_opt = NULL;
> -
>    used_arg.finalize ();
>  }
>  
> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> index e34b697..d565b08 100644
> --- a/gcc/lto-wrapper.c
> +++ b/gcc/lto-wrapper.c
> @@ -53,6 +53,13 @@ along with GCC; see the file COPYING3.  If not see
>     driver to lto-wrapper.  */
>  #define OFFLOAD_TARGET_NAMES_ENV	"OFFLOAD_TARGET_NAMES"
>  
> +/* By default there is no special suffix for target executables.  */
> +#ifdef TARGET_EXECUTABLE_SUFFIX
> +#define HAVE_TARGET_EXECUTABLE_SUFFIX
> +#else
> +#define TARGET_EXECUTABLE_SUFFIX ""
> +#endif
> +
>  enum lto_mode_d {
>    LTO_MODE_NONE,			/* Not doing LTO.  */
>    LTO_MODE_LTO,				/* Normal LTO.  */
> @@ -126,7 +133,7 @@ maybe_unlink (const char *file)
>  }
>  
>  /* Template of LTRANS dumpbase suffix.  */
> -#define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
> +#define DUMPBASE_SUFFIX "ltrans18446744073709551615"
>  
>  /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
>     environment.  */
> @@ -1100,12 +1107,7 @@ debug_objcopy (const char *infile, bool rename)
>      }
>  
>    if (save_temps)
> -    {
> -      outfile = (char *) xmalloc (strlen (orig_infile)
> -				  + sizeof (".debug.temp.o") + 1);
> -      strcpy (outfile, orig_infile);
> -      strcat (outfile, ".debug.temp.o");
> -    }
> +    outfile = concat (orig_infile, ".debug.temp.o", NULL);
>    else
>      outfile = make_temp_file (".debug.temp.o");
>    errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err, rename);
> @@ -1296,6 +1298,8 @@ run_gcc (unsigned argc, char *argv[])
>    bool linker_output_rel = false;
>    bool skip_debug = false;
>    unsigned n_debugobj;
> +  const char *dumppfx = NULL, *incoming_dumppfx = NULL;
> +  static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
>  
>    /* Get the driver and options.  */
>    collect_gcc = getenv ("COLLECT_GCC");
> @@ -1407,6 +1411,10 @@ run_gcc (unsigned argc, char *argv[])
>  	  linker_output = option->arg;
>  	  break;
>  
> +	  /* We don't have to distinguish between -save-temps=* and
> +	     -save-temps, -dumpdir already carries that
> +	     information.  */
> +	case OPT_save_temps_:
>  	case OPT_save_temps:
>  	  save_temps = 1;
>  	  break;
> @@ -1452,6 +1460,10 @@ run_gcc (unsigned argc, char *argv[])
>  	  skip_debug = option->arg && !strcmp (option->arg, "0");
>  	  break;
>  
> +	case OPT_dumpdir:
> +	  incoming_dumppfx = dumppfx = option->arg;
> +	  break;
> +
>  	default:
>  	  break;
>  	}
> @@ -1490,32 +1502,47 @@ run_gcc (unsigned argc, char *argv[])
>  	}
>      }
>  
> -  if (linker_output)
> +  if (!dumppfx)
>      {
> -      char *output_dir, *base, *name;
> -      bool bit_bucket = strcmp (linker_output, HOST_BIT_BUCKET) == 0;
> -
> -      output_dir = xstrdup (linker_output);
> -      base = output_dir;
> -      for (name = base; *name; name++)
> -	if (IS_DIR_SEPARATOR (*name))
> -	  base = name + 1;
> -      *base = '\0';
> -
> -      linker_output = &linker_output[base - output_dir];
> -      if (*output_dir == '\0')
> -	{
> -	  static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
> -	  output_dir = current_dir;
> -	}
> -      if (!bit_bucket)
> +      if (!linker_output
> +	  || strcmp (linker_output, HOST_BIT_BUCKET) == 0)
> +	dumppfx = "a.";
> +      else
>  	{
> -	  obstack_ptr_grow (&argv_obstack, "-dumpdir");
> -	  obstack_ptr_grow (&argv_obstack, output_dir);
> +	  const char *obase = lbasename (linker_output), *temp;
> +
> +	  /* Strip the executable extension.  */
> +	  size_t blen = strlen (obase), xlen;
> +	  if ((temp = strrchr (obase + 1, '.'))
> +	      && (xlen = strlen (temp))
> +	      && (strcmp (temp, ".exe") == 0
> +#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
> +		  || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
> +#endif
> +		  || strcmp (obase, "a.out") == 0))
> +	    dumppfx = xstrndup (linker_output,
> +				obase - linker_output + blen - xlen + 1);
> +	  else
> +	    dumppfx = concat (linker_output, ".", NULL);
>  	}
> +    }
>  
> -      obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  /* If there's no directory component in the dumppfx, add one, so
> +     that, when it is used as -dumpbase, it overrides any occurrence
> +     of -dumpdir that might have been passed in.  */
> +  if (!dumppfx || lbasename (dumppfx) == dumppfx)
> +    dumppfx = concat (current_dir, dumppfx, NULL);
> +
> +  /* Make sure some -dumpdir is passed, so as to get predictable
> +     -dumpbase overriding semantics.  If we got an incoming -dumpdir
> +     argument, we'll pass it on, so don't bother with another one
> +     then.  */
> +  if (!incoming_dumppfx)
> +    {
> +      obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +      obstack_ptr_grow (&argv_obstack, "");
>      }
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
>  
>    /* Remember at which point we can scrub args to re-use the commons.  */
>    new_head_argc = obstack_object_size (&argv_obstack) / sizeof (void *);
> @@ -1621,15 +1648,11 @@ cont1:
>  
>    if (lto_mode == LTO_MODE_LTO)
>      {
> -      if (linker_output)
> -	{
> -	  obstack_ptr_grow (&argv_obstack, linker_output);
> -	  flto_out = (char *) xmalloc (strlen (linker_output)
> -				       + sizeof (".lto.o") + 1);
> -	  strcpy (flto_out, linker_output);
> -	  strcat (flto_out, ".lto.o");
> -	}
> -      else
> +      /* -dumpbase argument for LTO.  */
> +      flto_out = concat (dumppfx, "lto.o", NULL);
> +      obstack_ptr_grow (&argv_obstack, flto_out);
> +
> +      if (!save_temps)
>  	flto_out = make_temp_file (".lto.o");
>        obstack_ptr_grow (&argv_obstack, "-o");
>        obstack_ptr_grow (&argv_obstack, flto_out);
> @@ -1637,47 +1660,17 @@ cont1:
>    else 
>      {
>        const char *list_option = "-fltrans-output-list=";
> -      size_t list_option_len = strlen (list_option);
> -      char *tmp;
>  
> -      if (linker_output)
> -	{
> -	  char *dumpbase = (char *) xmalloc (strlen (linker_output)
> -					     + sizeof (".wpa") + 1);
> -	  strcpy (dumpbase, linker_output);
> -	  strcat (dumpbase, ".wpa");
> -	  obstack_ptr_grow (&argv_obstack, dumpbase);
> -	}
> +      /* -dumpbase argument for WPA.  */
> +      char *dumpbase = concat (dumppfx, "wpa", NULL);
> +      obstack_ptr_grow (&argv_obstack, dumpbase);
>  
> -      if (linker_output && save_temps)
> -	{
> -	  ltrans_output_file = (char *) xmalloc (strlen (linker_output)
> -						 + sizeof (".ltrans.out") + 1);
> -	  strcpy (ltrans_output_file, linker_output);
> -	  strcat (ltrans_output_file, ".ltrans.out");
> -	}
> +      if (save_temps)
> +	ltrans_output_file = concat (dumppfx, "ltrans.out", NULL);
>        else
> -	{
> -	  char *prefix = NULL;
> -	  if (linker_output)
> -	    {
> -	      prefix = (char *) xmalloc (strlen (linker_output) + 2);
> -	      strcpy (prefix, linker_output);
> -	      strcat (prefix, ".");
> -	    }
> -
> -	  ltrans_output_file = make_temp_file_with_prefix (prefix,
> -							   ".ltrans.out");
> -	  free (prefix);
> -	}
> -      list_option_full = (char *) xmalloc (sizeof (char) *
> -		         (strlen (ltrans_output_file) + list_option_len + 1));
> -      tmp = list_option_full;
> -
> -      obstack_ptr_grow (&argv_obstack, tmp);
> -      strcpy (tmp, list_option);
> -      tmp += list_option_len;
> -      strcpy (tmp, ltrans_output_file);
> +	ltrans_output_file = make_temp_file (".ltrans.out");
> +      list_option_full = concat (list_option, ltrans_output_file, NULL);
> +      obstack_ptr_grow (&argv_obstack, list_option_full);
>  
>        if (jobserver)
>  	{
> @@ -1833,16 +1826,10 @@ cont:
>  	  output_name = XOBFINISH (&env_obstack, char *);
>  
>  	  /* Adjust the dumpbase if the linker output file was seen.  */
> -	  if (linker_output)
> -	    {
> -	      char *dumpbase
> -		  = (char *) xmalloc (strlen (linker_output)
> -				      + sizeof (DUMPBASE_SUFFIX) + 1);
> -	      snprintf (dumpbase,
> -			strlen (linker_output) + sizeof (DUMPBASE_SUFFIX),
> -			"%s.ltrans%u", linker_output, i);
> -	      argv_ptr[0] = dumpbase;
> -	    }
> +	  int dumpbase_len = (strlen (dumppfx) + sizeof (DUMPBASE_SUFFIX));
> +	  char *dumpbase = (char *) xmalloc (dumpbase_len + 1);
> +	  snprintf (dumpbase, dumpbase_len, "%sltrans%u.ltrans", dumppfx, i);
> +	  argv_ptr[0] = dumpbase;
>  
>  	  argv_ptr[1] = "-fltrans";
>  	  argv_ptr[2] = "-o";
> diff --git a/gcc/opts.c b/gcc/opts.c
> index ec3ca07..340d9943 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -845,30 +845,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>  	/* We have a DUMP_DIR_NAME, prepend that.  */
>  	opts->x_dump_base_name = opts_concat (opts->x_dump_dir_name,
>  					      opts->x_dump_base_name, NULL);
> -      else if (opts->x_aux_base_name
> -	       && strcmp (opts->x_aux_base_name, HOST_BIT_BUCKET) != 0)
> -	/* AUX_BASE_NAME is set and is not the bit bucket.  If it
> -	   contains a directory component, prepend those directories.
> -	   Typically this places things in the same directory as the
> -	   object file.  */
> -	{
> -	  const char *aux_base;
> -
> -	  base_of_path (opts->x_aux_base_name, &aux_base);
> -	  if (opts->x_aux_base_name != aux_base)
> -	    {
> -	      int dir_len = aux_base - opts->x_aux_base_name;
> -	      char *new_dump_base_name
> -		= XOBNEWVEC (&opts_obstack, char,
> -			     strlen (opts->x_dump_base_name) + dir_len + 1);
> -
> -	      /* Copy directory component from OPTS->X_AUX_BASE_NAME.  */
> -	      memcpy (new_dump_base_name, opts->x_aux_base_name, dir_len);
> -	      /* Append existing OPTS->X_DUMP_BASE_NAME.  */
> -	      strcpy (new_dump_base_name + dir_len, opts->x_dump_base_name);
> -	      opts->x_dump_base_name = new_dump_base_name;
> -	    }
> -	}
>  
>        /* It is definitely prefixed now.  */
>        opts->x_dump_base_name_prefixed = true;
> @@ -2346,17 +2322,6 @@ common_handle_option (struct gcc_options *opts,
>        opts->x_flag_gen_aux_info = 1;
>        break;
>  
> -    case OPT_auxbase_strip:
> -      {
> -	char *tmp = xstrdup (arg);
> -	strip_off_ending (tmp, strlen (tmp));
> -	if (tmp[0])
> -	  opts->x_aux_base_name = tmp;
> -	else
> -	  free (tmp);
> -      }
> -      break;
> -
>      case OPT_d:
>        decode_d_option (arg, opts, loc, dc);
>        break;
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs-0.c b/gcc/testsuite/gcc.misc-tests/outputs-0.c
> new file mode 100644
> index 00000000..ca2ac4a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.misc-tests/outputs-0.c
> @@ -0,0 +1 @@
> +int main () {}
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs-1.c b/gcc/testsuite/gcc.misc-tests/outputs-1.c
> new file mode 100644
> index 00000000..35f19cf
> --- /dev/null
> +++ b/gcc/testsuite/gcc.misc-tests/outputs-1.c
> @@ -0,0 +1,4 @@
> +extern void f();
> +int main() {
> +  f();
> +}
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs-2.c b/gcc/testsuite/gcc.misc-tests/outputs-2.c
> new file mode 100644
> index 00000000..109733d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.misc-tests/outputs-2.c
> @@ -0,0 +1,2 @@
> +void f() {
> +}
> diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp
> new file mode 100644
> index 00000000..9823710
> --- /dev/null
> +++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
> @@ -0,0 +1,695 @@
> +# Copyright (C) 2005-2020 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with GCC; see the file COPYING3.  If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +# This file contains a set of test that check that options intended to
> +# control the location and name of GCC outputs behave as expected.
> +
> +load_lib gcc-defs.exp
> +
> +set b "outputs"
> +
> +# These tests don't run runtest_file_p consistently if it
> +# doesn't return the same values, so disable parallelization
> +# of this *.exp file.  The first parallel runtest to reach
> +# this will run all the tests serially.
> +if {![gcc_parallel_test_run_p $b] || [is_remote host]} {
> +    return
> +}
> +gcc_parallel_test_enable 0
> +
> +set gsplit_dwarf "-gsplit-dwarf"
> +if ![check_no_compiler_messages gsplitdwarf object {
> +    void foo (void) { }
> +} "$gsplit_dwarf"] {
> +    set gsplit_dwarf ""
> +}
> +
> +# Prepare additional options to be used for linking.
> +# We do not compile to an executable, because that requires naming an output.
> +set link_options ""
> +set dest [target_info name]
> +foreach i { ldflags libs ldscripts } {
> +    if {[board_info $dest exists $i]} {
> +	set skip ""
> +	foreach opt [split [board_info $dest $i]] {
> +	    if { $skip != "" } then {
> +		set skip ""
> +	    } elseif { $opt == "-Xlinker" } then {
> +		set skip $opt
> +	    } elseif { ![string match "-*" $opt] && [file isfile $opt] } {
> +	    	set opt "-Wl,$opt"
> +	    }
> +	    append link_options " additional_flags=$opt"
> +	}
> +    }
> +}
> +if {[board_info $dest exists output_format]} {
> +    append link_options " additional_flags=-Wl,-oformat,[board_info $dest output_format]"
> +}
> +
> +# For the test named TEST, run the compiler with SOURCES and OPTS, and
> +# look in DIRS for OUTPUTS.  SOURCES is a list of suffixes for source
> +# files starting with $b in $srcdir/$subdir, OPTS is a string with
> +# options to be passed to the compiler, DIRS and OUTPUTS are lists.
> +# DIRS is a list of output directories, children before parent, and
> +# for each element of DIRS, there should be a corresponding sublist in
> +# OUTPUTS.  If OUTPUTS has an additional trailing sublist, that's the
> +# output list for the current directory.  Each element of the sublists
> +# in OUTPUT is a file name or glob pattern to be checked for; a name
> +# starting with a dash or a period is taken as a suffix for $b; with a
> +# double dash, or a dash followed by a period, the first dash is
> +# replaced with $b-$b; names starting with "a--" or "a-." have "$b"
> +# inserted after the first dash.  The glob pattern may expand to more
> +# than one file, but then the test will pass when there any number of
> +# matches.  So, it's safe to use for a.{out,exe}, but .{i,s,o} and
> +# .[iso] will pass even if only the .o is present.
> +proc outest { test sources opts dirs outputs } {
> +    global b
> +    global srcdir
> +    global subdir
> +    global gsplit_dwarf
> +    set src {}
> +    foreach s $sources {
> +	lappend src $srcdir/$subdir/$b$s
> +    }
> +    foreach f [glob -nocomplain -path $b -- *] {
> +	file delete $f
> +    }
> +    foreach d $dirs {
> +	file mkdir $d
> +	foreach f [glob -nocomplain -path $d -- *] {
> +	    file delete $d$f
> +	}
> +    }
> +    set options ""
> +    foreach opt [split $opts " "] {
> +	append options " additional_flags=$opt"
> +    }
> +    # Add linker flags if we're linking
> +    if {![string match "* -\[ESc\] *" " $opts "]} {
> +	global link_options
> +	append options "$link_options"
> +    }
> +    set gcc_output [gcc_target_compile $src "" none "$options"]
> +    set outs {}
> +    foreach d $dirs olist $outputs {
> +	foreach og $olist {
> +	    if { [string index $og 0] == "-" } then {
> +		if { [string index $og 1] == "-" \
> +		     || [string index $og 1] == "." } then {
> +		    set o "$b-$b[string range $og 1 end]"
> +		} else {
> +		    set o "$b$og"
> +		}
> +	    } elseif { [string index $og 0] == "." } then {
> +		set o "$b$og"
> +	    } elseif { [string range $og 0 2] == "a--" } then {
> +		set o "a-$b-[string range $og 3 end]"
> +	    } elseif { [string range $og 0 2] == "a-." } then {
> +		set o "a-$b.[string range $og 3 end]"
> +	    } else {
> +		set o "$og"
> +	    }
> +	    if { "$gsplit_dwarf" == "" \
> +		 && [string match "*.dwo" "$og"] } then {
> +		continue
> +	    }
> +	    if { [file exists $d$o] } then {
> +		pass "$test: $d$o"
> +		file delete $d$o
> +	    } else {
> +	        set ogl [glob -nocomplain -path $d -- $o]
> +		if { $ogl != {} } {
> +		    pass "$test: $d$o"
> +		    file delete $ogl
> +		} else {
> +		    fail "$test: $d$o"
> +		}
> +	    }
> +	}
> +	foreach ol [glob -nocomplain -path $d$b -- *] {
> +	    lappend outs $ol
> +	}
> +	foreach ol [glob -nocomplain -path $d -- a{-,.}*] {
> +	    lappend outs $ol
> +	}
> +    }
> +
> +    foreach f $outs {
> +	file delete $f
> +    }
> +    foreach d $dirs {
> +	file delete -force $d
> +    }
> +
> +    if { [llength $outs] == 0 } then {
> +	pass "$test: extra"
> +    } else {
> +	fail "$test: extra\n$outs"
> +    }
> +
> +    if { [string equal "$gcc_output" ""] } then {
> +	pass "$test: std out"
> +    } else {
> +	fail "$test: std out\n$gcc_output"
> +    }
> +
> +}
> +
> +set sing {-0.c}
> +set mult {-1.c -2.c}
> +
> +# Driver-chosen outputs.
> +outest "$b asm default 1" $sing "-S" {} {{-0.s}}
> +outest "$b asm default 2" $mult "-S" {} {{-1.s -2.s}}
> +
> +outest "$b obj default 1" $sing "-c" {} {{-0.o}}
> +outest "$b obj default 2" $mult "-c" {} {{-1.o -2.o}}
> +
> +outest "$b exe default 1" $sing "" {} {{a.{out,exe}}}
> +outest "$b exe default 2" $mult "" {} {{a.{out,exe}}}
> +
> +# Driver-chosen aux outputs.
> +outest "$b asm savetmp 1" $sing "-S -save-temps" {} {{-0.i -0.s}}
> +outest "$b asm savetmp 2" $mult "-S -save-temps" {} {{-1.i -1.s -2.i -2.s}}
> +outest "$b obj savetmp unnamed1" $sing "-c -save-temps" {} {{-0.i -0.s -0.o}}
> +outest "$b obj savetmp unnamed2" $mult "-c -save-temps" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
> +
> +# Aux outputs computed within the driver, based on output name (and
> +# input).
> +outest "$b cpp savetmp named0" $sing "-E -o $b-0.i -save-temps" {} {{-0.i}}
> +outest "$b asm savetmp named0" $sing "-S -o $b-0.s -save-temps" {} {{-0.i -0.s}}
> +outest "$b obj savetmp named0" $sing "-c -o $b-0.o -save-temps" {} {{-0.i -0.s -0.o}}
> +outest "$b cpp savetmp namedb" $sing "-E -o $b.i -save-temps" {} {{.i}}
> +outest "$b asm savetmp namedb" $sing "-S -o $b.s -save-temps" {} {{.i .s}}
> +outest "$b obj savetmp namedb" $sing "-c -o $b.o -save-temps" {} {{.i .s .o}}
> +
> +# When linking, the executable name gets prepended to aux output
> +# basenames, except when executable and single input share the same
> +# basename.
> +outest "$b exe savetmp unnamed1" $sing "-save-temps" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
> +outest "$b exe savetmp unnamed2" $mult "-save-temps" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
> +outest "$b exe savetmp named0" $sing "-o $b-0.exe -save-temps" {} {{-0.i -0.s -0.o -0.exe}}
> +outest "$b exe savetmp namedb" $sing "-o $b.exe -save-temps" {} {{--0.i --0.s --0.o .exe}}
> +outest "$b exe savetmp named2" $mult "-o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
> +
> +# Setting the main output to a dir selects it as the default aux&dump
> +# location.
> +outest "$b cpp savetmp namedir0" $sing "-E -o o/$b-0.i -save-temps" {o/} {{-0.i} {}}
> +outest "$b asm savetmp namedir0" $sing "-S -o o/$b-0.s -save-temps" {o/} {{-0.i -0.s} {}}
> +outest "$b obj savetmp namedir0" $sing "-c -o o/$b-0.o -save-temps" {o/} {{-0.i -0.s -0.o} {}}
> +outest "$b cpp savetmp namedir" $sing "-E -o o/$b.i -save-temps" {o/} {{.i} {}}
> +outest "$b asm savetmp namedir" $sing "-S -o o/$b.s -save-temps" {o/} {{.i .s} {}}
> +outest "$b obj savetmp namedir" $sing "-c -o o/$b.o -save-temps" {o/} {{.i .s .o} {}}
> +outest "$b exe savetmp namedir0" $sing "-o o/$b-0.exe -save-temps" {o/} {{-0.i -0.s -0.o -0.exe} {}}
> +outest "$b exe savetmp namedirb" $sing "-o o/$b.exe -save-temps" {o/} {{--0.i --0.s --0.o .exe} {}}
> +outest "$b exe savetmp namedir2" $mult "-o o/$b.exe -save-temps" {o/} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe} {}}
> +
> +# -save-temps=cwd overrides the aux output location to the current dir.
> +outest "$b obj savecwd unnamed1" $sing "-c -save-temps=cwd" {} {{-0.i -0.s -0.o}}
> +outest "$b obj savecwd unnamed2" $mult "-c -save-temps=cwd" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
> +outest "$b cpp savecwd named0" $sing "-E -o $b-0.i -save-temps=cwd" {} {{-0.i}}
> +outest "$b asm savecwd named0" $sing "-S -o $b-0.s -save-temps=cwd" {} {{-0.i -0.s}}
> +outest "$b obj savecwd named0" $sing "-c -o $b-0.o -save-temps=cwd" {} {{-0.i -0.s -0.o}}
> +outest "$b cpp savecwd namedb" $sing "-E -o $b.i -save-temps=cwd" {} {{.i}}
> +outest "$b asm savecwd namedb" $sing "-S -o $b.s -save-temps=cwd" {} {{.i .s}}
> +outest "$b obj savecwd namedb" $sing "-c -o $b.o -save-temps=cwd" {} {{.i .s .o}}
> +outest "$b exe savecwd unnamed1" $sing "-save-temps=cwd" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
> +outest "$b exe savecwd unnamed2" $mult "-save-temps=cwd" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
> +outest "$b exe savecwd named0" $sing "-o $b-0.exe -save-temps=cwd" {} {{-0.i -0.s -0.o -0.exe}}
> +outest "$b exe savecwd namedb" $sing "-o $b.exe -save-temps=cwd" {} {{--0.i --0.s --0.o .exe}}
> +outest "$b exe savecwd named2" $mult "-o $b.exe -save-temps=cwd" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
> +
> +outest "$b cpp savecwd namedir0" $sing "-E -o o/$b-0.i -save-temps=cwd" {o/} {{-0.i} {}}
> +outest "$b asm savecwd namedir0" $sing "-S -o o/$b-0.s -save-temps=cwd" {o/} {{-0.s} {-0.i}}
> +outest "$b obj savecwd namedir0" $sing "-c -o o/$b-0.o -save-temps=cwd" {o/} {{-0.o} {-0.i -0.s}}
> +outest "$b cpp savecwd namedir" $sing "-E -o o/$b.i -save-temps=cwd" {o/} {{.i} {}}
> +outest "$b asm savecwd namedir" $sing "-S -o o/$b.s -save-temps=cwd" {o/} {{.s} {.i}}
> +outest "$b obj savecwd namedir" $sing "-c -o o/$b.o -save-temps=cwd" {o/} {{.o} {.i .s}}
> +outest "$b exe savecwd namedir0" $sing "-o o/$b-0.exe -save-temps=cwd" {o/} {{-0.exe} {-0.i -0.s -0.o}}
> +outest "$b exe savecwd namedirb" $sing "-o o/$b.exe -save-temps=cwd" {o/} {{.exe} {--0.i --0.s --0.o}}
> +outest "$b exe savecwd namedir2" $mult "-o o/$b.exe -save-temps=cwd" {o/} {{.exe} {--1.i --1.s --1.o --2.i --2.s --2.o}}
> +
> +# -save-temps=obj overrides the aux output location to that of the
> +# main output
> +outest "$b obj saveobj unnamed1" $sing "-c -save-temps=obj" {} {{-0.i -0.s -0.o}}
> +outest "$b obj saveobj unnamed2" $mult "-c -save-temps=obj" {} {{-1.i -1.s -1.o -2.i -2.s -2.o}}
> +outest "$b cpp saveobj named0" $sing "-E -o $b-0.i -save-temps=obj" {} {{-0.i}}
> +outest "$b asm saveobj named0" $sing "-S -o $b-0.s -save-temps=obj" {} {{-0.i -0.s}}
> +outest "$b obj saveobj named0" $sing "-c -o $b-0.o -save-temps=obj" {} {{-0.i -0.s -0.o}}
> +outest "$b cpp saveobj namedb" $sing "-E -o $b.i -save-temps=obj" {} {{.i}}
> +outest "$b asm saveobj namedb" $sing "-S -o $b.s -save-temps=obj" {} {{.i .s}}
> +outest "$b obj saveobj namedb" $sing "-c -o $b.o -save-temps=obj" {} {{.i .s .o}}
> +outest "$b exe saveobj unnamed1" $sing "-save-temps=obj" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
> +outest "$b exe saveobj unnamed2" $mult "-save-temps=obj" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
> +outest "$b exe saveobj named0" $sing "-o $b-0.exe -save-temps=obj" {} {{-0.i -0.s -0.o -0.exe}}
> +outest "$b exe saveobj namedb" $sing "-o $b.exe -save-temps=obj" {} {{--0.i --0.s --0.o .exe}}
> +outest "$b exe saveobj named2" $mult "-o $b.exe -save-temps=obj" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
> +
> +outest "$b cpp saveobj namedir0" $sing "-E -o o/$b-0.i -save-temps=obj" {o/} {{-0.i} {}}
> +outest "$b asm saveobj namedir0" $sing "-S -o o/$b-0.s -save-temps=obj" {o/} {{-0.i -0.s} {}}
> +outest "$b obj saveobj namedir0" $sing "-c -o o/$b-0.o -save-temps=obj" {o/} {{-0.i -0.s -0.o} {}}
> +outest "$b cpp saveobj namedir" $sing "-E -o o/$b.i -save-temps=obj" {o/} {{.i} {}}
> +outest "$b asm saveobj namedir" $sing "-S -o o/$b.s -save-temps=obj" {o/} {{.i .s} {}}
> +outest "$b obj saveobj namedir" $sing "-c -o o/$b.o -save-temps=obj" {o/} {{.i .s .o} {}}
> +outest "$b exe saveobj namedir0" $sing "-o o/$b-0.exe -save-temps=obj" {o/} {{-0.i -0.s -0.o -0.exe} {}}
> +outest "$b exe saveobj namedirb" $sing "-o o/$b.exe -save-temps=obj" {o/} {{--0.i --0.s --0.o .exe} {}}
> +outest "$b exe saveobj namedir2" $mult "-o o/$b.exe -save-temps=obj" {o/} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe} {}}
> +
> +# Check -dumpdir overriding by -save-temps=*, and -save-temps
> +# non-overriding, with one catch: the presence of a given dumpdir,
> +# even if ultimately overridden, still disables the prepending of the
> +# executable basename to the aux&dump output basenames (or rather the
> +# appending of the executable basename to the dumpdir).
> +outest "$b exe sobjovr namedir0" $sing "-o o/$b-0.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-0.i -0.s -0.o -0.exe} {}}
> +outest "$b exe sobjovr namedirb" $sing "-o o/$b.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-0.i -0.s -0.o .exe} {}}
> +outest "$b exe sobjovr namedir2" $mult "-o o/$b.exe -dumpdir no/ -save-temps=obj -save-temps" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o .exe} {}}
> +outest "$b exe scwdovr namedir0" $sing "-o o/$b-0.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{-0.exe} {-0.i -0.s -0.o}}
> +outest "$b exe scwdovr namedirb" $sing "-o o/$b.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{.exe} {-0.i -0.s -0.o}}
> +outest "$b exe scwdovr namedir2" $mult "-o o/$b.exe -dumpdir o/ -save-temps=cwd -save-temps" {o/} {{.exe} {-1.i -1.s -1.o -2.i -2.s -2.o}}
> +outest "$b exe ddstovr namedir0" $sing "-o $b-0.exe -dumpdir o/ -save-temps" {o/} {{-0.i -0.s -0.o} {-0.exe}}
> +outest "$b exe ddstovr namedirb" $sing "-o $b.exe -dumpdir o/ -save-temps" {o/} {{-0.i -0.s -0.o} {.exe}}
> +outest "$b exe ddstovr namedir2" $mult "-o $b.exe -dumpdir o/ -save-temps" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o} {.exe}}
> +
> +# Check -dumpdir prevailing over -save-temps*.  Even though -dumpdir
> +# overrides the -save-temps=* directory selection, -save-temps remains
> +# enabled.
> +outest "$b exe soddovr namedir0" $sing "-o o/$b-0.exe -save-temps=obj -dumpdir ./" {o/} {{-0.exe} {-0.i -0.s -0.o}}
> +outest "$b exe soddovr namedirb" $sing "-o o/$b.exe -save-temps=obj -dumpdir ./" {o/} {{.exe} {-0.i -0.s -0.o}}
> +outest "$b exe soddovr namedir2" $mult "-o o/$b.exe -save-temps=obj -dumpdir ./" {o/} {{.exe} {-1.i -1.s -1.o -2.i -2.s -2.o}}
> +outest "$b exe scddovr namedir0" $sing "-o o/$b-0.exe -save-temps=cwd -dumpdir o/" {o/} {{-0.i -0.s -0.o -0.exe} {}}
> +outest "$b exe scddovr namedirb" $sing "-o o/$b.exe -save-temps=cwd -dumpdir o/" {o/} {{-0.i -0.s -0.o .exe} {}}
> +outest "$b exe scddovr namedir2" $mult "-o o/$b.exe -save-temps=cwd -dumpdir o/" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o .exe} {}}
> +outest "$b exe ddstovr namedir0" $sing "-o $b-0.exe -save-temps -dumpdir o/" {o/} {{-0.i -0.s -0.o} {-0.exe}}
> +outest "$b exe ddstovr namedirb" $sing "-o $b.exe -save-temps -dumpdir o/" {o/} {{-0.i -0.s -0.o} {.exe}}
> +outest "$b exe ddstovr namedir2" $mult "-o $b.exe -save-temps -dumpdir o/" {o/} {{-1.i -1.s -1.o -2.i -2.s -2.o} {.exe}}
> +
> +
> +# Compiler- and driver-generated aux and dump outputs.
> +# -fdump-rtl-final creates a .c.???r.final dump in the compiler.
> +# -fstack-usage creates a .su aux output in the compiler.
> +# $gsplit_dwarf extracts a .dwo aux output from the .o in the driver.
> +outest "$b asm auxdump 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.s}}
> +outest "$b asm auxdump 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-1.c.???r.final -1.su -1.s -2.c.???r.final -2.su -2.s}}
> +outest "$b obj auxdump unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +outest "$b obj auxdump unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-1.c.???r.final -1.su -1.dwo -1.o -2.c.???r.final -2.su -2.dwo -2.o}}
> +
> +outest "$b cpp auxdump named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.i}}
> +outest "$b asm auxdump named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.s}}
> +outest "$b obj auxdump named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.i}}
> +outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .s}}
> +outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .dwo .o}}
> +
> +outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
> +outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
> +outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
> +outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
> +outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
> +
> +outest "$b cpp auxdump namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.i} {}}
> +outest "$b asm auxdump namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.s} {}}
> +outest "$b obj auxdump namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.o} {}}
> +outest "$b cpp auxdump namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.i} {}}
> +outest "$b asm auxdump namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.c.???r.final .su .s} {}}
> +outest "$b obj auxdump namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{.c.???r.final .su .dwo .o} {}}
> +outest "$b exe auxdump namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{-0.c.???r.final -0.su -0.dwo -0.exe} {}}
> +outest "$b exe auxdump namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{--0.c.???r.final --0.su --0.dwo .exe} {}}
> +outest "$b exe auxdump namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
> +
> +# Check that -save-temps doesn't break compiler aux or dumps as it
> +# changes temp file names.
> +outest "$b asm auxdmps 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
> +outest "$b asm auxdmps 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -2.i -2.c.???r.final -2.su -2.s}}
> +outest "$b obj auxdmps unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
> +outest "$b obj auxdmps unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-1.i -1.c.???r.final -1.su -1.s -1.dwo -1.o -2.i -2.c.???r.final -2.su -2.s -2.dwo -2.o}}
> +
> +outest "$b cpp auxdmps named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i}}
> +outest "$b asm auxdmps named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s}}
> +outest "$b obj auxdmps named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o}}
> +outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i}}
> +outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
> +outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
> +
> +outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
> +outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
> +outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
> +outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
> +outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
> +
> +outest "$b cpp auxdmps namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i} {}}
> +outest "$b asm auxdmps namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s} {}}
> +outest "$b obj auxdmps namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o} {}}
> +outest "$b cpp auxdmps namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i} {}}
> +outest "$b asm auxdmps namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i .c.???r.final .su .s} {}}
> +outest "$b obj auxdmps namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{.i .c.???r.final .su .s .dwo .o} {}}
> +outest "$b exe auxdmps namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe} {}}
> +outest "$b exe auxdmps namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe} {}}
> +outest "$b exe auxdmps namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {o/} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe} {}}
> +
> +
> +# Check that dumpdir changes the location of non-primary outputs
> +outest "$b asm dumpdir 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
> +outest "$b asm dumpdir 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -2.c.???r.final -2.su} {-1.s -2.s}}
> +outest "$b obj dumpdir unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
> +outest "$b obj dumpdir unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dumpdir named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{} {-0.i}}
> +outest "$b asm dumpdir named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su} {-0.s}}
> +outest "$b obj dumpdir named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.o}}
> +outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{} {.i}}
> +outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
> +outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
> +
> +outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
> +outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
> +outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
> +outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
> +outest "$b exe dumpdira namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dumpdira named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +outest "$b exe dumpdirb namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
> +outest "$b exe dumpdirb named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +
> +outest "$b cpp dumpdir namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dumpdir namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su} {-0.s} {}}
> +outest "$b obj dumpdir namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.o} {}}
> +outest "$b cpp dumpdir namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{} {.i} {}}
> +outest "$b asm dumpdir namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su} {.s} {}}
> +outest "$b obj dumpdir namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{.c.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dumpdir namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe} {}}
> +outest "$b exe dumpdir namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-0.c.???r.final -0.su -0.dwo} {.exe} {}}
> +outest "$b exe dumpdir namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/ o/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe} {}}
> +outest "$b exe dumpdira namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
> +outest "$b exe dumpdira namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +outest "$b exe dumpdirb namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
> +outest "$b exe dumpdirb namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/$b-" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +
> +# Check that a -dumpbase with a dir component disregards the -dumpdir
> +# prefix.  Also, start testing -dumpbase-ext to distinguish between
> +# aux and dump files: only the latter retain the named extension.
> +# -dumpbase-ext, if absent or used in combination with -dumpbase for
> +# an executable name, defaults to the extension of the source file.
> +# The specified dumpbase is combined with the dumpdir prefix when
> +# processing more than one input (we couldn't use the same dumpbase
> +# for them all), or when linking (the specified dumpbase is then used
> +# as prefix instead of the linker output, and a new dumpbase is
> +# computed per source).
> +outest "$b asm dbsovrdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbsovrddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbsovrdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbsovrdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbsovrdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbsovrddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbsovrdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbsovrddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbsovrdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbsovrdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {-0.i}}
> +outest "$b asm dbsovrdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbsovrdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbsovrdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{} {.i}}
> +outest "$b asm dbsovrdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
> +
> +# Nit: -dumpdir affects whether the specified dumpbase is combined
> +# into dumpdir or taken as the output basename, even if dumpbase will
> +# ultimately override it.
> +outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
> +outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
> +outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
> +outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbsovrdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbsovrddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbsovrdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbsovrdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbsovrdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbsovrdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbsovrdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbsovrdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbsovrdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbsovrdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
> +outest "$b exe dbsovrdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
> +outest "$b exe dbsovrdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbsovrdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
> +outest "$b exe dbsovrdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +
> +
> +# Check that a -dumpbase without a dir component adds to the -dumpdir
> +# prefix.
> +outest "$b asm dbswthdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbswthddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbswthdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbswthdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbswthdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbswthddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbswthdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbswthddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbswthdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbswthdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {-0.i}}
> +outest "$b asm dbswthdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbswthdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbswthdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{} {.i}}
> +outest "$b asm dbswthdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {.o}}
> +
> +# Nitty details: -dumpdir affects whether the specified dumpbase is
> +# combined into dumpdir or taken as the output basename, even if
> +# dumpbase will ultimately override it.
> +outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
> +outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
> +outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
> +outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbswthdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbswthddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a.c -dumpbase-ext .c" {od/} {{a.c.???r.final a.su a.dwo} {.exe}}
> +outest "$b exe dbswthdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbswthdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbswthdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbswthdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbswthdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbswthdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbswthdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbswthdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{.???r.final .su .dwo} {-0.exe} {}}
> +outest "$b exe dbswthdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/ o/} {{.exe.???r.final .su .dwo} {.exe} {}}
> +outest "$b exe dbswthdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbswthdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a.???r.final a.su a.dwo} {.exe} {}}
> +outest "$b exe dbswthdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +
> +
> +# Check for the minor differences when -dumpbase is used without
> +# -dumpdir.  The main difference between dbwoutdd and dbswthdd tests
> +# is in the single-input link tests: with the dump dir/ prefix moved
> +# to dumpbase, and without -dumpdir we end up using -dumpbase as the
> +# executable prefix rather than as the dumpbase for the single input.
> +outest "$b asm dbwoutdd 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b asm dbwoutddx 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su} {-0.s}}
> +outest "$b asm dbwoutdd-x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c" {od/} {{.c.???r.final .c.su} {-0.s}}
> +outest "$b asm dbwoutdd.x 1" $sing "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.x" {od/} {{.x.???r.final .x.su} {-0.s}}
> +outest "$b asm dbwoutdd 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b asm dbwoutddx 2" $mult "-S -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.x -dumpbase-ext .x" {od/} {{--1.c.???r.final --1.su --2.c.???r.final --2.su} {-1.s -2.s}}
> +outest "$b obj dbwoutdd unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbwoutddx unnamed1" $sing "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.c -dumpbase-ext .c" {od/} {{.c.???r.final .su .dwo} {-0.o}}
> +outest "$b obj dbwoutdd unnamed2" $mult "-c -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +outest "$b cpp dbwoutdd named0" $sing "-E -o $b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{} {-0.i}}
> +outest "$b asm dbwoutdd named0" $sing "-S -o $b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {-0.s}}
> +outest "$b obj dbwoutdd named0" $sing "-c -o $b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.o}}
> +outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{} {.i}}
> +outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
> +outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
> +
> +outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
> +outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
> +outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
> +outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
> +outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
> +outest "$b exe dbwoutdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
> +outest "$b exe dbwoutdda namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dbwoutddac namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a.c -dumpbase-ext .c" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe}}
> +outest "$b exe dbwoutdda named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe}}
> +
> +outest "$b cpp dbwoutdd namedir0" $sing "-E -o o/$b-0.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{} {-0.i} {}}
> +outest "$b asm dbwoutdd namedir0" $sing "-S -o o/$b-0.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {-0.s} {}}
> +outest "$b obj dbwoutdd namedir0" $sing "-c -o o/$b-0.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {-0.o} {}}
> +outest "$b cpp dbwoutdd namedir" $sing "-E -o o/$b.i -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{} {.i} {}}
> +outest "$b asm dbwoutdd namedir" $sing "-S -o o/$b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su} {.s} {}}
> +outest "$b obj dbwoutdd namedir" $sing "-c -o o/$b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{.???r.final .su .dwo} {.o} {}}
> +outest "$b exe dbwoutdd namedir0" $sing "-o o/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe} {}}
> +outest "$b exe dbwoutdd namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/ o/} {{--0.c.???r.final --0.su --0.dwo} {.exe} {}}
> +outest "$b exe dbwoutdd namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/ o/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe} {}}
> +outest "$b exe dbwoutdda namedirb" $sing "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/ o/} {{a--0.c.???r.final a--0.su a--0.dwo} {.exe} {}}
> +outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/ o/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {.exe} {}}
> +
> +# -fcompare-debug
> +outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
> +outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
> +
> +# -flto
> +outest "$b lto sing unnamed" $sing "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto mult unnamed" $mult "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.c.???i.icf a--2.c.???i.icf  a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto sing named" $sing "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
> +outest "$b lto mult named" $mult "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
> +outest "$b lto sing nameddir" $sing "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
> +outest "$b lto mult nameddir" $mult "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
> +
> +# -dumpbase without -dumpdir.  The trailing dumppfx dash after it is
> +# combined with dumpbase turns into a period when passed to lto as
> +# -dumpdir, because the dash is introduced by the compiler driver.
> +outest "$b lto sing dumpbase unnamed" $sing "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto mult dumpbase unnamed" $mult "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto sing dumpbase named" $sing "-dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto mult dumpbase named" $mult "-dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto sing dumpbase namedb" $sing "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +outest "$b lto mult dumpbase namedb" $mult "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +
> +# -dumpdir without -dumpbase.  The trailing dash in -dumpdir is given
> +# by the user, thus not replaced with a dot.
> +outest "$b lto sing dumpdir unnamed" $sing "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto mult dumpdir unnamed" $mult "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto sing dumpdir namedb" $sing "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
> +outest "$b lto mult dumpdir namedb" $mult "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
> +
> +# -dumpdir and non-overriding -dumpbase.
> +outest "$b lto dbswthdd sing unnamed" $sing "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto dbswthdd mult unnamed" $mult "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto dbswthdd sing named" $sing "-dumpdir dir/ -dumpbase $b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto dbswthdd mult named" $mult "-dumpdir dir/ -dumpbase $b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto dbswthdd sing namedb" $sing "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +outest "$b lto dbswthdd mult namedb" $mult "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +
> +# -dumpdir and an overriding -dumpbase.
> +outest "$b lto dbsovrdd sing unnamed" $sing "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto dbsovrdd mult unnamed" $mult "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto dbsovrdd sing named" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto dbsovrdd mult named" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto dbsovrdd sing namedb" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +outest "$b lto dbsovrdd mult namedb" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
> +
> +# Check that -dumpbase '' gets source names as dumpbases for
> +# compilation, and output name as dumpbase for linking, regardless of
> +# how many source files.
> +outest "$b lto sing empty dumpbase unnamed" $sing "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto mult empty dumpbase unnamed" $mult "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto sing empty dumpbase named" $sing "-dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.exe} {}}
> +outest "$b lto mult empty dumpbase named" $mult "-dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.exe} {}}
> +outest "$b lto sing empty dumpbase namedb" $sing "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
> +outest "$b lto mult empty dumpbase namedb" $mult "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
> +
> +# Now with -dumpdir too.
> +outest "$b lto sing empty dumpbase dumpdir unnamed" $sing "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto mult empty dumpbase dumpdir unnamed" $mult "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
> +outest "$b lto sing empty dumpbase dumpdir named" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf --0.wpa.???i.icf --0.ltrans0.ltrans.???r.final --0.ltrans0.ltrans.su} {-0.exe}}
> +outest "$b lto mult empty dumpbase dumpdir named" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf --1.wpa.???i.icf --1.ltrans0.ltrans.???r.final --1.ltrans0.ltrans.su} {-1.exe}}
> +outest "$b lto sing empty dumpbase dumpdir namedb" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
> +outest "$b lto mult empty dumpbase dumpdir namedb" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
> +
> +# And also with an empty -dumpdir.  That's equivalent to -dumpdir ./,
> +# overriding any dumpdir implied by the output.
> +outest "$b lto sing empty dumpdir empty dumpbase unnamed" $sing "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto mult empty dumpdir empty dumpbase unnamed" $mult "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
> +outest "$b lto sing empty dumpdir empty dumpbase named" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.exe} {-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su}}
> +outest "$b lto mult empty dumpdir empty dumpbase named" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.exe} {-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su}}
> +outest "$b lto sing empty dumpdir empty dumpbase namedb" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
> +outest "$b lto mult empty dumpdir empty dumpbase namedb" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
> +
> +# Now -flto with -save-temps, not exhaustive.
> +outest "$b lto st sing empty dumpbase unnamed" $sing "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.i -0.s -0.o -0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
> +outest "$b lto st mult empty dumpbase unnamed" $mult "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
> +outest "$b lto st sing dumpdir empty dumpbase named" $sing "-dumpdir dir/ -dumpbase \"\" -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf -0.lto_wrapper_args -0.wpa.???i.icf -0.ltrans.out -0.res -0.ltrans0.o -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.ltrans0.ltrans.s -0.ltrans0.ltrans.o} {-0.exe}}
> +outest "$b lto st mult dumpdir empty dumpbase named" $mult "-dumpdir dir/ -dumpbase \"\" -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf -1.lto_wrapper_args -1.wpa.???i.icf -1.ltrans.out -1.res -1.ltrans0.o -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.ltrans0.ltrans.s -1.ltrans0.ltrans.o} {-1.exe}}
> +outest "$b lto st sing empty dumpbase namedb" $sing "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
> +outest "$b lto st mult empty dumpbase namedb" $mult "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
> +
> +# lto save-temps without -dumpbase.
> +outest "$b lto st sing unnamed" $sing "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.i a--0.s a--0.o a--0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
> +outest "$b lto st mult unnamed" $mult "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.i a--1.s a--1.o a--1.c.???i.icf a--2.i a--2.s a--2.o a--2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
> +outest "$b lto st sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-0.exe}}
> +outest "$b lto st mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-1.exe}}
> +outest "$b lto st sing namedb" $sing "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
> +outest "$b lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
> +
> +# Below are examples taken from the documentation.
> +# They are likely redundant with earlier test,
> +# but we want to make sure behavior matches the docs.
> +
> +# gcc -c foo.c ...
> +outest "$b doc single  -c !-o" $sing "-c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.o}}
> +
> +# gcc -c foo.c -o dir/foobar.o ...
> +outest "$b doc single  -c +-o" $sing "-c -o dir/$b.o -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo .o} {}}
> +
> +# gcc foo.c bar.c -o dir/foobar ...
> +outest "$b doc double !-c  -o" $mult "-o dir/$b.exe -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe} {}}
> +
> +# gcc foo.c -o dir/foo ...
> +outest "$b doc single !-c  -o" $sing "-o dir/$b-0 -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo -0} {}}
> +
> +# gcc -save-temps -S foo.c
> +outest "$b doc single  -S -st" $sing "-save-temps -S" {} {{-0.i -0.s}}
> +
> +# gcc -save-temps -dumpbase save-foo -c foo.c
> +outest "$b doc single  -c -st -db" $sing "-save-temps -dumpbase $b -c" {} {{.i .s -0.o}}
> +
> +# gcc foo.c -c -o dir/foo.o -dumpbase alt/foo \
> +#   -dumpdir pfx- -save-temps=cwd ...
> +outest "$b doc single  -c  -o -db" $sing "-c -o dir/$b.o -dumpbase alt/$b -dumpdir pfx- -save-temps=cwd -fdump-rtl-final -fstack-usage $gsplit_dwarf" {alt/ dir/} {{.i .s .???r.final .su .dwo} {.o} {}}
> +
> +# gcc foo.c bar.c -c -dumpbase main ...
> +outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo -1.o --2.c.???r.final --2.su --2.dwo -2.o}}
> +
> +# gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
> +outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
> +
> +# gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
> +outest "$b doc double !-c  -o -db'' -flto" $mult "-o dir/$b.exe -dumpbase \"\" -flto -O2 -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
> +
> +
> +# gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
> +outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
> +
> +# gcc foo.c bar.c -o main.out -dumpbase-ext .out ...
> +outest "$b doc double !-c  -o -dbx" $mult "-o $b.out -dumpbase-ext .out -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .out}}
> +
> +# gcc -dumpdir pfx- -c foo.c ...
> +outest "$b doc single  -c !-o -dd" $sing "-dumpdir $b- -c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo -0.o}}
> +
> +# gcc -dumpdir dir/ -c foo.c -o obj/bar.o ...
> +outest "$b doc single  -c  -o -dd" $sing "-dumpdir dir/ -c -o obj/$b.o -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/ obj/} {{.c.???r.final .su .dwo} {.o} {}}
> +
> +# gcc -dumpdir pfx- -c foo.c -save-temps=obj ...
> +outest "$b doc single  -c  -o -dd -st=" $sing "-dumpdir $b- -c -save-temps=obj -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.i -0.s -0.o}}
> +
> +# gcc foo.c bar.c -c -dumpdir dir/pfx- -dumpbase main ...
> +outest "$b doc double  -c !-o -dd -db" $mult "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {-1.o -2.o}}
> +
> +# gcc foo.c -c -dumpdir dir/pfx- -dumpbase main ...
> +outest "$b doc single  -c !-o -dd -db" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
> +
> +# gcc foo.c bar.c -dumpdir dir/pfx- -o main ...
> +outest "$b doc double !-c  -o -dd" $mult "-dumpdir dir/ -o $b.exe -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
> +
> +# gcc foo.c -dumpdir alt/pfx- -o dir/main.exe -save-temps=cwd ...
> +outest "$b doc single !-c  -o -dd -st=" $sing "-c -dumpdir dir/ -dumpbase $b -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.???r.final .su .dwo} {-0.o}}
> +
> +
> +gcc_parallel_test_enable 1
> diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
> index 180a9ab..fc7e8e2 100644
> --- a/gcc/testsuite/lib/gcc-defs.exp
> +++ b/gcc/testsuite/lib/gcc-defs.exp
> @@ -285,11 +285,53 @@ proc dg-additional-files { args } {
>      set additional_files [lindex $args 1]
>  }
>  
> +set gcc_adjusted_linker_flags 0
> +
> +# Add -Wl, before any file names in ldflags, libs, and ldscripts, so
> +# that default object files or libraries do not change the names of
> +# gcc auxiliary outputs.
> +
> +proc gcc_adjust_linker_flags {} {
> +    global gcc_adjusted_linker_flags
> +    if {$gcc_adjusted_linker_flags} {
> +	return
> +    }
> +    set gcc_adjusted_linker_flags 1
> +
> +    if {![is_remote host]} {
> +	set dest [target_info name]
> +	foreach i { ldflags libs ldscripts } {
> +	    if {[board_info $dest exists $i]} {
> +		set opts [board_info $dest $i]
> +		set nopts {}
> +		set skip ""
> +		foreach opt [split $opts] {
> +		    if { $skip != "" } then {
> +			set skip ""
> +		    } elseif { $opt == "-Xlinker" } then {
> +			set skip $opt
> +		    } elseif { ![string match "-*" $opt] \
> +				&& [file isfile $opt] } {
> +			set opt "-Wl,$opt"
> +		    }
> +		    lappend nopts $opt
> +		}
> +		if { $nopts != $opts } {
> +		    unset_currtarget_info $i
> +		    set_currtarget_info $i "$nopts"
> +		}
> +	    }
> +	}
> +    }
> +}
> +
>  # Return an updated version of OPTIONS that mentions any additional
>  # source files registered with dg-additional-sources.  SOURCE is the
>  # name of the test case.
>  
>  proc dg-additional-files-options { options source } {
> +    gcc_adjust_linker_flags
> +
>      global additional_sources
>      global additional_sources_used
>      global additional_files
> @@ -305,6 +347,10 @@ proc dg-additional-files-options { options source } {
>  	set to_download [concat $to_download $additional_sources]
>  	set additional_sources_used "$additional_sources"
>  	set additional_sources ""
> +	# This option restores naming of aux and dump output files
> +	# after input files when multiple input files are named,
> +	# instead of getting them combined with the output name.
> +	lappend options "additional_flags=-dumpbase \"\""
>      }
>      if { $additional_files != "" } then { 
>  	regsub -all "^| " $additional_files " [file dirname $source]/" additional_files
> diff --git a/gcc/testsuite/lib/profopt.exp b/gcc/testsuite/lib/profopt.exp
> index 0b853a1..af1fd62f 100644
> --- a/gcc/testsuite/lib/profopt.exp
> +++ b/gcc/testsuite/lib/profopt.exp
> @@ -353,6 +353,10 @@ proc profopt-execute { src } {
>  
>      set count 0
>      foreach option $prof_option_list {
> +	# We pass -dumpbase-ext ${execext}[123] to the compile&link
> +	# commands so as to avoid the combination of the executable
> +	# with the source name in the aux outputs.
> +	set execext ".x${count}"
>  	set execname1 "${executable}${count}1"
>  	set execname2 "${executable}${count}2"
>  	set execname3 "${executable}${count}3"
> @@ -402,7 +406,7 @@ proc profopt-execute { src } {
>  	# Compile for profiling.
>  
>  	set options "$extra_options"
> -	lappend options "additional_flags=$option $extra_flags $profile_option"
> +	lappend options "additional_flags=$option $extra_flags $profile_option -dumpbase-ext ${execext}1"
>  	set optstr "$option $profile_option"
>  	set comp_output [${tool}_target_compile "$src" "$execname1" executable $options]
>  	if ![${tool}_check_compile "$testcase compilation" $optstr $execname1 $comp_output] {
> @@ -491,7 +495,7 @@ proc profopt-execute { src } {
>  	# Compile with feedback-directed optimizations.
>  
>  	set options "$extra_options"
> -	lappend options "additional_flags=$option $extra_flags $feedback_option"
> +	lappend options "additional_flags=$option $extra_flags $feedback_option -dumpbase-ext ${execext}2"
>  	set optstr "$option $feedback_option"
>  	if { [string first "-fauto-profile" $options] >= 0} {
>  	    set options [regsub -- "-fauto-profile" $options "-fauto-profile=$tmpdir/$bprefix$base.$ext"]
> @@ -548,7 +552,7 @@ proc profopt-execute { src } {
>  	# Compile with normal optimizations.
>  
>  	set options "$extra_options"
> -	lappend options "additional_flags=$option"
> +	lappend options "additional_flags=$option -dumpbase-ext ${execext}3"
>  	set optstr "$option"
>  	set comp_output [${tool}_target_compile "$src" "$execname3" "executable" $options]
>  	if ![${tool}_check_compile "$testcase compilation" $optstr $execname3 $comp_output] {
> diff --git a/gcc/testsuite/lib/scandump.exp b/gcc/testsuite/lib/scandump.exp
> index d6ba350..2479c89 100644
> --- a/gcc/testsuite/lib/scandump.exp
> +++ b/gcc/testsuite/lib/scandump.exp
> @@ -32,6 +32,9 @@ proc dump-suffix { arg } {
>  proc dump-base { args } {
>      set src [lindex $args 0]
>      set dumpbase_suf [lindex $args 1]
> +    # The dump basename may vary depending on the output name, on
> +    # whether there are multiple sources.  We use -dumpbase "" in
> +    # gcc-defs to base compilation dumps only on the source basename.
>      set dumpbase $src
>      if { [string length $dumpbase_suf] != 0 } {
>  	regsub {[.][^.]*$} $src $dumpbase_suf dumpbase
> diff --git a/gcc/testsuite/lib/scanltranstree.exp b/gcc/testsuite/lib/scanltranstree.exp
> index cff956b..6d35bef 100644
> --- a/gcc/testsuite/lib/scanltranstree.exp
> +++ b/gcc/testsuite/lib/scanltranstree.exp
> @@ -37,11 +37,11 @@ proc scan-ltrans-tree-dump { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump "ltrans-tree" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
> +		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
>  		  [lindex $args 2]
>      } else {
>  	scan-dump "ltrans-tree" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
> +		  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
>      }
>  }
>  
> @@ -63,10 +63,10 @@ proc scan-ltrans-tree-dump-times { args } {
>      if { [llength $args] >= 4 } {
>  	scan-dump-times "ltrans-tree" [lindex $args 0] [lindex $args 1] \
>  			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" \
> -			".exe.ltrans0" [lindex $args 3]
> +			".ltrans0.ltrans" [lindex $args 3]
>      } else {
>  	scan-dump-times "ltrans-tree" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" ".exe.ltrans0"
> +			"\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 2]" ".ltrans0.ltrans"
>      }
>  }
>  
> @@ -87,11 +87,11 @@ proc scan-ltrans-tree-dump-not { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-not "ltrans-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
> +		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
>  		      [lindex $args 2]
>      } else {
>  	scan-dump-not "ltrans-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
> +		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
>      }
>  }
>  
> @@ -113,11 +113,11 @@ proc scan-ltrans-tree-dump-dem { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-dem "ltrans-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0" \
> +		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans" \
>  		      [lindex $args 2]
>      } else {
>  	scan-dump-dem "ltrans-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".exe.ltrans0"
> +		      "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" ".ltrans0.ltrans"
>      }
>  }
>  
> @@ -139,10 +139,10 @@ proc scan-ltrans-tree-dump-dem-not { args } {
>      if { [llength $args] >= 3 } {
>  	scan-dump-dem-not "ltrans-tree" [lindex $args 0] \
>  			  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" \
> -			  ".exe.ltrans0" [lindex $args 2]
> +			  ".ltrans0.ltrans" [lindex $args 2]
>      } else {
>  	scan-dump-dem-not "ltrans-tree" [lindex $args 0] \
>  			  "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" \
> -			  ".exe.ltrans0"
> +			  ".ltrans0.ltrans"
>      }
>  }
> diff --git a/gcc/testsuite/lib/scanwpaipa.exp b/gcc/testsuite/lib/scanwpaipa.exp
> index 2f58823..cc50cc4 100644
> --- a/gcc/testsuite/lib/scanwpaipa.exp
> +++ b/gcc/testsuite/lib/scanwpaipa.exp
> @@ -37,11 +37,11 @@ proc scan-wpa-ipa-dump { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump "wpa-ipa" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
> +		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
>  		  [lindex $args 2]
>      } else {
>  	scan-dump "wpa-ipa" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
> +		  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
>      }
>  }
>  
> @@ -85,11 +85,11 @@ proc scan-wpa-ipa-dump-times { args } {
>      }
>      if { [llength $args] >= 4 } {
>  	scan-dump-times "wpa-ipa" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".exe.wpa" \
> +			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".wpa" \
>  			[lindex $args 3]
>      } else {
>  	scan-dump-times "wpa-ipa" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".exe.wpa"
> +			"\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 2]" ".wpa"
>      }
>  }
>  
> @@ -110,11 +110,11 @@ proc scan-wpa-ipa-dump-not { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-not "wpa-ipa" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
> +		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
>  		      [lindex $args 2]
>      } else {
>  	scan-dump-not "wpa-ipa" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
> +		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
>      }
>  }
>  
> @@ -136,11 +136,11 @@ proc scan-wpa-ipa-dump-dem { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-dem "wpa-ipa" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
> +		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
>  		      [lindex $args 2]
>      } else {
>  	scan-dump-dem "wpa-ipa" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
> +		      "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
>      }
>  }
>  
> @@ -161,10 +161,10 @@ proc scan-wpa-ipa-dump-dem-not { args } {
>      }
>      if { [llength $args] >= 3 } {
>  	scan-dump-dem-not "wpa-ipa" [lindex $args 0] \
> -			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa" \
> +			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa" \
>  			  [lindex $args 2]
>      } else {
>  	scan-dump-dem-not "wpa-ipa" [lindex $args 0] \
> -			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".exe.wpa"
> +			  "\[0-9\]\[0-9\]\[0-9\]i.[lindex $args 1]" ".wpa"
>      }
>  }
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index 96316fb..1a75485 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -796,8 +796,8 @@ print_switch_values (print_switch_fn_type print_fn)
>  	case OPT_o:
>  	case OPT_d:
>  	case OPT_dumpbase:
> +	case OPT_dumpbase_ext:
>  	case OPT_dumpdir:
> -	case OPT_auxbase:
>  	case OPT_quiet:
>  	case OPT_version:
>  	  /* Ignore these.  */
> @@ -1410,11 +1410,19 @@ process_options (void)
>    /* Set aux_base_name if not already set.  */
>    if (aux_base_name)
>      ;
> -  else if (main_input_filename)
> +  else if (dump_base_name)
>      {
> -      char *name = xstrdup (lbasename (main_input_filename));
> +      const char *name = dump_base_name;
> +      int nlen, len;
> +
> +      if (dump_base_ext && (len = strlen (dump_base_ext))
> +	  && (nlen = strlen (name)) && nlen > len
> +	  && strcmp (name + nlen - len, dump_base_ext) == 0)
> +	{
> +	  char *p = xstrndup (name, nlen - len);
> +	  name = p;
> +	}
>  
> -      strip_off_ending (name, strlen (name));
>        aux_base_name = name;
>      }
>    else
> @@ -1964,8 +1972,21 @@ static int
>  lang_dependent_init (const char *name)
>  {
>    location_t save_loc = input_location;
> -  if (dump_base_name == 0)
> -    dump_base_name = name && name[0] ? name : "gccdump";
> +  if (!dump_base_name)
> +    {
> +      dump_base_name = name && name[0] ? name : "gccdump";
> +
> +      /* We do not want to derive a non-empty dumpbase-ext from an
> +	 explicit -dumpbase argument, only from a defaulted
> +	 dumpbase.  */
> +      if (!dump_base_ext)
> +	{
> +	  const char *base = lbasename (dump_base_name);
> +	  const char *ext = strrchr (base, '.');
> +	  if (ext)
> +	    dump_base_ext = ext;
> +	}
> +    }
>  
>    /* Other front-end initialization.  */
>    input_location = BUILTINS_LOCATION;
> @@ -1977,20 +1998,25 @@ lang_dependent_init (const char *name)
>      {
>        init_asm_output (name);
>  
> -      /* If stack usage information is desired, open the output file.  */
> -      if (flag_stack_usage && !flag_generate_lto)
> -	stack_usage_file = open_auxiliary_file ("su");
> -
> -      /* If call graph information is desired, open the output file.  */
> -      if (flag_callgraph_info && !flag_generate_lto)
> +      if (!flag_generate_lto && !flag_compare_debug)
>  	{
> -	  callgraph_info_file = open_auxiliary_file ("ci");
> -	  /* Write the file header.  */
> -	  fprintf (callgraph_info_file,
> -		   "graph: { title: \"%s\"\n", main_input_filename);
> -	  bitmap_obstack_initialize (NULL);
> -	  callgraph_info_external_printed = BITMAP_ALLOC (NULL);
> +	  /* If stack usage information is desired, open the output file.  */
> +	  if (flag_stack_usage)
> +	    stack_usage_file = open_auxiliary_file ("su");
> +
> +	  /* If call graph information is desired, open the output file.  */
> +	  if (flag_callgraph_info)
> +	    {
> +	      callgraph_info_file = open_auxiliary_file ("ci");
> +	      /* Write the file header.  */
> +	      fprintf (callgraph_info_file,
> +		       "graph: { title: \"%s\"\n", main_input_filename);
> +	      bitmap_obstack_initialize (NULL);
> +	      callgraph_info_external_printed = BITMAP_ALLOC (NULL);
> +	    }
>  	}
> +      else
> +	flag_stack_usage = flag_callgraph_info = false;
>      }
>  
>    /* This creates various _DECL nodes, so needs to be called after the
> diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c
> index 37f4bda..a65c280 100644
> --- a/lto-plugin/lto-plugin.c
> +++ b/lto-plugin/lto-plugin.c
> @@ -203,6 +203,10 @@ static bool linker_output_known;
>  static bool linker_output_auto_nolto_rel;
>  static const char *link_output_name = NULL;
>  
> +/* This indicates link_output_name already contains the dot of the
> +   suffix, so we can skip it in extensions.  */
> +static int skip_in_suffix = 0;
> +
>  /* The version of gold being used, or -1 if not gold.  The number is
>     MAJOR * 100 + MINOR.  */
>  static int gold_version = -1;
> @@ -621,14 +625,11 @@ exec_lto_wrapper (char *argv[])
>    /* Write argv to a file to avoid a command line that is too long
>       Save the file locally on save-temps.  */
>    if (save_temps && link_output_name)
> -    {
> -      arguments_file_name = (char *) xmalloc (strlen (link_output_name)
> -				  + sizeof (".lto_wrapper_args") + 1);
> -      strcpy (arguments_file_name, link_output_name);
> -      strcat (arguments_file_name, ".lto_wrapper_args");
> -    }
> +    arguments_file_name = concat (link_output_name,
> +				  ".lto_wrapper_args"
> +				  + skip_in_suffix, NULL);
>    else
> -     arguments_file_name = make_temp_file (".lto_wrapper_args");
> +    arguments_file_name = make_temp_file (".lto_wrapper_args");
>    check (arguments_file_name, LDPL_FATAL,
>           "Failed to generate a temorary file name");
>  
> @@ -1439,12 +1440,82 @@ onload (struct ld_plugin_tv *tv)
>        if (strstr (collect_gcc_options, "'-fno-use-linker-plugin'"))
>  	return LDPS_ERR;
>  
> -      if ( strstr (collect_gcc_options, "'-save-temps'"))
> +      if (strstr (collect_gcc_options, "'-save-temps'"))
>  	save_temps = true;
>  
>        if (strstr (collect_gcc_options, "'-v'")
>            || strstr (collect_gcc_options, "'--verbose'"))
>  	verbose = true;
> +
> +      const char *p;
> +      if ((p = strstr (collect_gcc_options, "'-dumpdir'")))
> +	{
> +	  p += sizeof ("'-dumpdir'");
> +	  while (*p == ' ')
> +	    p++;
> +	  const char *start = p;
> +	  int ticks = 0, escapes = 0;
> +	  /* Count ticks (') and escaped (\.) characters.  Stop at the
> +	     end of the options or at a blank after an even number of
> +	     ticks (not counting escaped ones.  */
> +	  for (p = start; *p; p++)
> +	    {
> +	      if (*p == '\'')
> +		{
> +		  ticks++;
> +		  continue;
> +		}
> +	      else if ((ticks % 2) != 0)
> +		{
> +		  if (*p == ' ')
> +		    break;
> +		  if (*p == '\\')
> +		    {
> +		      if (*++p)
> +			escapes++;
> +		      else
> +			p--;
> +		    }
> +		}
> +	    }
> +
> +	  /* Now allocate a new link_output_name and decode dumpdir
> +	     into it.  The loop uses the same logic, except it counts
> +	     ticks and escapes backwards (so ticks is adjusted if we
> +	     find an odd number of them), and it copies characters
> +	     that are escaped or not otherwise skipped.  */
> +	  int len = p - start - ticks - escapes + 1;
> +	  char *q = xmalloc (len);
> +	  link_output_name = q;
> +	  int oddticks = (ticks % 2);
> +	  ticks += oddticks;
> +	  for (p = start; *p; p++)
> +	    {
> +	      if (*p == '\'')
> +		{
> +		  ticks--;
> +		  continue;
> +		}
> +	      else if ((ticks % 2) != 0)
> +		{
> +		  if (*p == ' ')
> +		    break;
> +		  if (*p == '\\')
> +		    {
> +		      if (*++p)
> +			escapes--;
> +		      else
> +			p--;
> +		    }
> +		}
> +	      *q++ = *p;
> +	    }
> +	  *q = '\0';
> +	  assert (escapes == 0);
> +	  assert (ticks == oddticks);
> +	  assert (q - link_output_name == len - 1);
> +	  skip_in_suffix = 1;
> +	}
>      }
>  
>    return LDPS_OK;
> 
> 
>
Martin Liška May 26, 2020, 9:02 a.m. UTC | #58
On 5/26/20 10:52 AM, Richard Biener wrote:
> Did you maybe install a wrong patch or miss some changes?

No, I see the same failures.

Martin
Alexandre Oliva May 26, 2020, 10 a.m. UTC | #59
On May 26, 2020, Richard Biener <rguenther@suse.de> wrote:

> I'm seeing a lot of issues.

:-(

> First any LTO invocations end up with

> xgcc: error: unrecognized command-line option '-dumpbase'^M
> lto-wrapper: fatal error: /home/rguenther/obj/gcc/xgcc returned 1 exit 
> status^M
> compilation terminated.^M

> xg++: error: unrecognized command-line option '-dA'; did you mean '-A'

No luck duplicating these with my builds of gcc master :-(

(conversation on IRC)

Thanks for the binary, I've managed to duplicate the problem using your
binary.  Investigating...
Alexandre Oliva May 26, 2020, 12:14 p.m. UTC | #60
On May 26, 2020, Richard Biener <rguenther@suse.de> wrote:

> All visible by testing on x86_64-linux.

Interesting bug.  You wouldn't have hit it if you enabled Ada.  That's
because I'd missed the %< directives that validate_switches mishandled
in the Ada specs, so validate_switches handled the %{d*} and validated
-dA, -dumpbase, and any other option starting with -d.

Without those Ada specs, they wouldn't be validated, and we'd end up
reporting them as unrecognized.


So we have two bugs:

1. the Ada specs should have included %<dumpdir, %<dumpbase and
%<dumpbase-ext, so that %{d*} would not pass these flags on to gnat1, so
that %:dumps(...) can drop or override these flags without risk of
accidents.

Once I fixed that, I got the same symptoms that you did with a compiler
built without Ada.


2. validate_switches mishandled %< directives.  Unlike %{, %W{ and %@{,
%< is terminated by whitespace, and it can't have multiple options
separated by '|' or '&', nor does it have sub-specs to process after a
':'.  As it tried to handle %<dumpdir as %{dumpdir} or %{dumpdir| or
%{dumpdir:specs}, it skipped the whitespace after %<dumpdir, then
skipped what, for braced specs, would have been a separator or
terminator, and then proceeded to look at what the skipped character
was.  Finding none of the expected separators, it would just assume it
had skipped the closing brace and be done with it.  Problem is that,
instead of skipping a separator, it skipped the first character of the
next spec atom.  In our case, a '%'.  So validate_switches_from_spec
would skip <dumpbase, validate %<dumpbase-ext and get the % of %{d*}
skipped, so validate_switches_from_spec would skip rather than handle
{d*}.  And that's why none of the d* options got validated.  Oops.

I've arranged for callers of validate_switches to specify whether it's
to handle all the possibilities of a braced spec, or a single switch
name.


This is the resulting patch, that, though I'm still testing it, appears
to fix the problem.  I'll report back with a shorter summary and a
ChangeLog entry once I get it more thoroughly tested.


do not skip validation of switch after %<opt

From: Alexandre Oliva <oliva@gnu.org>


---
 gcc/ada/gcc-interface/lang-specs.h |    8 +++++---
 gcc/gcc.c                          |   22 +++++++++++++++-------
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
index 12b7cf5e..b72ab29 100644
--- a/gcc/ada/gcc-interface/lang-specs.h
+++ b/gcc/ada/gcc-interface/lang-specs.h
@@ -23,6 +23,8 @@
  *                                                                          *
  ****************************************************************************/
 
+#define ADA_DUMPS_OPTIONS DUMPS_OPTIONS ("%{!.adb:%{!.ads:.ada}}")
+
 /* This is the contribution to the `default_compilers' array in gcc.c for
    GNAT.  */
 
@@ -35,7 +37,7 @@
  gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
     %{fcompare-debug-second:-gnatd_A} \
-    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
+    %{O*} %{W*} %{w} %{p} %{pg:-p} " ADA_DUMPS_OPTIONS " \
     %{coverage:-fprofile-arcs -ftest-coverage} "
 #if defined(TARGET_VXWORKS_RTP)
    "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
@@ -51,7 +53,7 @@
  %{!c:%e-c required for gnat2why}\
  gnat1why %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
+    %{a} " ADA_DUMPS_OPTIONS " \
     %{gnatea:-gnatez} %{g*&m*&f*} \
     %1 %{o*:%w%*-gnatO} \
     %i \
@@ -62,7 +64,7 @@
  %{!c:%e-c required for gnat2scil}\
  gnat1scil %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
+    %{a} " ADA_DUMPS_OPTIONS " \
     %{gnatea:-gnatez} %{g*&m*&f*} \
     %1 %{o*:%w%*-gnatO} \
     %i \
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 8c851d7..49b7020 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -388,7 +388,7 @@ static void do_option_spec (const char *, const char *);
 static void do_self_spec (const char *);
 static const char *find_file (const char *);
 static int is_directory (const char *, bool);
-static const char *validate_switches (const char *, bool);
+static const char *validate_switches (const char *, bool, bool);
 static void validate_all_switches (void);
 static inline void validate_switches_from_spec (const char *, bool);
 static void give_switch (int, int);
@@ -1176,9 +1176,14 @@ static const char *cpp_options =
  %{!fno-working-directory:-fworking-directory}}} %{O*}\
  %{undef} %{save-temps*:-fpch-preprocess}";
 
+/* Make it easy for Ada to override the arguments for the %:dumps
+   specs function call.  */
+#define DUMPS_OPTIONS(EXTS) \
+  "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps(" EXTS ")"
+
 /* This contains cpp options which are not passed when the preprocessor
    output will be used by another program.  */
-static const char *cpp_debug_options = "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps()";
+static const char *cpp_debug_options = DUMPS_OPTIONS ("");
 
 /* NB: This is shared amongst all front-ends, except for Ada.  */
 static const char *cc1_options =
@@ -9061,7 +9066,7 @@ validate_switches_from_spec (const char *spec, bool user)
 	    || (*p == 'W' && *++p == '{')
 	    || (*p == '@' && *++p == '{')))
       /* We have a switch spec.  */
-      p = validate_switches (p + 1, user);
+      p = validate_switches (p + 1, user, *p == '{');
 }
 
 static void
@@ -9084,7 +9089,7 @@ validate_all_switches (void)
    and mark as valid all supplied switches that match it.  */
 
 static const char *
-validate_switches (const char *start, bool user_spec)
+validate_switches (const char *start, bool user_spec, bool braced)
 {
   const char *p = start;
   const char *atom;
@@ -9126,6 +9131,9 @@ next_member:
 	      switches[i].validated = true;
     }
 
+  if (!braced)
+    return p;
+
   if (*p) p++;
   if (*p && (p[-1] == '|' || p[-1] == '&'))
     goto next_member;
@@ -9138,11 +9146,11 @@ next_member:
 	    {
 	      p++;
 	      if (*p == '{' || *p == '<')
-		p = validate_switches (p+1, user_spec);
+		p = validate_switches (p+1, user_spec, *p == '{');
 	      else if (p[0] == 'W' && p[1] == '{')
-		p = validate_switches (p+2, user_spec);
+		p = validate_switches (p+2, user_spec, true);
 	      else if (p[0] == '@' && p[1] == '{')
-		p = validate_switches (p+2, user_spec);
+		p = validate_switches (p+2, user_spec, true);
 	    }
 	  else
 	    p++;
Alexandre Oliva May 26, 2020, 1:52 p.m. UTC | #61
On May 26, 2020, Richard Biener <rguenther@suse.de> wrote:

> xgcc: error: unrecognized command-line option '-dumpbase'^M

> xg++: error: unrecognized command-line option '-dA'; did you mean '-A'


Here's a proper patch submission.  I'm still throwing tests at it, but
it's already proved (with a non-bootstrapped build and test run) to fix
the latent (to me) problems above, exposed by configuring GCC without
Ada support, so I think putting it in is highly desirable, and a strict
improvement.  Ok to install?


do not skip validation of switch after %<opt

From: Alexandre Oliva <oliva@adacore.com>

After the patch that revamped dump and aux outputs, GCC compilation
drivers built without Ada would reject -d* options.  Such options
would only be validated because of the %{d*} in Ada lang specs, though
other languages had it as well.  Other languages had %< specs that had
to be there before %{d*} %:dumps(), while Ada was missing them.
Adding them to Ada brought the same problem to compilers that had Ada
enabled.

The reason validation failed was that they mishandled %< specs,
advancing past the beginning of the next spec, causing it not to be
handled.  Since %{d*} appeared after an odd %<, it was thus ignored.
The logic of validate_switches originally skipped the closing brace
that matched the opening brace, but this shouldn't happen for %<.
Fixed by letting validate_switches know whether it is handling a
braced group or a single atom, and behaving accordingly.


for  gcc/ChangeLog

	* gcc.c (validate_switches): Add braced parameter.  Adjust all
	callers.  Expected and skip trailing brace only if braced.
	Return after handling one atom otherwise.
	(DUMPS_OPTIONS): New.
	(cpp_debug_options): Define in terms of it.

for  gcc/ada/ChangeLog

	* gcc-interfaces/lang-specs.h (ADA_DUMPS_OPTIONS): Define in
	terms of DUMPS_OPTIONS.  Replace occurrences of %{d*} %:dumps
	with it.
---
 gcc/ada/gcc-interface/lang-specs.h |   10 +++++++---
 gcc/gcc.c                          |   32 +++++++++++++++++++++++---------
 2 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
index 12b7cf5e..f0ef3b92 100644
--- a/gcc/ada/gcc-interface/lang-specs.h
+++ b/gcc/ada/gcc-interface/lang-specs.h
@@ -23,6 +23,10 @@
  *                                                                          *
  ****************************************************************************/
 
+/* Pass -d* flags to the actual compiler, but mapping non-Ada
+   extensions to .ada in dump file names.  */
+#define ADA_DUMPS_OPTIONS DUMPS_OPTIONS ("%{!.adb:%{!.ads:.ada}}")
+
 /* This is the contribution to the `default_compilers' array in gcc.c for
    GNAT.  */
 
@@ -35,7 +39,7 @@
  gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
     %{fcompare-debug-second:-gnatd_A} \
-    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
+    %{O*} %{W*} %{w} %{p} %{pg:-p} " ADA_DUMPS_OPTIONS " \
     %{coverage:-fprofile-arcs -ftest-coverage} "
 #if defined(TARGET_VXWORKS_RTP)
    "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
@@ -51,7 +55,7 @@
  %{!c:%e-c required for gnat2why}\
  gnat1why %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
+    %{a} " ADA_DUMPS_OPTIONS " \
     %{gnatea:-gnatez} %{g*&m*&f*} \
     %1 %{o*:%w%*-gnatO} \
     %i \
@@ -62,7 +66,7 @@
  %{!c:%e-c required for gnat2scil}\
  gnat1scil %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
     %{nostdinc*} %{nostdlib*}\
-    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
+    %{a} " ADA_DUMPS_OPTIONS " \
     %{gnatea:-gnatez} %{g*&m*&f*} \
     %1 %{o*:%w%*-gnatO} \
     %i \
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 8c851d7..e2362175f4 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -388,7 +388,7 @@ static void do_option_spec (const char *, const char *);
 static void do_self_spec (const char *);
 static const char *find_file (const char *);
 static int is_directory (const char *, bool);
-static const char *validate_switches (const char *, bool);
+static const char *validate_switches (const char *, bool, bool);
 static void validate_all_switches (void);
 static inline void validate_switches_from_spec (const char *, bool);
 static void give_switch (int, int);
@@ -1176,9 +1176,16 @@ static const char *cpp_options =
  %{!fno-working-directory:-fworking-directory}}} %{O*}\
  %{undef} %{save-temps*:-fpch-preprocess}";
 
+/* Pass -d* flags, possibly modifying -dumpdir, -dumpbase et al.
+
+   Make it easy for a language to override the argument for the
+   %:dumps specs function call.  */
+#define DUMPS_OPTIONS(EXTS) \
+  "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps(" EXTS ")"
+
 /* This contains cpp options which are not passed when the preprocessor
    output will be used by another program.  */
-static const char *cpp_debug_options = "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps()";
+static const char *cpp_debug_options = DUMPS_OPTIONS ("");
 
 /* NB: This is shared amongst all front-ends, except for Ada.  */
 static const char *cc1_options =
@@ -9061,7 +9068,7 @@ validate_switches_from_spec (const char *spec, bool user)
 	    || (*p == 'W' && *++p == '{')
 	    || (*p == '@' && *++p == '{')))
       /* We have a switch spec.  */
-      p = validate_switches (p + 1, user);
+      p = validate_switches (p + 1, user, *p == '{');
 }
 
 static void
@@ -9080,11 +9087,15 @@ validate_all_switches (void)
   validate_switches_from_spec (link_command_spec, false);
 }
 
-/* Look at the switch-name that comes after START
-   and mark as valid all supplied switches that match it.  */
+/* Look at the switch-name that comes after START and mark as valid
+   all supplied switches that match it.  If BRACED, handle other
+   switches after '|' and '&', and specs after ':' until ';' or '}',
+   going back for more switches after ';'.  Without BRACED, handle
+   only one atom.  Return a pointer to whatever follows the handled
+   items, after the closing brace if BRACED.  */
 
 static const char *
-validate_switches (const char *start, bool user_spec)
+validate_switches (const char *start, bool user_spec, bool braced)
 {
   const char *p = start;
   const char *atom;
@@ -9126,6 +9137,9 @@ next_member:
 	      switches[i].validated = true;
     }
 
+  if (!braced)
+    return p;
+
   if (*p) p++;
   if (*p && (p[-1] == '|' || p[-1] == '&'))
     goto next_member;
@@ -9138,11 +9152,11 @@ next_member:
 	    {
 	      p++;
 	      if (*p == '{' || *p == '<')
-		p = validate_switches (p+1, user_spec);
+		p = validate_switches (p+1, user_spec, *p == '{');
 	      else if (p[0] == 'W' && p[1] == '{')
-		p = validate_switches (p+2, user_spec);
+		p = validate_switches (p+2, user_spec, true);
 	      else if (p[0] == '@' && p[1] == '{')
-		p = validate_switches (p+2, user_spec);
+		p = validate_switches (p+2, user_spec, true);
 	    }
 	  else
 	    p++;
Richard Biener May 26, 2020, 1:56 p.m. UTC | #62
On Tue, 26 May 2020, Alexandre Oliva wrote:

> On May 26, 2020, Richard Biener <rguenther@suse.de> wrote:
> 
> > xgcc: error: unrecognized command-line option '-dumpbase'^M
> 
> > xg++: error: unrecognized command-line option '-dA'; did you mean '-A'
> 
> 
> Here's a proper patch submission.  I'm still throwing tests at it, but
> it's already proved (with a non-bootstrapped build and test run) to fix
> the latent (to me) problems above, exposed by configuring GCC without
> Ada support, so I think putting it in is highly desirable, and a strict
> improvement.  Ok to install?

OK.

Thanks,
Richard.

> 
> do not skip validation of switch after %<opt
> 
> From: Alexandre Oliva <oliva@adacore.com>
> 
> After the patch that revamped dump and aux outputs, GCC compilation
> drivers built without Ada would reject -d* options.  Such options
> would only be validated because of the %{d*} in Ada lang specs, though
> other languages had it as well.  Other languages had %< specs that had
> to be there before %{d*} %:dumps(), while Ada was missing them.
> Adding them to Ada brought the same problem to compilers that had Ada
> enabled.
> 
> The reason validation failed was that they mishandled %< specs,
> advancing past the beginning of the next spec, causing it not to be
> handled.  Since %{d*} appeared after an odd %<, it was thus ignored.
> The logic of validate_switches originally skipped the closing brace
> that matched the opening brace, but this shouldn't happen for %<.
> Fixed by letting validate_switches know whether it is handling a
> braced group or a single atom, and behaving accordingly.
> 
> 
> for  gcc/ChangeLog
> 
> 	* gcc.c (validate_switches): Add braced parameter.  Adjust all
> 	callers.  Expected and skip trailing brace only if braced.
> 	Return after handling one atom otherwise.
> 	(DUMPS_OPTIONS): New.
> 	(cpp_debug_options): Define in terms of it.
> 
> for  gcc/ada/ChangeLog
> 
> 	* gcc-interfaces/lang-specs.h (ADA_DUMPS_OPTIONS): Define in
> 	terms of DUMPS_OPTIONS.  Replace occurrences of %{d*} %:dumps
> 	with it.
> ---
>  gcc/ada/gcc-interface/lang-specs.h |   10 +++++++---
>  gcc/gcc.c                          |   32 +++++++++++++++++++++++---------
>  2 files changed, 30 insertions(+), 12 deletions(-)
> 
> diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h
> index 12b7cf5e..f0ef3b92 100644
> --- a/gcc/ada/gcc-interface/lang-specs.h
> +++ b/gcc/ada/gcc-interface/lang-specs.h
> @@ -23,6 +23,10 @@
>   *                                                                          *
>   ****************************************************************************/
>  
> +/* Pass -d* flags to the actual compiler, but mapping non-Ada
> +   extensions to .ada in dump file names.  */
> +#define ADA_DUMPS_OPTIONS DUMPS_OPTIONS ("%{!.adb:%{!.ads:.ada}}")
> +
>  /* This is the contribution to the `default_compilers' array in gcc.c for
>     GNAT.  */
>  
> @@ -35,7 +39,7 @@
>   gnat1 %{I*} %{k8:-gnatk8} %{Wall:-gnatwa} %{w:-gnatws} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
>      %{fcompare-debug-second:-gnatd_A} \
> -    %{O*} %{W*} %{w} %{p} %{pg:-p} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
> +    %{O*} %{W*} %{w} %{p} %{pg:-p} " ADA_DUMPS_OPTIONS " \
>      %{coverage:-fprofile-arcs -ftest-coverage} "
>  #if defined(TARGET_VXWORKS_RTP)
>     "%{fRTS=rtp|fRTS=rtp-smp|fRTS=ravenscar-cert-rtp:-mrtp} "
> @@ -51,7 +55,7 @@
>   %{!c:%e-c required for gnat2why}\
>   gnat1why %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
> +    %{a} " ADA_DUMPS_OPTIONS " \
>      %{gnatea:-gnatez} %{g*&m*&f*} \
>      %1 %{o*:%w%*-gnatO} \
>      %i \
> @@ -62,7 +66,7 @@
>   %{!c:%e-c required for gnat2scil}\
>   gnat1scil %{I*} %{k8:-gnatk8} %{!Q:-quiet}\
>      %{nostdinc*} %{nostdlib*}\
> -    %{a} %{d*} %:dumps(%{!.adb:%{!.ads:.ada}}) \
> +    %{a} " ADA_DUMPS_OPTIONS " \
>      %{gnatea:-gnatez} %{g*&m*&f*} \
>      %1 %{o*:%w%*-gnatO} \
>      %i \
> diff --git a/gcc/gcc.c b/gcc/gcc.c
> index 8c851d7..e2362175f4 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -388,7 +388,7 @@ static void do_option_spec (const char *, const char *);
>  static void do_self_spec (const char *);
>  static const char *find_file (const char *);
>  static int is_directory (const char *, bool);
> -static const char *validate_switches (const char *, bool);
> +static const char *validate_switches (const char *, bool, bool);
>  static void validate_all_switches (void);
>  static inline void validate_switches_from_spec (const char *, bool);
>  static void give_switch (int, int);
> @@ -1176,9 +1176,16 @@ static const char *cpp_options =
>   %{!fno-working-directory:-fworking-directory}}} %{O*}\
>   %{undef} %{save-temps*:-fpch-preprocess}";
>  
> +/* Pass -d* flags, possibly modifying -dumpdir, -dumpbase et al.
> +
> +   Make it easy for a language to override the argument for the
> +   %:dumps specs function call.  */
> +#define DUMPS_OPTIONS(EXTS) \
> +  "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps(" EXTS ")"
> +
>  /* This contains cpp options which are not passed when the preprocessor
>     output will be used by another program.  */
> -static const char *cpp_debug_options = "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps()";
> +static const char *cpp_debug_options = DUMPS_OPTIONS ("");
>  
>  /* NB: This is shared amongst all front-ends, except for Ada.  */
>  static const char *cc1_options =
> @@ -9061,7 +9068,7 @@ validate_switches_from_spec (const char *spec, bool user)
>  	    || (*p == 'W' && *++p == '{')
>  	    || (*p == '@' && *++p == '{')))
>        /* We have a switch spec.  */
> -      p = validate_switches (p + 1, user);
> +      p = validate_switches (p + 1, user, *p == '{');
>  }
>  
>  static void
> @@ -9080,11 +9087,15 @@ validate_all_switches (void)
>    validate_switches_from_spec (link_command_spec, false);
>  }
>  
> -/* Look at the switch-name that comes after START
> -   and mark as valid all supplied switches that match it.  */
> +/* Look at the switch-name that comes after START and mark as valid
> +   all supplied switches that match it.  If BRACED, handle other
> +   switches after '|' and '&', and specs after ':' until ';' or '}',
> +   going back for more switches after ';'.  Without BRACED, handle
> +   only one atom.  Return a pointer to whatever follows the handled
> +   items, after the closing brace if BRACED.  */
>  
>  static const char *
> -validate_switches (const char *start, bool user_spec)
> +validate_switches (const char *start, bool user_spec, bool braced)
>  {
>    const char *p = start;
>    const char *atom;
> @@ -9126,6 +9137,9 @@ next_member:
>  	      switches[i].validated = true;
>      }
>  
> +  if (!braced)
> +    return p;
> +
>    if (*p) p++;
>    if (*p && (p[-1] == '|' || p[-1] == '&'))
>      goto next_member;
> @@ -9138,11 +9152,11 @@ next_member:
>  	    {
>  	      p++;
>  	      if (*p == '{' || *p == '<')
> -		p = validate_switches (p+1, user_spec);
> +		p = validate_switches (p+1, user_spec, *p == '{');
>  	      else if (p[0] == 'W' && p[1] == '{')
> -		p = validate_switches (p+2, user_spec);
> +		p = validate_switches (p+2, user_spec, true);
>  	      else if (p[0] == '@' && p[1] == '{')
> -		p = validate_switches (p+2, user_spec);
> +		p = validate_switches (p+2, user_spec, true);
>  	    }
>  	  else
>  	    p++;
> 
> 
>
Andreas Schwab May 27, 2020, 9:45 a.m. UTC | #63
FAIL: outputs exe default 1: a.{out,exe}
FAIL: outputs exe default 1: extra
a.out
FAIL: outputs exe default 2: a.{out,exe}
FAIL: outputs exe default 2: extra
a.out
FAIL: outputs exe savetmp unnamed1: a.{out,exe}
FAIL: outputs exe savetmp unnamed1: extra
a.out
FAIL: outputs exe savetmp unnamed2: a.{out,exe}
FAIL: outputs exe savetmp unnamed2: extra
a.out
FAIL: outputs exe savecwd unnamed1: a.{out,exe}
FAIL: outputs exe savecwd unnamed1: extra
a.out
FAIL: outputs exe savecwd unnamed2: a.{out,exe}
FAIL: outputs exe savecwd unnamed2: extra
a.out
FAIL: outputs exe saveobj unnamed1: a.{out,exe}
FAIL: outputs exe saveobj unnamed1: extra
a.out
FAIL: outputs exe saveobj unnamed2: a.{out,exe}
FAIL: outputs exe saveobj unnamed2: extra
a.out
FAIL: outputs exe auxdump unnamed1: a.{out,exe}
FAIL: outputs exe auxdump unnamed1: extra
a.out
FAIL: outputs exe auxdump unnamed2: a.{out,exe}
FAIL: outputs exe auxdump unnamed2: extra
a.out
FAIL: outputs exe auxdmps unnamed1: a.{out,exe}
FAIL: outputs exe auxdmps unnamed1: extra
a.out
FAIL: outputs exe auxdmps unnamed2: a.{out,exe}
FAIL: outputs exe auxdmps unnamed2: extra
a.out
FAIL: outputs exe dumpdir unnamed1: a.{out,exe}
FAIL: outputs exe dumpdir unnamed1: extra
a.out
FAIL: outputs exe dumpdir unnamed2: a.{out,exe}
FAIL: outputs exe dumpdir unnamed2: extra
a.out
FAIL: outputs exe dbsovrdd unnamed1: a.{out,exe}
FAIL: outputs exe dbsovrdd unnamed1: extra
a.out
FAIL: outputs exe dbsovrdd unnamed2: a.{out,exe}
FAIL: outputs exe dbsovrdd unnamed2: extra
a.out
FAIL: outputs exe dbswthdd unnamed1: a.{out,exe}
FAIL: outputs exe dbswthdd unnamed1: extra
a.out
FAIL: outputs exe dbswthdd unnamed2: a.{out,exe}
FAIL: outputs exe dbswthdd unnamed2: extra
a.out
FAIL: outputs exe dbwoutdd unnamed1: a.{out,exe}
FAIL: outputs exe dbwoutdd unnamed1: extra
a.out
FAIL: outputs exe dbwoutdd unnamed2: a.{out,exe}
FAIL: outputs exe dbwoutdd unnamed2: extra
a.out
FAIL: outputs lto sing unnamed: a.{out,exe}
FAIL: outputs lto sing unnamed: extra
a.out
FAIL: outputs lto mult unnamed: a.{out,exe}
FAIL: outputs lto mult unnamed: extra
a.out
FAIL: outputs lto sing dumpbase unnamed: a.{out,exe}
FAIL: outputs lto sing dumpbase unnamed: extra
a.out
FAIL: outputs lto mult dumpbase unnamed: a.{out,exe}
FAIL: outputs lto mult dumpbase unnamed: extra
a.out
FAIL: outputs lto sing dumpdir unnamed: a.{out,exe}
FAIL: outputs lto sing dumpdir unnamed: extra
a.out
FAIL: outputs lto mult dumpdir unnamed: a.{out,exe}
FAIL: outputs lto mult dumpdir unnamed: extra
a.out
FAIL: outputs lto dbswthdd sing unnamed: a.{out,exe}
FAIL: outputs lto dbswthdd sing unnamed: extra
a.out
FAIL: outputs lto dbswthdd mult unnamed: a.{out,exe}
FAIL: outputs lto dbswthdd mult unnamed: extra
a.out
FAIL: outputs lto dbsovrdd sing unnamed: a.{out,exe}
FAIL: outputs lto dbsovrdd sing unnamed: extra
a.out
FAIL: outputs lto dbsovrdd mult unnamed: a.{out,exe}
FAIL: outputs lto dbsovrdd mult unnamed: extra
a.out
FAIL: outputs lto sing empty dumpbase unnamed: a.{out,exe}
FAIL: outputs lto sing empty dumpbase unnamed: extra
a.out
FAIL: outputs lto mult empty dumpbase unnamed: a.{out,exe}
FAIL: outputs lto mult empty dumpbase unnamed: extra
a.out
FAIL: outputs lto sing empty dumpbase dumpdir unnamed: a.{out,exe}
FAIL: outputs lto sing empty dumpbase dumpdir unnamed: extra
a.out
FAIL: outputs lto mult empty dumpbase dumpdir unnamed: a.{out,exe}
FAIL: outputs lto mult empty dumpbase dumpdir unnamed: extra
a.out
FAIL: outputs lto sing empty dumpdir empty dumpbase unnamed: a.{out,exe}
FAIL: outputs lto sing empty dumpdir empty dumpbase unnamed: extra
a.out
FAIL: outputs lto mult empty dumpdir empty dumpbase unnamed: a.{out,exe}
FAIL: outputs lto mult empty dumpdir empty dumpbase unnamed: extra
a.out
FAIL: outputs lto st sing empty dumpbase unnamed: a.{out,exe}
FAIL: outputs lto st sing empty dumpbase unnamed: extra
a.out
FAIL: outputs lto st mult empty dumpbase unnamed: a.{out,exe}
FAIL: outputs lto st mult empty dumpbase unnamed: extra
a.out
FAIL: outputs lto st sing unnamed: a.{out,exe}
FAIL: outputs lto st sing unnamed: extra
a.out
FAIL: outputs lto st mult unnamed: a.{out,exe}
FAIL: outputs lto st mult unnamed: extra
a.out

Andreas.
Andreas Schwab May 27, 2020, 10:28 a.m. UTC | #64
Looks like tcl 8.5.5 has a bug:

% glob -nocomplain -path {} -- {a.{out,exe}}
% glob -nocomplain -path {} -- {a.{out,exe}*}
a.out

Andreas.
Alexandre Oliva May 27, 2020, 2:41 p.m. UTC | #65
On May 27, 2020, Andreas Schwab <schwab@suse.de> wrote:

> Looks like tcl 8.5.5 has a bug:

Ugh, how unfortunate.


> % glob -nocomplain -path {} -- {a.{out,exe}}
> % glob -nocomplain -path {} -- {a.{out,exe}*}
> a.out

Thanks for tracking that down, I'll put in some work around for that.
Andreas Schwab May 27, 2020, 2:59 p.m. UTC | #66
On Mai 27 2020, Alexandre Oliva wrote:

> On May 27, 2020, Andreas Schwab <schwab@suse.de> wrote:
>
>> Looks like tcl 8.5.5 has a bug:
>
> Ugh, how unfortunate.

In fact, that bug exists in all versions.

https://core.tcl-lang.org/tcl/tktview?name=5bbd044812

Andreas.
Alexandre Oliva May 27, 2020, 10:05 p.m. UTC | #67
outputs.exp: no lto, linker default output, cdtor temps, empty args

From: Alexandre Oliva <oliva@adacore.com>

This patch fixes various issues in the testsuite that came up after
the dump/aux output revamp, namely:

- many outputs.exp tests used -flto without checking that LTO was
supported, getting lots of failures.  With this patch, we test for LTO
support, and skip -flto tests on platforms that do not support it.

- some linkers error out if an output file is not named, and the
a.{out,exe} construct that we used throughout outputs.exp to match the
default linker output would trigger a bug in tcl globbing.  With this
patch, we detect the default linker output early.  If none is found,
we arrange to pass -o a.out explicitly in tests that used to test the
default linker output.  We now look for the detected default, or for
explicitly-specified output.

- collect2 will leave <execname>.cdtor.* files behind in -save-temps
tests.  Ignore them.

- The prepending of -Wl, to file names in ldflags et al was done in a
way that introduced empty arguments when consecutive blanks appeared
in these board configuration knobs.  Skip the empty strings between
consecutive blanks to avoid this problem.

Tested so far on x86_64-linux-gnu and powerpc-aix7.  Ok to install?


gcc/testsuite/ChangeLog:

	* lib/gcc-defs.exp: Avoid introducing empty arguments between
	consecutive blanks in board linking options.
	* gcc.misc-tests/outputs.exp: Likewise.  Document
	-gsplit-dwarf testing, skip LTO tests if -flto is not
	supported, detect the default linker output name, cope with
	the need for an explicit executable output.
---
 gcc/testsuite/gcc.misc-tests/outputs.exp |  163 +++++++++++++++++++++---------
 gcc/testsuite/lib/gcc-defs.exp           |    4 +
 2 files changed, 119 insertions(+), 48 deletions(-)

diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp
index 9823710..c3c6c2d 100644
--- a/gcc/testsuite/gcc.misc-tests/outputs.exp
+++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
@@ -30,6 +30,9 @@ if {![gcc_parallel_test_run_p $b] || [is_remote host]} {
 }
 gcc_parallel_test_enable 0
 
+# Check for -gsplit-dwarf support.  The outest proc will check that
+# gsplit_dwarf is empty if a .dwo file is missing before deciding
+# that's a fail.
 set gsplit_dwarf "-gsplit-dwarf"
 if ![check_no_compiler_messages gsplitdwarf object {
     void foo (void) { }
@@ -37,6 +40,10 @@ if ![check_no_compiler_messages gsplitdwarf object {
     set gsplit_dwarf ""
 }
 
+# Check for -flto support.  We explicitly test the result to skip
+# tests that use -flto.
+set skip_lto ![check_effective_target_lto]
+
 # Prepare additional options to be used for linking.
 # We do not compile to an executable, because that requires naming an output.
 set link_options ""
@@ -45,7 +52,9 @@ foreach i { ldflags libs ldscripts } {
     if {[board_info $dest exists $i]} {
 	set skip ""
 	foreach opt [split [board_info $dest $i]] {
-	    if { $skip != "" } then {
+	    if { $opt == "" } then {
+		continue
+	    } elseif { $skip != "" } then {
 		set skip ""
 	    } elseif { $opt == "-Xlinker" } then {
 		set skip $opt
@@ -73,9 +82,10 @@ if {[board_info $dest exists output_format]} {
 # double dash, or a dash followed by a period, the first dash is
 # replaced with $b-$b; names starting with "a--" or "a-." have "$b"
 # inserted after the first dash.  The glob pattern may expand to more
-# than one file, but then the test will pass when there any number of
-# matches.  So, it's safe to use for a.{out,exe}, but .{i,s,o} and
-# .[iso] will pass even if only the .o is present.
+# than one file, but then the test will pass for any number of
+# matches, i.e., it would be safe to use for a.{out,exe} (if it
+# weren't for https://core.tcl-lang.org/tcl/tktview?name=5bbd044812),
+# but .{i,s,o} and .[iso] will pass even if only the .o is present.
 proc outest { test sources opts dirs outputs } {
     global b
     global srcdir
@@ -120,6 +130,9 @@ proc outest { test sources opts dirs outputs } {
 		set o "a-$b-[string range $og 3 end]"
 	    } elseif { [string range $og 0 2] == "a-." } then {
 		set o "a-$b.[string range $og 3 end]"
+	    } elseif { "$og" == "\$aout" } then {
+		global aout
+		set o "$aout"
 	    } else {
 		set o "$og"
 	    }
@@ -148,17 +161,23 @@ proc outest { test sources opts dirs outputs } {
 	}
     }
 
+    set outb {}
     foreach f $outs {
 	file delete $f
+	# collect2 may create <execname>.cdtor* files in -save-temps link tests,
+	# ??? without regard to aux output naming conventions.
+	if ![string match "*.cdtor.*" $f] then {
+	    lappend outb $f
+	}
     }
     foreach d $dirs {
 	file delete -force $d
     }
 
-    if { [llength $outs] == 0 } then {
+    if { [llength $outb] == 0 } then {
 	pass "$test: extra"
     } else {
-	fail "$test: extra\n$outs"
+	fail "$test: extra\n$outb"
     }
 
     if { [string equal "$gcc_output" ""] } then {
@@ -172,6 +191,50 @@ proc outest { test sources opts dirs outputs } {
 set sing {-0.c}
 set mult {-1.c -2.c}
 
+# Find out the default linker output.  We only check for a.out and
+# e.exe; gcc.c, the lto-wrapper and whatnot may have to change if
+# prefixes other than a. might be used.  Our tests may have to be
+# adjusted then.  Also, there may not be a default.  Some linkers
+# error out if -o is not specified.
+proc default_link_name { sources } {
+    global b
+    global srcdir
+    global subdir
+    set src {}
+    foreach s $sources {
+	lappend src $srcdir/$subdir/$b$s
+    }
+
+    set maybe { a.out a.exe }
+    foreach f $maybe {
+	file delete $f
+    }
+
+    global link_options
+    set gcc_output [gcc_target_compile $src "" none "$link_options"]
+
+    foreach f $maybe {
+	if { [file exists $f] } then {
+	    file delete $f
+	    return $f
+	}
+    }
+
+    return "";
+}
+
+set aout [default_link_name $sing]
+
+# If there is no default linker output, arrange for -o a.out to be
+# specified where we would normally leave it for the linker to use its
+# default.
+if { "$aout" != "" } then {
+    set oaout ""
+} else {
+    set aout a.out
+    set oaout "-o $aout"
+}
+
 # Driver-chosen outputs.
 outest "$b asm default 1" $sing "-S" {} {{-0.s}}
 outest "$b asm default 2" $mult "-S" {} {{-1.s -2.s}}
@@ -179,8 +242,8 @@ outest "$b asm default 2" $mult "-S" {} {{-1.s -2.s}}
 outest "$b obj default 1" $sing "-c" {} {{-0.o}}
 outest "$b obj default 2" $mult "-c" {} {{-1.o -2.o}}
 
-outest "$b exe default 1" $sing "" {} {{a.{out,exe}}}
-outest "$b exe default 2" $mult "" {} {{a.{out,exe}}}
+outest "$b exe default 1" $sing "$oaout" {} {{$aout}}
+outest "$b exe default 2" $mult "$oaout" {} {{$aout}}
 
 # Driver-chosen aux outputs.
 outest "$b asm savetmp 1" $sing "-S -save-temps" {} {{-0.i -0.s}}
@@ -200,8 +263,8 @@ outest "$b obj savetmp namedb" $sing "-c -o $b.o -save-temps" {} {{.i .s .o}}
 # When linking, the executable name gets prepended to aux output
 # basenames, except when executable and single input share the same
 # basename.
-outest "$b exe savetmp unnamed1" $sing "-save-temps" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
-outest "$b exe savetmp unnamed2" $mult "-save-temps" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe savetmp unnamed1" $sing "-save-temps $oaout" {} {{a--0.i a--0.s a--0.o $aout}}
+outest "$b exe savetmp unnamed2" $mult "-save-temps $oaout" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o $aout}}
 outest "$b exe savetmp named0" $sing "-o $b-0.exe -save-temps" {} {{-0.i -0.s -0.o -0.exe}}
 outest "$b exe savetmp namedb" $sing "-o $b.exe -save-temps" {} {{--0.i --0.s --0.o .exe}}
 outest "$b exe savetmp named2" $mult "-o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
@@ -227,8 +290,8 @@ outest "$b obj savecwd named0" $sing "-c -o $b-0.o -save-temps=cwd" {} {{-0.i -0
 outest "$b cpp savecwd namedb" $sing "-E -o $b.i -save-temps=cwd" {} {{.i}}
 outest "$b asm savecwd namedb" $sing "-S -o $b.s -save-temps=cwd" {} {{.i .s}}
 outest "$b obj savecwd namedb" $sing "-c -o $b.o -save-temps=cwd" {} {{.i .s .o}}
-outest "$b exe savecwd unnamed1" $sing "-save-temps=cwd" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
-outest "$b exe savecwd unnamed2" $mult "-save-temps=cwd" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe savecwd unnamed1" $sing "-save-temps=cwd $oaout" {} {{a--0.i a--0.s a--0.o $aout}}
+outest "$b exe savecwd unnamed2" $mult "-save-temps=cwd $oaout" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o $aout}}
 outest "$b exe savecwd named0" $sing "-o $b-0.exe -save-temps=cwd" {} {{-0.i -0.s -0.o -0.exe}}
 outest "$b exe savecwd namedb" $sing "-o $b.exe -save-temps=cwd" {} {{--0.i --0.s --0.o .exe}}
 outest "$b exe savecwd named2" $mult "-o $b.exe -save-temps=cwd" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
@@ -253,8 +316,8 @@ outest "$b obj saveobj named0" $sing "-c -o $b-0.o -save-temps=obj" {} {{-0.i -0
 outest "$b cpp saveobj namedb" $sing "-E -o $b.i -save-temps=obj" {} {{.i}}
 outest "$b asm saveobj namedb" $sing "-S -o $b.s -save-temps=obj" {} {{.i .s}}
 outest "$b obj saveobj namedb" $sing "-c -o $b.o -save-temps=obj" {} {{.i .s .o}}
-outest "$b exe saveobj unnamed1" $sing "-save-temps=obj" {} {{a--0.i a--0.s a--0.o a.{out,exe}}}
-outest "$b exe saveobj unnamed2" $mult "-save-temps=obj" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o a.{out,exe}}}
+outest "$b exe saveobj unnamed1" $sing "-save-temps=obj $oaout" {} {{a--0.i a--0.s a--0.o $aout}}
+outest "$b exe saveobj unnamed2" $mult "-save-temps=obj $oaout" {} {{a--1.i a--1.s a--1.o a--2.i a--2.s a--2.o $aout}}
 outest "$b exe saveobj named0" $sing "-o $b-0.exe -save-temps=obj" {} {{-0.i -0.s -0.o -0.exe}}
 outest "$b exe saveobj namedb" $sing "-o $b.exe -save-temps=obj" {} {{--0.i --0.s --0.o .exe}}
 outest "$b exe saveobj named2" $mult "-o $b.exe -save-temps=obj" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .exe}}
@@ -314,8 +377,8 @@ outest "$b cpp auxdump namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usa
 outest "$b asm auxdump namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .s}}
 outest "$b obj auxdump namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{.c.???r.final .su .dwo .o}}
 
-outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--0.c.???r.final a--0.su a--0.dwo a.{out,exe}}}
-outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo a.{out,exe}}}
+outest "$b exe auxdump unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf $oaout" {} {{a--0.c.???r.final a--0.su a--0.dwo $aout}}
+outest "$b exe auxdump unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf $oaout" {} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo $aout}}
 outest "$b exe auxdump named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{-0.c.???r.final -0.su -0.dwo -0.exe}}
 outest "$b exe auxdump namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--0.c.???r.final --0.su --0.dwo .exe}}
 outest "$b exe auxdump named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf" {} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo .exe}}
@@ -344,8 +407,8 @@ outest "$b cpp auxdmps namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usa
 outest "$b asm auxdmps namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s}}
 outest "$b obj auxdmps namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{.i .c.???r.final .su .s .dwo .o}}
 
-outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o a.{out,exe}}}
-outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o a.{out,exe}}}
+outest "$b exe auxdmps unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps $oaout" {} {{a--0.i a--0.c.???r.final a--0.su a--0.s a--0.dwo a--0.o $aout}}
+outest "$b exe auxdmps unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps $oaout" {} {{a--1.i a--1.c.???r.final a--1.su a--1.s a--1.dwo a--1.o a--2.i a--2.c.???r.final a--2.su a--2.s a--2.dwo a--2.o $aout}}
 outest "$b exe auxdmps named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{-0.i -0.c.???r.final -0.su -0.s -0.dwo -0.o -0.exe}}
 outest "$b exe auxdmps namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--0.i --0.c.???r.final --0.su --0.s --0.dwo --0.o .exe}}
 outest "$b exe auxdmps named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -save-temps" {} {{--1.i --1.c.???r.final --1.su --1.s --1.dwo --1.o --2.i --2.c.???r.final --2.su --2.s --2.dwo --2.o .exe}}
@@ -374,8 +437,8 @@ outest "$b cpp dumpdir namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-usa
 outest "$b asm dumpdir namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su} {.s}}
 outest "$b obj dumpdir namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{.c.???r.final .su .dwo} {.o}}
 
-outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {a.{out,exe}}}
-outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a-" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dumpdir unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a- $oaout" {od/} {{a--0.c.???r.final a--0.su a--0.dwo} {$aout}}
+outest "$b exe dumpdir unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/a- $oaout" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {$aout}}
 outest "$b exe dumpdir named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {-0.exe}}
 outest "$b exe dumpdir namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-0.c.???r.final -0.su -0.dwo} {.exe}}
 outest "$b exe dumpdir named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/" {od/} {{-1.c.???r.final -1.su -1.dwo -2.c.???r.final -2.su -2.dwo} {.exe}}
@@ -428,8 +491,8 @@ outest "$b obj dbsovrdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-us
 # Nit: -dumpdir affects whether the specified dumpbase is combined
 # into dumpdir or taken as the output basename, even if dumpbase will
 # ultimately override it.
-outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
-outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbsovrdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b $oaout" {od/} {{.???r.final .su .dwo} {$aout}}
+outest "$b exe dbsovrdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/a $oaout" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {$aout}}
 outest "$b exe dbsovrdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {-0.exe}}
 outest "$b exe dbsovrdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
 outest "$b exe dbsovrdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir ./ -dumpbase od/$b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
@@ -472,8 +535,8 @@ outest "$b obj dbswthdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-us
 # Nitty details: -dumpdir affects whether the specified dumpbase is
 # combined into dumpdir or taken as the output basename, even if
 # dumpbase will ultimately override it.
-outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {a.{out,exe}}}
-outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbswthdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b $oaout" {od/} {{.???r.final .su .dwo} {$aout}}
+outest "$b exe dbswthdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase a $oaout" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {$aout}}
 outest "$b exe dbswthdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{.???r.final .su .dwo} {-0.exe}}
 outest "$b exe dbswthdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b.exe -dumpbase-ext .exe" {od/} {{.exe.???r.final .su .dwo} {.exe}}
 outest "$b exe dbswthdd named2" $mult "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpdir od/ -dumpbase $b" {od/} {{--1.c.???r.final --1.su --1.dwo --2.c.???r.final --2.su --2.dwo} {.exe}}
@@ -516,8 +579,8 @@ outest "$b cpp dbwoutdd namedb" $sing "-E -o $b.i -g -fdump-rtl-final -fstack-us
 outest "$b asm dbwoutdd namedb" $sing "-S -o $b.s -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su} {.s}}
 outest "$b obj dbwoutdd namedb" $sing "-c -o $b.o -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{.???r.final .su .dwo} {.o}}
 
-outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {a.{out,exe}}}
-outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {a.{out,exe}}}
+outest "$b exe dbwoutdd unnamed1" $sing "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b $oaout" {od/} {{--0.c.???r.final --0.su --0.dwo} {$aout}}
+outest "$b exe dbwoutdd unnamed2" $mult "-g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/a $oaout" {od/} {{a--1.c.???r.final a--1.su a--1.dwo a--2.c.???r.final a--2.su a--2.dwo} {$aout}}
 outest "$b exe dbwoutdd named0" $sing "-o $b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b" {od/} {{--0.c.???r.final --0.su --0.dwo} {-0.exe}}
 outest "$b exe dbwoutdd named0d" $sing "-o od/$b-0.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase $b" {od/} {{--0.c.???r.final --0.su --0.dwo -0.exe} {}}
 outest "$b exe dbwoutdd namedb" $sing "-o $b.exe -g -fdump-rtl-final -fstack-usage $gsplit_dwarf -dumpbase od/$b.exe -dumpbase-ext .exe" {od/} {{--0.c.???r.final --0.su --0.dwo} {.exe}}
@@ -542,9 +605,11 @@ outest "$b exe dbwoutdda namedir2" $mult "-o o/$b.exe -g -fdump-rtl-final -fstac
 outest "$b obj compare-debug" $sing "-c -fcompare-debug -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.c.gkd -0.gk.c.???r.final -0.dwo -0.o}}
 outest "$b obj compare-debug save-temps" $sing "-c -fcompare-debug -save-temps -fdump-rtl-final -fstack-usage $gsplit_dwarf -fdump-final-insns" {} {{-0.c.???r.final -0.su -0.i -0.c.gkd -0.s -0.gk.i -0.gk.c.???r.final -0.gk.c.gkd -0.dwo -0.o}}
 
+if !$skip_lto {
+
 # -flto
-outest "$b lto sing unnamed" $sing "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
-outest "$b lto mult unnamed" $mult "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.c.???i.icf a--2.c.???i.icf  a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing unnamed" $sing "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{a--0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su $aout}}
+outest "$b lto mult unnamed" $mult "-O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{a--1.c.???i.icf a--2.c.???i.icf  a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su $aout}}
 outest "$b lto sing named" $sing "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
 outest "$b lto mult named" $mult "-o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
 outest "$b lto sing nameddir" $sing "-o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
@@ -553,8 +618,8 @@ outest "$b lto mult nameddir" $mult "-o dir/$b.exe -O2 -flto -flto-partition=one
 # -dumpbase without -dumpdir.  The trailing dumppfx dash after it is
 # combined with dumpbase turns into a period when passed to lto as
 # -dumpdir, because the dash is introduced by the compiler driver.
-outest "$b lto sing dumpbase unnamed" $sing "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
-outest "$b lto mult dumpbase unnamed" $mult "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing dumpbase unnamed" $sing "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {$aout}}
+outest "$b lto mult dumpbase unnamed" $mult "-dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {$aout}}
 outest "$b lto sing dumpbase named" $sing "-dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
 outest "$b lto mult dumpbase named" $mult "-dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
 outest "$b lto sing dumpbase namedb" $sing "-dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
@@ -562,24 +627,24 @@ outest "$b lto mult dumpbase namedb" $mult "-dumpbase dir/$b -o $b.exe -O2 -flto
 
 # -dumpdir without -dumpbase.  The trailing dash in -dumpdir is given
 # by the user, thus not replaced with a dot.
-outest "$b lto sing dumpdir unnamed" $sing "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
-outest "$b lto mult dumpdir unnamed" $mult "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing dumpdir unnamed" $sing "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {$aout}}
+outest "$b lto mult dumpdir unnamed" $mult "-dumpdir dir/$b- -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {$aout}}
 outest "$b lto sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-0.exe}}
 outest "$b lto mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {-1.exe}}
 outest "$b lto sing dumpdir namedb" $sing "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
 outest "$b lto mult dumpdir namedb" $mult "-dumpdir dir/$b- -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -wpa.???i.icf -ltrans0.ltrans.???r.final -ltrans0.ltrans.su} {.exe}}
 
 # -dumpdir and non-overriding -dumpbase.
-outest "$b lto dbswthdd sing unnamed" $sing "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
-outest "$b lto dbswthdd mult unnamed" $mult "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbswthdd sing unnamed" $sing "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {$aout}}
+outest "$b lto dbswthdd mult unnamed" $mult "-dumpdir dir/ -dumpbase $b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {$aout}}
 outest "$b lto dbswthdd sing named" $sing "-dumpdir dir/ -dumpbase $b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
 outest "$b lto dbswthdd mult named" $mult "-dumpdir dir/ -dumpbase $b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
 outest "$b lto dbswthdd sing namedb" $sing "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
 outest "$b lto dbswthdd mult namedb" $mult "-dumpdir dir/ -dumpbase $b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
 
 # -dumpdir and an overriding -dumpbase.
-outest "$b lto dbsovrdd sing unnamed" $sing "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
-outest "$b lto dbsovrdd mult unnamed" $mult "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto dbsovrdd sing unnamed" $sing "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {$aout}}
+outest "$b lto dbsovrdd mult unnamed" $mult "-dumpdir ignore/ -dumpbase dir/$b -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {$aout}}
 outest "$b lto dbsovrdd sing named" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-0.exe}}
 outest "$b lto dbsovrdd mult named" $mult "-dumpdir ignore/ -dumpbase dir/$b -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {-1.exe}}
 outest "$b lto dbsovrdd sing namedb" $sing "-dumpdir ignore/ -dumpbase dir/$b -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su} {.exe}}
@@ -588,16 +653,16 @@ outest "$b lto dbsovrdd mult namedb" $mult "-dumpdir ignore/ -dumpbase dir/$b -o
 # Check that -dumpbase '' gets source names as dumpbases for
 # compilation, and output name as dumpbase for linking, regardless of
 # how many source files.
-outest "$b lto sing empty dumpbase unnamed" $sing "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
-outest "$b lto mult empty dumpbase unnamed" $mult "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing empty dumpbase unnamed" $sing "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su $aout}}
+outest "$b lto mult empty dumpbase unnamed" $mult "-dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su $aout}}
 outest "$b lto sing empty dumpbase named" $sing "-dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.exe} {}}
 outest "$b lto mult empty dumpbase named" $mult "-dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.exe} {}}
 outest "$b lto sing empty dumpbase namedb" $sing "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
 outest "$b lto mult empty dumpbase namedb" $mult "-dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe}}
 
 # Now with -dumpdir too.
-outest "$b lto sing empty dumpbase dumpdir unnamed" $sing "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
-outest "$b lto mult empty dumpbase dumpdir unnamed" $mult "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {a.{out,exe}}}
+outest "$b lto sing empty dumpbase dumpdir unnamed" $sing "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{--0.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {$aout}}
+outest "$b lto mult empty dumpbase dumpdir unnamed" $mult "-dumpdir dir/$b- -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {dir/} {{--1.c.???i.icf --2.c.???i.icf -a.wpa.???i.icf -a.ltrans0.ltrans.???r.final -a.ltrans0.ltrans.su} {$aout}}
 outest "$b lto sing empty dumpbase dumpdir named" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf --0.wpa.???i.icf --0.ltrans0.ltrans.???r.final --0.ltrans0.ltrans.su} {-0.exe}}
 outest "$b lto mult empty dumpbase dumpdir named" $mult "-dumpdir dir/$b- -dumpbase \"\" -o $b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --2.c.???i.icf --1.wpa.???i.icf --1.ltrans0.ltrans.???r.final --1.ltrans0.ltrans.su} {-1.exe}}
 outest "$b lto sing empty dumpbase dumpdir namedb" $sing "-dumpdir dir/$b- -dumpbase \"\" -o $b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf -.wpa.???i.icf -.ltrans0.ltrans.???r.final -.ltrans0.ltrans.su} {.exe}}
@@ -605,29 +670,32 @@ outest "$b lto mult empty dumpbase dumpdir namedb" $mult "-dumpdir dir/$b- -dump
 
 # And also with an empty -dumpdir.  That's equivalent to -dumpdir ./,
 # overriding any dumpdir implied by the output.
-outest "$b lto sing empty dumpdir empty dumpbase unnamed" $sing "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
-outest "$b lto mult empty dumpdir empty dumpbase unnamed" $mult "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.{out,exe}}}
+outest "$b lto sing empty dumpdir empty dumpbase unnamed" $sing "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-0.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su $aout}}
+outest "$b lto mult empty dumpdir empty dumpbase unnamed" $mult "-dumpdir \"\" -dumpbase \"\" -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-1.c.???i.icf -2.c.???i.icf a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su $aout}}
 outest "$b lto sing empty dumpdir empty dumpbase named" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b-0.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.exe} {-0.c.???i.icf -0.wpa.???i.icf -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su}}
 outest "$b lto mult empty dumpdir empty dumpbase named" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b-1.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.exe} {-1.c.???i.icf -2.c.???i.icf -1.wpa.???i.icf -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su}}
 outest "$b lto sing empty dumpdir empty dumpbase namedb" $sing "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-0.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
 outest "$b lto mult empty dumpdir empty dumpbase namedb" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
 
 # Now -flto with -save-temps, not exhaustive.
-outest "$b lto st sing empty dumpbase unnamed" $sing "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-0.i -0.s -0.o -0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
-outest "$b lto st mult empty dumpbase unnamed" $mult "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st sing empty dumpbase unnamed" $sing "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-0.i -0.s -0.o -0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o $aout}}
+outest "$b lto st mult empty dumpbase unnamed" $mult "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o $aout}}
 outest "$b lto st sing dumpdir empty dumpbase named" $sing "-dumpdir dir/ -dumpbase \"\" -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf -0.lto_wrapper_args -0.wpa.???i.icf -0.ltrans.out -0.res -0.ltrans0.o -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.ltrans0.ltrans.s -0.ltrans0.ltrans.o} {-0.exe}}
 outest "$b lto st mult dumpdir empty dumpbase named" $mult "-dumpdir dir/ -dumpbase \"\" -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf -1.lto_wrapper_args -1.wpa.???i.icf -1.ltrans.out -1.res -1.ltrans0.o -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.ltrans0.ltrans.s -1.ltrans0.ltrans.o} {-1.exe}}
 outest "$b lto st sing empty dumpbase namedb" $sing "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
 outest "$b lto st mult empty dumpbase namedb" $mult "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf -2.i -2.s -2.o -2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
 
 # lto save-temps without -dumpbase.
-outest "$b lto st sing unnamed" $sing "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--0.i a--0.s a--0.o a--0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
-outest "$b lto st mult unnamed" $mult "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {} {{a--1.i a--1.s a--1.o a--1.c.???i.icf a--2.i a--2.s a--2.o a--2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.{out,exe}}}
+outest "$b lto st sing unnamed" $sing "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{a--0.i a--0.s a--0.o a--0.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o $aout}}
+outest "$b lto st mult unnamed" $mult "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{a--1.i a--1.s a--1.o a--1.c.???i.icf a--2.i a--2.s a--2.o a--2.c.???i.icf a.lto_wrapper_args a.wpa.???i.icf a.ltrans.out a.res a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o $aout}}
 outest "$b lto st sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-0.exe}}
 outest "$b lto st mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf -lto_wrapper_args -wpa.???i.icf -ltrans.out -res -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o} {-1.exe}}
 outest "$b lto st sing namedb" $sing "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
 outest "$b lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf --2.i --2.s --2.o --2.c.???i.icf .lto_wrapper_args .wpa.???i.icf .ltrans.out .res .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .exe} {}}
 
+# !$skip_lto
+}
+
 # Below are examples taken from the documentation.
 # They are likely redundant with earlier test,
 # but we want to make sure behavior matches the docs.
@@ -660,9 +728,10 @@ outest "$b doc double  -c !-o -db" $mult "-c -dumpbase $b -fdump-rtl-final -fsta
 # gcc -c foo.c -o dir/foobar.o -dumpbase '' ...
 outest "$b doc single  -c  -o -db''" $sing "-c -o dir/$b.o -dumpbase \"\" -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{-0.c.???r.final -0.su -0.dwo .o} {}}
 
+if !$skip_lto {
 # gcc foo.c bar.c -o dir/foobar -dumpbase '' -flto ...
 outest "$b doc double !-c  -o -db'' -flto" $mult "-o dir/$b.exe -dumpbase \"\" -flto -O2 -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.c.???i.icf -2.c.???i.icf .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
-
+}
 
 # gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...
 outest "$b doc single  -c  -o -dbx" $sing "-c -o dir/$b-0.o -dumpbase $b.c -dumpbase-ext .c -fdump-rtl-final -fstack-usage $gsplit_dwarf" {dir/} {{.c.???r.final .su .dwo -0.o} {}}
diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
index fc7e8e2..d591cb3 100644
--- a/gcc/testsuite/lib/gcc-defs.exp
+++ b/gcc/testsuite/lib/gcc-defs.exp
@@ -306,7 +306,9 @@ proc gcc_adjust_linker_flags {} {
 		set nopts {}
 		set skip ""
 		foreach opt [split $opts] {
-		    if { $skip != "" } then {
+		    if { $opt == "" } then {
+			continue
+		    } elseif { $skip != "" } then {
 			set skip ""
 		    } elseif { $opt == "-Xlinker" } then {
 			set skip $opt
Li, Pan2 via Gcc-patches May 27, 2020, 11:01 p.m. UTC | #68
On Wed, 2020-05-27 at 19:05 -0300, Alexandre Oliva wrote:
> outputs.exp: no lto, linker default output, cdtor temps, empty args
> 
> From: Alexandre Oliva <oliva@adacore.com>
> 
> This patch fixes various issues in the testsuite that came up after
> the dump/aux output revamp, namely:
> 
> - many outputs.exp tests used -flto without checking that LTO was
> supported, getting lots of failures.  With this patch, we test for LTO
> support, and skip -flto tests on platforms that do not support it.
> 
> - some linkers error out if an output file is not named, and the
> a.{out,exe} construct that we used throughout outputs.exp to match the
> default linker output would trigger a bug in tcl globbing.  With this
> patch, we detect the default linker output early.  If none is found,
> we arrange to pass -o a.out explicitly in tests that used to test the
> default linker output.  We now look for the detected default, or for
> explicitly-specified output.
> 
> - collect2 will leave <execname>.cdtor.* files behind in -save-temps
> tests.  Ignore them.
> 
> - The prepending of -Wl, to file names in ldflags et al was done in a
> way that introduced empty arguments when consecutive blanks appeared
> in these board configuration knobs.  Skip the empty strings between
> consecutive blanks to avoid this problem.
> 
> Tested so far on x86_64-linux-gnu and powerpc-aix7.  Ok to install?
> 
> 
> gcc/testsuite/ChangeLog:
> 
> 	* lib/gcc-defs.exp: Avoid introducing empty arguments between
> 	consecutive blanks in board linking options.
> 	* gcc.misc-tests/outputs.exp: Likewise.  Document
> 	-gsplit-dwarf testing, skip LTO tests if -flto is not
> 	supported, detect the default linker output name, cope with
> 	the need for an explicit executable output.
OK.  THanks for jumping on it quickly.  I'll re-enable the tester once the patch
is committed. 

jeff
>
Alexandre Oliva June 2, 2020, 11:52 a.m. UTC | #69
On May 27, 2020, Alexandre Oliva <oliva@adacore.com> wrote:

> - The prepending of -Wl, to file names in ldflags et al was done in a
> way that introduced empty arguments when consecutive blanks appeared
> in these board configuration knobs.  Skip the empty strings between
> consecutive blanks to avoid this problem.

I thought I'd dealt with nearly all of the fallout with the patch above,
but I was still seeing unexpected outputs.exp errors in gcc-testresults@

Anthony Green, whose results showed a problem, was kind enough to share
his board config file with me, and looking into it I realized I'd used
ldscripts instead of ldscript as the board configuration knob name.
Oops.

I have not tested the patch below yet.  I'm starting testing it on
various configurations that, despite some of them being crosses to
embedded targets, did *not* have ldscript or ldscripts in the board
config files, i.e., they did not experience the problem.

I'd appreciate if someone who uses the ldscript knob in their board
config file would confirm that this patch fixes the problems for them.
I'll check the patch in under the obviously correct rule as soon as I
get confirmation that it brings some progress.

Thanks in advance,


spell ldscript correctly in outputs.exp et al

From: Alexandre Oliva <oliva@adacore.com>

In my recent changes to outputs.exp and gcc-defs.exp, I misreferenced
dejagnu board property ldscript, singular, as ldscripts, plural.

This probably didn't have much impact on gcc-defs.exp: the code there
would just prefix with -Wl, any options that amounted to file names,
and linker scripts probably wouldn't be named without a -T or even an
-Wl,-T, prefix.

The visible effects were in outputs.exp, that also intended to add the
ldscript, if present, to the set of options to be passed to the
compiler driver for linking.  Using the wrong option name, that
wouldn't work.


for  gcc/testsuite/ChangeLog

	* gcc.misc-tests/outputs.exp: Spell ldscript correctly.
	* lib/gcc-defs.exp (gcc_adjust_linker_flags): Likewise.
---
 testsuite/gcc.misc-tests/outputs.exp |    2 +-
 testsuite/lib/gcc-defs.exp           |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git gcc/testsuite/gcc.misc-tests/outputs.exp gcc/testsuite/gcc.misc-tests/outputs.exp
index c3c6c2d..06a32db 100644
--- gcc/testsuite/gcc.misc-tests/outputs.exp
+++ gcc/testsuite/gcc.misc-tests/outputs.exp
@@ -48,7 +48,7 @@ set skip_lto ![check_effective_target_lto]
 # We do not compile to an executable, because that requires naming an output.
 set link_options ""
 set dest [target_info name]
-foreach i { ldflags libs ldscripts } {
+foreach i { ldflags libs ldscript } {
     if {[board_info $dest exists $i]} {
 	set skip ""
 	foreach opt [split [board_info $dest $i]] {
diff --git gcc/testsuite/lib/gcc-defs.exp gcc/testsuite/lib/gcc-defs.exp
index d591cb3..87eeb7d 100644
--- gcc/testsuite/lib/gcc-defs.exp
+++ gcc/testsuite/lib/gcc-defs.exp
@@ -287,7 +287,7 @@ proc dg-additional-files { args } {
 
 set gcc_adjusted_linker_flags 0
 
-# Add -Wl, before any file names in ldflags, libs, and ldscripts, so
+# Add -Wl, before any file names in ldflags, libs, and ldscript, so
 # that default object files or libraries do not change the names of
 # gcc auxiliary outputs.
 
@@ -300,7 +300,7 @@ proc gcc_adjust_linker_flags {} {
 
     if {![is_remote host]} {
 	set dest [target_info name]
-	foreach i { ldflags libs ldscripts } {
+	foreach i { ldflags libs ldscript } {
 	    if {[board_info $dest exists $i]} {
 		set opts [board_info $dest $i]
 		set nopts {}
Richard Biener June 2, 2020, 12:02 p.m. UTC | #70
On Tue, 2 Jun 2020, Alexandre Oliva wrote:

> On May 27, 2020, Alexandre Oliva <oliva@adacore.com> wrote:
> 
> > - The prepending of -Wl, to file names in ldflags et al was done in a
> > way that introduced empty arguments when consecutive blanks appeared
> > in these board configuration knobs.  Skip the empty strings between
> > consecutive blanks to avoid this problem.
> 
> I thought I'd dealt with nearly all of the fallout with the patch above,
> but I was still seeing unexpected outputs.exp errors in gcc-testresults@
> 
> Anthony Green, whose results showed a problem, was kind enough to share
> his board config file with me, and looking into it I realized I'd used
> ldscripts instead of ldscript as the board configuration knob name.
> Oops.
> 
> I have not tested the patch below yet.  I'm starting testing it on
> various configurations that, despite some of them being crosses to
> embedded targets, did *not* have ldscript or ldscripts in the board
> config files, i.e., they did not experience the problem.
> 
> I'd appreciate if someone who uses the ldscript knob in their board
> config file would confirm that this patch fixes the problems for them.
> I'll check the patch in under the obviously correct rule as soon as I
> get confirmation that it brings some progress.
> 
> Thanks in advance,

OK.

Richard.

> 
> spell ldscript correctly in outputs.exp et al
> 
> From: Alexandre Oliva <oliva@adacore.com>
> 
> In my recent changes to outputs.exp and gcc-defs.exp, I misreferenced
> dejagnu board property ldscript, singular, as ldscripts, plural.
> 
> This probably didn't have much impact on gcc-defs.exp: the code there
> would just prefix with -Wl, any options that amounted to file names,
> and linker scripts probably wouldn't be named without a -T or even an
> -Wl,-T, prefix.
> 
> The visible effects were in outputs.exp, that also intended to add the
> ldscript, if present, to the set of options to be passed to the
> compiler driver for linking.  Using the wrong option name, that
> wouldn't work.
> 
> 
> for  gcc/testsuite/ChangeLog
> 
> 	* gcc.misc-tests/outputs.exp: Spell ldscript correctly.
> 	* lib/gcc-defs.exp (gcc_adjust_linker_flags): Likewise.
> ---
>  testsuite/gcc.misc-tests/outputs.exp |    2 +-
>  testsuite/lib/gcc-defs.exp           |    4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git gcc/testsuite/gcc.misc-tests/outputs.exp gcc/testsuite/gcc.misc-tests/outputs.exp
> index c3c6c2d..06a32db 100644
> --- gcc/testsuite/gcc.misc-tests/outputs.exp
> +++ gcc/testsuite/gcc.misc-tests/outputs.exp
> @@ -48,7 +48,7 @@ set skip_lto ![check_effective_target_lto]
>  # We do not compile to an executable, because that requires naming an output.
>  set link_options ""
>  set dest [target_info name]
> -foreach i { ldflags libs ldscripts } {
> +foreach i { ldflags libs ldscript } {
>      if {[board_info $dest exists $i]} {
>  	set skip ""
>  	foreach opt [split [board_info $dest $i]] {
> diff --git gcc/testsuite/lib/gcc-defs.exp gcc/testsuite/lib/gcc-defs.exp
> index d591cb3..87eeb7d 100644
> --- gcc/testsuite/lib/gcc-defs.exp
> +++ gcc/testsuite/lib/gcc-defs.exp
> @@ -287,7 +287,7 @@ proc dg-additional-files { args } {
>  
>  set gcc_adjusted_linker_flags 0
>  
> -# Add -Wl, before any file names in ldflags, libs, and ldscripts, so
> +# Add -Wl, before any file names in ldflags, libs, and ldscript, so
>  # that default object files or libraries do not change the names of
>  # gcc auxiliary outputs.
>  
> @@ -300,7 +300,7 @@ proc gcc_adjust_linker_flags {} {
>  
>      if {![is_remote host]} {
>  	set dest [target_info name]
> -	foreach i { ldflags libs ldscripts } {
> +	foreach i { ldflags libs ldscript } {
>  	    if {[board_info $dest exists $i]} {
>  		set opts [board_info $dest $i]
>  		set nopts {}
> 
> 
> 
>
Thomas Schwinge June 9, 2020, 12:29 p.m. UTC | #71
Hi!

On 2020-05-26T04:08:44-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> Thanks, here's the combined patch I'm checking in.
>
> revamp dump and aux output names

For BRIG (HSAIL) front end testing, I'm see a lot of failures like:

    Running [...]/source-gcc/gcc/testsuite/brig.dg/dg.exp ...
    PASS: brig.dg/test/gimple/variables.hsail (test for excess errors)
    [-PASS:-]{+UNRESOLVED:+} variables.hsail.brig scan-tree-dump original "__group_base_addr \\+ \\(0 \\+"
    [-PASS:-]{+UNRESOLVED:+} variables.hsail.brig scan-tree-dump original "__group_base_addr \\+ 0"
    [-PASS:-]{+UNRESOLVED:+} variables.hsail.brig scan-tree-dump gimple "[ ]*prog_global = s204;"
    [-PASS:-]{+UNRESOLVED:+} variables.hsail.brig scan-tree-dump gimple ".module.mod_global;"
    [...]

That's:

    spawn -ignore SIGHUP [...]/build-gcc/gcc/xgcc -B[...]/build-gcc/gcc/ [...]/build-gcc/gcc/testsuite/brig/variables.hsail.brig -fdump-tree-gimple -fdump-tree-original -S -o variables.s
    PASS: brig.dg/test/gimple/variables.hsail (test for excess errors)
    variables.hsail.brig: dump file does not exist
    dump file: variables.hsail.brig.original
    UNRESOLVED: variables.hsail.brig scan-tree-dump original "__group_base_addr \\+ \\(0 \\+"

We're trying to scan 'variables.hsail.brig.*', but for input file name
'variables.hsail.brig', we're now creating:

    $ ls -1 build-gcc/gcc/testsuite/brig/variables.*???t.*
    build-gcc/gcc/testsuite/brig/variables.brig.004t.original
    build-gcc/gcc/testsuite/brig/variables.brig.005t.gimple

Before your changes, GCC produced the expected:

    $ ls -1 build-gcc/gcc/testsuite/brig/variables.*???t.*
    build-gcc/gcc/testsuite/brig/variables.hsail.brig.004t.original
    build-gcc/gcc/testsuite/brig/variables.hsail.brig.005t.gimple

Are you able to easily create a patch for that?  How/where to adjust:
producer-side (GCC driver, or BRIG (HSAIL) front end?), or consumer-side
(testsuite: tree scanning machinery, or have to put some '-dumpbase' into
all test case files?)?


Grüße
 Thomas
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Thomas Schwinge June 9, 2020, 1:08 p.m. UTC | #72
Hi!

On 2020-05-26T04:08:44-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> Thanks, here's the combined patch I'm checking in.
>
> revamp dump and aux output names

For libgomp offloading testing, I'm seeing a number of failures like:

    UNSUPPORTED: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0
    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  (test for excess errors)
    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  execution test
    [-PASS:-]{+UNRESOLVED:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2   scan-offload-rtl-dump mach "Merging loop .* into "

    [...]

    UNSUPPORTED: libgomp.oacc-c/../libgomp.oacc-c-c++-common/pr85381-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0
    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/pr85381-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  (test for excess errors)
    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/pr85381-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  execution test
    [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/pr85381-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2   scan-assembler-times bar.sync 2

    [...]

    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/vector-length-128-1.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0  (test for excess errors)
    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/vector-length-128-1.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0  execution test
    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/vector-length-128-1.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0  output pattern test
    [-PASS:-]{+UNRESOLVED:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/vector-length-128-1.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0   scan-offload-tree-dump oaccdevlow "__attribute__\\(\\(oacc function \\(1, 1, 128\\)"

    [...]

    UNSUPPORTED: libgomp.oacc-c/vec.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0
    PASS: libgomp.oacc-c/vec.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  (test for excess errors)
    PASS: libgomp.oacc-c/vec.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  execution test
    [-PASS:-]{+UNRESOLVED:+} libgomp.oacc-c/vec.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2   scan-offload-tree-dump slp1 "vector\\(2\\) long long unsigned int"

    [...]

(A number of similar ones skipped.)


A word of warning: some of that testing indeed is fragile/ugly ;-) -- but
we have to restore it anyway.  That means, we shall gladly accept
suggestions how to do it better.


Consider 'libgomp.oacc-c-c++-common/nvptx-merged-loop.c':

    /* { dg-options "-foffload=-fdump-rtl-mach" } */

    /* { dg-final { scan-offload-rtl-dump "Merging loop .* into " "mach" } } */

Previously, for '-foffload=nvptx-none -foffload=-fdump-rtl-mach
-save-temps -o ./nvptx-merged-loop.exe', GCC produced the expected
'nvptx-merged-loop.o.307r.mach'.

Now, I find the file at '/tmp/cc6nlTN9.mkoffload-cc4ebUn4.o.307r.mach'

(The '-save-temps' comes from
'libgomp/testsuite/lib/libgomp-dg.exp:libgomp-dg-test', by the way.)

(Yes, that's all a bit ugly, how the 'mkoffload's etc. handle their
files...)

Similar for 'libgomp.oacc-c-c++-common/vector-length-128-1.c':

    /* { dg-additional-options "-foffload=-fdump-tree-oaccdevlow" } */

    /* { dg-final { scan-offload-tree-dump "__attribute__\\(\\(oacc function \\(1, 1, 128\\)" "oaccdevlow" } } */

Similar for 'libgomp.oacc-c/vec.c':

    /* { dg-additional-options "-std=c99 -ftree-slp-vectorize -foffload=-fdump-tree-slp1" } */

    /* { dg-final { scan-offload-tree-dump "vector\\(2\\) long long unsigned int" "slp1" } } */

(Thus not analyed these any further.)


Consider 'libgomp.oacc-c-c++-common/pr85381-2.c':

    /* { dg-additional-options "-save-temps" } */

    /* { dg-final { scan-assembler-times "bar.sync" 2 } } */

This expects to scan the PTX offloading compilation assembler code (not
host code!), expecting that nvptx offloading code assembly is produced
after the host code, and thus overwrites the latter file.  (Yes, that's
certainly ugly/fragile...)

Previously, for '-foffload=nvptx-none -save-temps -o ./pr85381-2.exe',
GCC left the '-foffload=nvptx-none' assembly in the expected
'pr85381-2.s'.

Now, I find the file at '/tmp/cc8JsG4H.mkoffload-pr85381-2.s'.


Are you able to easily create/suggest patches for these?  (You're
probably not set up for offloading compilation...)  Can you suggest
how/where to adjust: producer-side (GCC driver, 'mkoffload's?), or
consumer-side (testsuite: offload tree scanning machinery etc., or have
to put some '-dumpbase' or similar into all such test case files?)?


Grüße
 Thomas
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Alexandre Oliva June 10, 2020, 10:24 p.m. UTC | #73
On Jun  9, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:

> Are you able to easily create/suggest patches for these?  (You're
> probably not set up for offloading compilation...)

I can try, but I can certainly use help, if not in coding, at least with
testing.

> Can you suggest
> how/where to adjust: producer-side (GCC driver, 'mkoffload's?), or
> consumer-side (testsuite: offload tree scanning machinery etc., or have
> to put some '-dumpbase' or similar into all such test case files?)?

Given that files we used to output have now moved to /tmp, I suspect
we're failing to pass -dumpbase at some point, so the offloading
compiler ends up naming dump files after the temporary outputs rather
than as per the requested/expected names inferred from the main
compilation.

I guess mkoffload might need some tweaking; I see pieces of lto-wrapper
to call it, and the offload compiler, that I suspected might require
tweaking for the dumpbase revamp as well.

Let's see how far I can get by just looking at the code ;-)

If I were to get something like a -v compile and link session, from
someone all set for offloading compilation, with the command line passed
to lto-wrapper and the full commands it runs, I might be able to figure
out the dynamics more readily (hint, hint ;-)

Thanks in advance,
Tobias Burnus June 17, 2020, 10:50 a.m. UTC | #74
On 6/11/20 12:24 AM, Alexandre Oliva wrote:

> Let's see how far I can get by just looking at the code ;-)
>
> If I were to get something like a -v compile and link session, from
> someone all set for offloading compilation, with the command line passed
> to lto-wrapper and the full commands it runs, I might be able to figure
> out the dynamics more readily (hint, hint ;-)

I now did run it with a 7-day-old mainline compiler – run as run in
the testsuite plus '-v -foffload=-v'.
* 'files.log' shows the created files
* 'run.log' has in the first line the used command line and then the
   resulting output of '-v'.

I hope it helps.

Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Alexandre Oliva June 18, 2020, 2:58 a.m. UTC | #75
On Jun 17, 2020, Tobias Burnus <Tobias_Burnus@mentor.com> wrote:

> I hope it helps.

Thanks!  Not quite as much as I'd hoped, because I forgot much of the
arg passing in lto land is through @files, but I think I've got enough
to take a shot at fixing this.


Two questions that come to mind:

- do we wish to preserve the temp files used to hold args as dumpfiles
under -save-temps?  I'm a little ambivalent on this.

- can we assume the offload-target toolchain to also support -dumpbase,
  and possibly -dumpbase-ext, with the same semantics?
Alexandre Oliva June 18, 2020, 6:10 a.m. UTC | #76
On Jun  9, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:

> Are you able to easily create/suggest patches for these?  (You're
> probably not set up for offloading compilation...)  Can you suggest
> how/where to adjust: producer-side (GCC driver, 'mkoffload's?), or
> consumer-side (testsuite: offload tree scanning machinery etc., or have
> to put some '-dumpbase' or similar into all such test case files?)?

Could you possibly give this *completely* untested patch a try and let
me know whether it does any good?

I actually thought it might be appropriate to use ".x<offload_target>"
instead of ".target" in the dumpbase passed to mkoffload, so that we
create different file names for different offload targets, but then, how
do we access that target name in the testsuite machinery to pass
".x<offload_target>.mkoffload" as the dump base suffix appended to the
source/output basename?

Also, maybe we should shorten the suffixes appended to dumpbase, at
least in the -save-temps case.


handle dumpbase in offloading

From: Alexandre Oliva <oliva@adacore.com>

Pass dumpbase on to mkoffloads and their offload-target compiler runs.
Obey -save-temps in naming temporary files while at that.


for  gcc/ChangeLog

	* colllect-utils.h (dumppfx): New.
	* colllect-utils.c (dumppfx): Likewise.
	* lto-wrapper.c (run_gcc): Set global dumppfx.
	(compile_offload_image): Pass a -dumpbase on to mkoffload.
	* config/nvptx/mkoffload.c (ptx_dumpbase): New.
	(main): Handle incoming -dumpbase.  Set ptx_dumpbase.  Obey
	save_temps.
	(compile_native): Pass -dumpbase et al to compiler.
	* config/gcn/mkoffload.c (gcn_dumpbase): New.
	(main): Handle incoming -dumpbase.  Set gcn_dumpbase.  Obey
	save_temps.  Pass -dumpbase et al to offload target compiler.
	(compile_native): Pass -dumpbase et al to compiler.

for  gcc/testsuite/ChangeLog

	* lib/scanoffloadrtl.exp: Replace ".o" with
	".target.mkoffload" globally as the dump base suffix.
	* lib/scanoffloadtree.exp: Likewise.
---
 gcc/collect-utils.c                   |    1 +
 gcc/collect-utils.h                   |    1 +
 gcc/config/gcn/mkoffload.c            |   52 ++++++++++++++++++++++++++++++---
 gcc/config/nvptx/mkoffload.c          |   31 ++++++++++++++++++--
 gcc/lto-wrapper.c                     |   13 +++++++-
 gcc/testsuite/lib/scanoffloadrtl.exp  |   28 +++++++++---------
 gcc/testsuite/lib/scanoffloadtree.exp |   30 ++++++++++---------
 7 files changed, 118 insertions(+), 38 deletions(-)

diff --git a/gcc/collect-utils.c b/gcc/collect-utils.c
index e85843bc..0920e2e 100644
--- a/gcc/collect-utils.c
+++ b/gcc/collect-utils.c
@@ -34,6 +34,7 @@ static char *response_file;
 bool debug;
 bool verbose;
 bool save_temps;
+char *dumppfx;
 
 
 /* Notify user of a non-error.  */
diff --git a/gcc/collect-utils.h b/gcc/collect-utils.h
index e7c955f..8769065 100644
--- a/gcc/collect-utils.h
+++ b/gcc/collect-utils.h
@@ -37,6 +37,7 @@ extern void utils_cleanup (bool);
 extern bool debug;
 extern bool verbose;
 extern bool save_temps;
+extern char *dumppfx;
 
 /* Provided by the tool itself.  */
 
diff --git a/gcc/config/gcn/mkoffload.c b/gcc/config/gcn/mkoffload.c
index 4a99d70..9046451a 100644
--- a/gcc/config/gcn/mkoffload.c
+++ b/gcc/config/gcn/mkoffload.c
@@ -41,6 +41,7 @@ static const char *gcn_s1_name;
 static const char *gcn_s2_name;
 static const char *gcn_o_name;
 static const char *gcn_cfile_name;
+static const char *gcn_dumpbase;
 
 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
 
@@ -496,6 +497,12 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, gcn_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   switch (offload_abi)
     {
     case OFFLOAD_ABI_LP64:
@@ -525,6 +532,7 @@ main (int argc, char **argv)
   FILE *out = stdout;
   FILE *cfile = stdout;
   const char *outname = 0;
+  char *dumpbase;
 
   progname = "mkoffload";
   diagnostic_initialize (global_dc, 0);
@@ -611,6 +619,9 @@ main (int argc, char **argv)
 	save_temps = true;
       else if (strcmp (argv[i], "-v") == 0)
 	verbose = true;
+      else if (strcmp (argv[i], "-dumpbase") == 0
+	       && i + 1 < argc)
+	dumppfx = argv[++i];
     }
   if (!(fopenacc ^ fopenmp))
     fatal_error (input_location, "either -fopenacc or -fopenmp must be set");
@@ -628,11 +639,6 @@ main (int argc, char **argv)
       gcc_unreachable ();
     }
 
-  gcn_s1_name = make_temp_file (".mkoffload.1.s");
-  gcn_s2_name = make_temp_file (".mkoffload.2.s");
-  gcn_o_name = make_temp_file (".mkoffload.hsaco");
-  gcn_cfile_name = make_temp_file (".c");
-
   /* Build arguments for compiler pass.  */
   struct obstack cc_argv_obstack;
   obstack_init (&cc_argv_obstack);
@@ -656,6 +662,35 @@ main (int argc, char **argv)
 	obstack_ptr_grow (&cc_argv_obstack, argv[ix]);
     }
 
+  if (!dumppfx)
+    dumppfx = outname;
+
+  const char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
+  const char *hsaco_dumpbase = concat (dumppfx, ".mkoffload.hsaco", NULL);
+  gcn_dumpbase = concat (dumppfx, ".c", NULL);
+
+  if (save_temps)
+    {
+      gcn_s1_name = concat (mko_dumpbase, ".1.s", NULL);
+      gcn_s2_name = concat (mko_dumpbase, ".2.s", NULL);
+      gcn_o_name = hsaco_dumpbase;
+      gcn_cfile_name = gcn_dumpbase;
+    }
+  else
+    {
+      gcn_s1_name = make_temp_file (".mkoffload.1.s");
+      gcn_s2_name = make_temp_file (".mkoffload.2.s");
+      gcn_o_name = make_temp_file (".mkoffload.hsaco");
+      gcn_cfile_name = make_temp_file (".c");
+    }
+
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, mko_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, "");
+
   obstack_ptr_grow (&cc_argv_obstack, "-o");
   obstack_ptr_grow (&cc_argv_obstack, gcn_s1_name);
   obstack_ptr_grow (&cc_argv_obstack, NULL);
@@ -674,6 +709,13 @@ main (int argc, char **argv)
 	|| strncmp (argv[i], "-march", 6) == 0)
       obstack_ptr_grow (&ld_argv_obstack, argv[i]);
 
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, hsaco_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, "");
+
   obstack_ptr_grow (&ld_argv_obstack, "-o");
   obstack_ptr_grow (&ld_argv_obstack, gcn_o_name);
   obstack_ptr_grow (&ld_argv_obstack, NULL);
diff --git a/gcc/config/nvptx/mkoffload.c b/gcc/config/nvptx/mkoffload.c
index 803b585..efdf9b9 100644
--- a/gcc/config/nvptx/mkoffload.c
+++ b/gcc/config/nvptx/mkoffload.c
@@ -55,6 +55,7 @@ static id_map *var_ids, **vars_tail = &var_ids;
 /* Files to unlink.  */
 static const char *ptx_name;
 static const char *ptx_cfile_name;
+static const char *ptx_dumpbase;
 
 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
 
@@ -369,6 +370,12 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, ptx_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   switch (offload_abi)
     {
     case OFFLOAD_ABI_LP64:
@@ -486,6 +493,9 @@ main (int argc, char **argv)
 	save_temps = true;
       else if (strcmp (argv[i], "-v") == 0)
 	verbose = true;
+      else if (strcmp (argv[i], "-dumpbase") == 0
+	       && i + 1 < argc)
+	dumppfx = argv[++i];
     }
   if (!(fopenacc ^ fopenmp))
     fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> "
@@ -521,7 +531,14 @@ main (int argc, char **argv)
 	obstack_ptr_grow (&argv_obstack, argv[ix]);
     }
 
-  ptx_cfile_name = make_temp_file (".c");
+  if (!dumppfx)
+    dumppfx = outname;
+
+  ptx_dumpbase = concat (dumppfx, ".c", NULL);
+  if (save_temps)
+    ptx_cfile_name = ptx_dumpbase;
+  else
+    ptx_cfile_name = make_temp_file (".c");
 
   out = fopen (ptx_cfile_name, "w");
   if (!out)
@@ -531,7 +548,17 @@ main (int argc, char **argv)
      configurations.  */
   if (offload_abi == OFFLOAD_ABI_LP64)
     {
-      ptx_name = make_temp_file (".mkoffload");
+      char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
+      if (save_temps)
+	ptx_name = mko_dumpbase;
+      else
+	ptx_name = make_temp_file (".mkoffload");
+      obstack_ptr_grow (&argv_obstack, "-dumpdir");
+      obstack_ptr_grow (&argv_obstack, "");
+      obstack_ptr_grow (&argv_obstack, "-dumpbase");
+      obstack_ptr_grow (&argv_obstack, mko_dumpbase);
+      obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+      obstack_ptr_grow (&argv_obstack, "");
       obstack_ptr_grow (&argv_obstack, "-o");
       obstack_ptr_grow (&argv_obstack, ptx_name);
       obstack_ptr_grow (&argv_obstack, NULL);
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index 8fbca7c..74bcda3 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -830,6 +830,7 @@ compile_offload_image (const char *target, const char *compiler_path,
 		       unsigned int linker_opt_count)
 {
   char *filename = NULL;
+  char *dumpbase;
   char **argv;
   char *suffix
     = XALLOCAVEC (char, sizeof ("/accel//mkoffload") + strlen (target));
@@ -853,8 +854,13 @@ compile_offload_image (const char *target, const char *compiler_path,
 		 "could not find %s in %s (consider using %<-B%>)",
 		 suffix + 1, compiler_path);
 
+  dumpbase = concat (dumppfx, ".target", NULL);
+
   /* Generate temporary output file name.  */
-  filename = make_temp_file (".target.o");
+  if (save_temps)
+    filename = concat (dumpbase, ".o", NULL);
+  else
+    filename = make_temp_file (".target.o");
 
   struct obstack argv_obstack;
   obstack_init (&argv_obstack);
@@ -875,6 +881,9 @@ compile_offload_image (const char *target, const char *compiler_path,
 			   compiler_opt_count);
   append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
 
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dumpbase);
+
   /* Append options specified by -foffload last.  In case of conflicting
      options we expect offload compiler to choose the latest.  */
   append_offload_options (&argv_obstack, target, compiler_opts,
@@ -1298,7 +1307,7 @@ run_gcc (unsigned argc, char *argv[])
   bool linker_output_rel = false;
   bool skip_debug = false;
   unsigned n_debugobj;
-  const char *dumppfx = NULL, *incoming_dumppfx = NULL;
+  const char *incoming_dumppfx = dumppfx = NULL;
   static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
 
   /* Get the driver and options.  */
diff --git a/gcc/testsuite/lib/scanoffloadrtl.exp b/gcc/testsuite/lib/scanoffloadrtl.exp
index 69e4e7c8..e792450 100644
--- a/gcc/testsuite/lib/scanoffloadrtl.exp
+++ b/gcc/testsuite/lib/scanoffloadrtl.exp
@@ -37,11 +37,11 @@ proc scan-offload-rtl-dump { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump "offload-rtl" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		  [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump "offload-rtl" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -62,11 +62,11 @@ proc scan-offload-rtl-dump-times { args } {
     }
     if { [llength $args] >= 4 } {
 	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".o" \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".target.mkoffload" \
 			[lindex $args 3]
     } else {
 	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".target.mkoffload"
     }
 }
 
@@ -87,11 +87,11 @@ proc scan-offload-rtl-dump-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-not "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-not "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -113,11 +113,11 @@ proc scan-offload-rtl-dump-dem { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-dem "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -138,10 +138,10 @@ proc scan-offload-rtl-dump-dem-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-			  [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
     }
 }
diff --git a/gcc/testsuite/lib/scanoffloadtree.exp b/gcc/testsuite/lib/scanoffloadtree.exp
index 76a28d0..3a3b64d2 100644
--- a/gcc/testsuite/lib/scanoffloadtree.exp
+++ b/gcc/testsuite/lib/scanoffloadtree.exp
@@ -37,11 +37,11 @@ proc scan-offload-tree-dump { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump "offload-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		  [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump "offload-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -62,11 +62,11 @@ proc scan-offload-tree-dump-times { args } {
     }
     if { [llength $args] >= 4 } {
 	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".o" \
-			[lindex $args 3]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".target.mkoffload" \
+	    [lindex $args 3]
     } else {
 	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".target.mkoffload"
     }
 }
 
@@ -87,11 +87,11 @@ proc scan-offload-tree-dump-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-not "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-not "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -113,11 +113,11 @@ proc scan-offload-tree-dump-dem { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-dem "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -138,10 +138,10 @@ proc scan-offload-tree-dump-dem-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem-not "offload-tree" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-			  [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-dem-not "offload-tree" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
     }
 }
Tobias Burnus June 18, 2020, 9:41 a.m. UTC | #77
On 6/18/20 8:10 AM, Alexandre Oliva wrote:
> Could you possibly give this *completely* untested patch a try and let
> me know whether it does any good?

gcc/lto-wrapper.c:1473:41: error: invalid conversion from 'const char*' to 'char*' [-fpermissive]
     incoming_dumppfx = dumppfx = option->arg;
                                          ^
gcc/lto-wrapper.c:1518:10: warning: ISO C++ forbids converting a string constant to 'char*' [-Wpedantic]
   dumppfx = "a.";

gcc/config/nvptx/mkoffload.c:535:13: error: invalid conversion from 'const char*' to 'char*'
      dumppfx = outname;
              ^

Otherwise, see attachment. I now added also the @/tmp file which is
passed to mkoffload.

> I actually thought it might be appropriate to use ".x<offload_target>"
> instead of ".target" in the dumpbase passed to mkoffload, so that we
> create different file names for different offload targets,

I wonder whether we need to do this – as one can create code for
multiple offload targets by the same compiler at the same time.
I don't know how common this is in practice, but the compilers
offered by the Linux distributions support this.
(At least Debian and SUSE, I did not follow whether
Red Hat/Fedora already has GCN enabled or not.)

For example, on an openSUSE Linux system, one gets with
"gcc -fopenmp hello-world.f90 -v 2>&1|grep '/mkoffload":
/usr/lib64/gcc/x86_64-suse-linux/10//accel/nvptx-none/mkoffload @/tmp/ccKJReG8
/usr/lib64/gcc/x86_64-suse-linux/10//accel/amdgcn-amdhsa/mkoffload @/tmp/ccJcfKw8

Thus, without the offload_target prefix, they would dump into the same file!

On the other hand, by using -foffload=<name> one can restrict
the code to the host ("disable") or a list of offload devices,
typically the two above, although GCC also supports HSA (works differently)
and intelmic.

Thus, if really needed for debugging, one would be still able to
save the dump one wants to have.

I think the OpenACC libgomp testsuite cycles through the
available offload targets (disable, ...). While OpenMP
simply uses those which are available – which can be
zero/host (e.g. if build w/o offload support), one or
multiple.

> but then, how
> do we access that target name in the testsuite machinery to pass
> ".x<offload_target>.mkoffload" as the dump base suffix appended to the
> source/output basename?

Good question.

Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
-save-temps
-v
-xlto
-m64
-save-temps
-v
./nvptx-merged-loop.o
-fno-openmp
-fno-pie
-foffload-abi=lp64
-O2
-fno-diagnostics-show-caret
-fopenacc
-fdiagnostics-color=never
-fno-diagnostics-show-caret
-dumpbase
./nvptx-merged-loop..target
-fdump-rtl-mach
-v
-fdump-rtl-mach
-v
-dumpdir
""
-dumpbase
./nvptx-merged-loop..target.mkoffload
-dumpbase-ext
""
-o
./nvptx-merged-loop..target.mkoffload
Alexandre Oliva June 18, 2020, 10:39 a.m. UTC | #78
On Jun 18, 2020, Tobias Burnus <tobias@codesourcery.com> wrote:

> On 6/18/20 8:10 AM, Alexandre Oliva wrote:
>> Could you possibly give this *completely* untested patch a try and let
>> me know whether it does any good?

> Otherwise, see attachment. I now added also the @/tmp file which is
> passed to mkoffload.

Thanks.  I see the main problem besides the dumppfx constness is the
double dot before target, fixed in the revised patch below.

With this, I think the libgomp testsuite might work with offloading
again.

>> I actually thought it might be appropriate to use ".x<offload_target>"
>> instead of ".target" in the dumpbase passed to mkoffload, so that we
>> create different file names for different offload targets,

> I wonder whether we need to do this – as one can create code for
> multiple offload targets by the same compiler at the same time.

Aah, I wasn't sure this was indeed the case.

Well, then, I'll try to figure out how to get to the selected offloading
target from the scandump machinery.

> and intelmic.

How does intelmic get into the picture?  I looked for a mkoffload
program for it in the GCC source tree and couldn't find one.  This
suggests that the addition of -dumpbase to the mkoffload interface might
require changes elsewhere.


handle dumpbase in offloading

From: Alexandre Oliva <oliva@adacore.com>

Pass dumpbase on to mkoffloads and their offload-target compiler runs.
Obey -save-temps in naming temporary files while at that.


for  gcc/ChangeLog

	* colllect-utils.h (dumppfx): New.
	* colllect-utils.c (dumppfx): Likewise.
	* lto-wrapper.c (run_gcc): Set global dumppfx.
	(compile_offload_image): Pass a -dumpbase on to mkoffload.
	* config/nvptx/mkoffload.c (ptx_dumpbase): New.
	(main): Handle incoming -dumpbase.  Set ptx_dumpbase.  Obey
	save_temps.
	(compile_native): Pass -dumpbase et al to compiler.
	* config/gcn/mkoffload.c (gcn_dumpbase): New.
	(main): Handle incoming -dumpbase.  Set gcn_dumpbase.  Obey
	save_temps.  Pass -dumpbase et al to offload target compiler.
	(compile_native): Pass -dumpbase et al to compiler.

for  gcc/testsuite/ChangeLog

	* lib/scanoffloadrtl.exp: Replace ".o" with
	".target.mkoffload" globally as the dump base suffix.
	* lib/scanoffloadtree.exp: Likewise.
---
 gcc/collect-utils.c                   |    1 +
 gcc/collect-utils.h                   |    1 +
 gcc/config/gcn/mkoffload.c            |   52 ++++++++++++++++++++++++++++++---
 gcc/config/nvptx/mkoffload.c          |   31 ++++++++++++++++++--
 gcc/lto-wrapper.c                     |   16 +++++++++-
 gcc/testsuite/lib/scanoffloadrtl.exp  |   28 +++++++++---------
 gcc/testsuite/lib/scanoffloadtree.exp |   30 ++++++++++---------
 7 files changed, 121 insertions(+), 38 deletions(-)

diff --git a/gcc/collect-utils.c b/gcc/collect-utils.c
index e85843bc..d4fa2c3 100644
--- a/gcc/collect-utils.c
+++ b/gcc/collect-utils.c
@@ -34,6 +34,7 @@ static char *response_file;
 bool debug;
 bool verbose;
 bool save_temps;
+const char *dumppfx;
 
 
 /* Notify user of a non-error.  */
diff --git a/gcc/collect-utils.h b/gcc/collect-utils.h
index e7c955f..6ff7d9d9 100644
--- a/gcc/collect-utils.h
+++ b/gcc/collect-utils.h
@@ -37,6 +37,7 @@ extern void utils_cleanup (bool);
 extern bool debug;
 extern bool verbose;
 extern bool save_temps;
+extern const char *dumppfx;
 
 /* Provided by the tool itself.  */
 
diff --git a/gcc/config/gcn/mkoffload.c b/gcc/config/gcn/mkoffload.c
index 4a99d70..9046451a 100644
--- a/gcc/config/gcn/mkoffload.c
+++ b/gcc/config/gcn/mkoffload.c
@@ -41,6 +41,7 @@ static const char *gcn_s1_name;
 static const char *gcn_s2_name;
 static const char *gcn_o_name;
 static const char *gcn_cfile_name;
+static const char *gcn_dumpbase;
 
 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
 
@@ -496,6 +497,12 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, gcn_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   switch (offload_abi)
     {
     case OFFLOAD_ABI_LP64:
@@ -525,6 +532,7 @@ main (int argc, char **argv)
   FILE *out = stdout;
   FILE *cfile = stdout;
   const char *outname = 0;
+  char *dumpbase;
 
   progname = "mkoffload";
   diagnostic_initialize (global_dc, 0);
@@ -611,6 +619,9 @@ main (int argc, char **argv)
 	save_temps = true;
       else if (strcmp (argv[i], "-v") == 0)
 	verbose = true;
+      else if (strcmp (argv[i], "-dumpbase") == 0
+	       && i + 1 < argc)
+	dumppfx = argv[++i];
     }
   if (!(fopenacc ^ fopenmp))
     fatal_error (input_location, "either -fopenacc or -fopenmp must be set");
@@ -628,11 +639,6 @@ main (int argc, char **argv)
       gcc_unreachable ();
     }
 
-  gcn_s1_name = make_temp_file (".mkoffload.1.s");
-  gcn_s2_name = make_temp_file (".mkoffload.2.s");
-  gcn_o_name = make_temp_file (".mkoffload.hsaco");
-  gcn_cfile_name = make_temp_file (".c");
-
   /* Build arguments for compiler pass.  */
   struct obstack cc_argv_obstack;
   obstack_init (&cc_argv_obstack);
@@ -656,6 +662,35 @@ main (int argc, char **argv)
 	obstack_ptr_grow (&cc_argv_obstack, argv[ix]);
     }
 
+  if (!dumppfx)
+    dumppfx = outname;
+
+  const char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
+  const char *hsaco_dumpbase = concat (dumppfx, ".mkoffload.hsaco", NULL);
+  gcn_dumpbase = concat (dumppfx, ".c", NULL);
+
+  if (save_temps)
+    {
+      gcn_s1_name = concat (mko_dumpbase, ".1.s", NULL);
+      gcn_s2_name = concat (mko_dumpbase, ".2.s", NULL);
+      gcn_o_name = hsaco_dumpbase;
+      gcn_cfile_name = gcn_dumpbase;
+    }
+  else
+    {
+      gcn_s1_name = make_temp_file (".mkoffload.1.s");
+      gcn_s2_name = make_temp_file (".mkoffload.2.s");
+      gcn_o_name = make_temp_file (".mkoffload.hsaco");
+      gcn_cfile_name = make_temp_file (".c");
+    }
+
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, mko_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, "");
+
   obstack_ptr_grow (&cc_argv_obstack, "-o");
   obstack_ptr_grow (&cc_argv_obstack, gcn_s1_name);
   obstack_ptr_grow (&cc_argv_obstack, NULL);
@@ -674,6 +709,13 @@ main (int argc, char **argv)
 	|| strncmp (argv[i], "-march", 6) == 0)
       obstack_ptr_grow (&ld_argv_obstack, argv[i]);
 
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, hsaco_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, "");
+
   obstack_ptr_grow (&ld_argv_obstack, "-o");
   obstack_ptr_grow (&ld_argv_obstack, gcn_o_name);
   obstack_ptr_grow (&ld_argv_obstack, NULL);
diff --git a/gcc/config/nvptx/mkoffload.c b/gcc/config/nvptx/mkoffload.c
index 803b585..efdf9b9 100644
--- a/gcc/config/nvptx/mkoffload.c
+++ b/gcc/config/nvptx/mkoffload.c
@@ -55,6 +55,7 @@ static id_map *var_ids, **vars_tail = &var_ids;
 /* Files to unlink.  */
 static const char *ptx_name;
 static const char *ptx_cfile_name;
+static const char *ptx_dumpbase;
 
 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
 
@@ -369,6 +370,12 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, ptx_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   switch (offload_abi)
     {
     case OFFLOAD_ABI_LP64:
@@ -486,6 +493,9 @@ main (int argc, char **argv)
 	save_temps = true;
       else if (strcmp (argv[i], "-v") == 0)
 	verbose = true;
+      else if (strcmp (argv[i], "-dumpbase") == 0
+	       && i + 1 < argc)
+	dumppfx = argv[++i];
     }
   if (!(fopenacc ^ fopenmp))
     fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> "
@@ -521,7 +531,14 @@ main (int argc, char **argv)
 	obstack_ptr_grow (&argv_obstack, argv[ix]);
     }
 
-  ptx_cfile_name = make_temp_file (".c");
+  if (!dumppfx)
+    dumppfx = outname;
+
+  ptx_dumpbase = concat (dumppfx, ".c", NULL);
+  if (save_temps)
+    ptx_cfile_name = ptx_dumpbase;
+  else
+    ptx_cfile_name = make_temp_file (".c");
 
   out = fopen (ptx_cfile_name, "w");
   if (!out)
@@ -531,7 +548,17 @@ main (int argc, char **argv)
      configurations.  */
   if (offload_abi == OFFLOAD_ABI_LP64)
     {
-      ptx_name = make_temp_file (".mkoffload");
+      char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
+      if (save_temps)
+	ptx_name = mko_dumpbase;
+      else
+	ptx_name = make_temp_file (".mkoffload");
+      obstack_ptr_grow (&argv_obstack, "-dumpdir");
+      obstack_ptr_grow (&argv_obstack, "");
+      obstack_ptr_grow (&argv_obstack, "-dumpbase");
+      obstack_ptr_grow (&argv_obstack, mko_dumpbase);
+      obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+      obstack_ptr_grow (&argv_obstack, "");
       obstack_ptr_grow (&argv_obstack, "-o");
       obstack_ptr_grow (&argv_obstack, ptx_name);
       obstack_ptr_grow (&argv_obstack, NULL);
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index 8fbca7c..e990961 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -830,6 +830,7 @@ compile_offload_image (const char *target, const char *compiler_path,
 		       unsigned int linker_opt_count)
 {
   char *filename = NULL;
+  char *dumpbase;
   char **argv;
   char *suffix
     = XALLOCAVEC (char, sizeof ("/accel//mkoffload") + strlen (target));
@@ -853,8 +854,16 @@ compile_offload_image (const char *target, const char *compiler_path,
 		 "could not find %s in %s (consider using %<-B%>)",
 		 suffix + 1, compiler_path);
 
+  /* ??? We should probably use the TARGET name instead of "target"
+     here, so as to create different file names for different offload
+     targets.  */
+  dumpbase = concat (dumppfx, "target", NULL);
+
   /* Generate temporary output file name.  */
-  filename = make_temp_file (".target.o");
+  if (save_temps)
+    filename = concat (dumpbase, ".o", NULL);
+  else
+    filename = make_temp_file (".target.o");
 
   struct obstack argv_obstack;
   obstack_init (&argv_obstack);
@@ -875,6 +884,9 @@ compile_offload_image (const char *target, const char *compiler_path,
 			   compiler_opt_count);
   append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
 
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dumpbase);
+
   /* Append options specified by -foffload last.  In case of conflicting
      options we expect offload compiler to choose the latest.  */
   append_offload_options (&argv_obstack, target, compiler_opts,
@@ -1298,7 +1310,7 @@ run_gcc (unsigned argc, char *argv[])
   bool linker_output_rel = false;
   bool skip_debug = false;
   unsigned n_debugobj;
-  const char *dumppfx = NULL, *incoming_dumppfx = NULL;
+  const char *incoming_dumppfx = dumppfx = NULL;
   static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
 
   /* Get the driver and options.  */
diff --git a/gcc/testsuite/lib/scanoffloadrtl.exp b/gcc/testsuite/lib/scanoffloadrtl.exp
index 69e4e7c8..e792450 100644
--- a/gcc/testsuite/lib/scanoffloadrtl.exp
+++ b/gcc/testsuite/lib/scanoffloadrtl.exp
@@ -37,11 +37,11 @@ proc scan-offload-rtl-dump { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump "offload-rtl" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		  [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump "offload-rtl" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -62,11 +62,11 @@ proc scan-offload-rtl-dump-times { args } {
     }
     if { [llength $args] >= 4 } {
 	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".o" \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".target.mkoffload" \
 			[lindex $args 3]
     } else {
 	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".target.mkoffload"
     }
 }
 
@@ -87,11 +87,11 @@ proc scan-offload-rtl-dump-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-not "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-not "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -113,11 +113,11 @@ proc scan-offload-rtl-dump-dem { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-dem "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -138,10 +138,10 @@ proc scan-offload-rtl-dump-dem-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-			  [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
     }
 }
diff --git a/gcc/testsuite/lib/scanoffloadtree.exp b/gcc/testsuite/lib/scanoffloadtree.exp
index 76a28d0..3a3b64d2 100644
--- a/gcc/testsuite/lib/scanoffloadtree.exp
+++ b/gcc/testsuite/lib/scanoffloadtree.exp
@@ -37,11 +37,11 @@ proc scan-offload-tree-dump { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump "offload-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		  [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump "offload-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -62,11 +62,11 @@ proc scan-offload-tree-dump-times { args } {
     }
     if { [llength $args] >= 4 } {
 	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".o" \
-			[lindex $args 3]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".target.mkoffload" \
+	    [lindex $args 3]
     } else {
 	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".target.mkoffload"
     }
 }
 
@@ -87,11 +87,11 @@ proc scan-offload-tree-dump-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-not "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-not "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -113,11 +113,11 @@ proc scan-offload-tree-dump-dem { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-dem "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
     }
 }
 
@@ -138,10 +138,10 @@ proc scan-offload-tree-dump-dem-not { args } {
     }
     if { [llength $args] >= 3 } {
 	scan-dump-dem-not "offload-tree" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-			  [lindex $args 2]
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	    [lindex $args 2]
     } else {
 	scan-dump-dem-not "offload-tree" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
     }
 }
Tobias Burnus June 18, 2020, 12:06 p.m. UTC | #79
On 6/18/20 12:39 PM, Alexandre Oliva wrote:
> Thanks.  I see the main problem besides the dumppfx constness is the
> double dot before target, fixed in the revised patch below.
>
> With this, I think the libgomp testsuite might work with offloading
> again.

Thanks. I have only tried the first one of the list Thomas has sent.

Result as follows – seems to work: PASS :-)
(last but one line: 'scan-…'):

UNSUPPORTED: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0
PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  (test for excess errors)
PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  execution test
PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2   scan-offload-rtl-dump mach "Merging loop .* into "
UNSUPPORTED: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_host=1 -DACC_MEM_SHARED=1 -foffload=disable  -O2

[As previously mentioned, the libgomp OpenACC tests cycle through:
-foffload=nvptx-none + ...=disable  plus the -D… defines.
(That build supports neither amdgcn, hsa nor intelmic.)]

>> and intelmic.
> How does intelmic get into the picture?

No idea – I just know that it counts as offloading platform,
ENABLE_OFFLOAD is set for it (but not for has).
I just wanted to mention it GCC supports it, in principle.
(What I have heard is that it does not exist in silicon but
only as simulator, which can be used for testing with GCC,
but I did not follow this at all.)

>    I looked for a mkoffload
> program for it in the GCC source tree and couldn't find one.  This
> suggests that the addition of -dumpbase to the mkoffload interface might
> require changes elsewhere.

Maybe. I think Thomas is the only one who runs GCC with
emulated intelmic once in a while – thus, he surely knows a bit more about it.
But also Jakub should have an idea.

Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Alexandre Oliva June 19, 2020, 9:53 a.m. UTC | #80
On Jun 18, 2020, Tobias Burnus <tobias@codesourcery.com> wrote:

> Thus, without the offload_target prefix, they would dump into the same file!

Here's an incremental patch, on top of the one you kindly tested the
other day (thanks!), that attempts to introduce per-offload-target dump
name variation.

Could you possibly give it a spin with the offloading targets you've
got?

Thanks in advance,


introduce per-offload-target dumpbase

From: Alexandre Oliva <oliva@gnu.org>


---
 gcc/lto-wrapper.c                     |    5 +---
 gcc/testsuite/lib/scanoffload.exp     |   45 +++++++++++++++++++++++++++++++++
 gcc/testsuite/lib/scanoffloadrtl.exp  |   41 +++++++++++++++---------------
 gcc/testsuite/lib/scanoffloadtree.exp |   41 +++++++++++++++---------------
 libgomp/testsuite/lib/libgomp-dg.exp  |    8 ------
 libgomp/testsuite/lib/libgomp.exp     |    1 +
 6 files changed, 89 insertions(+), 52 deletions(-)
 create mode 100644 gcc/testsuite/lib/scanoffload.exp

diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index e990961..939a83a 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -854,10 +854,7 @@ compile_offload_image (const char *target, const char *compiler_path,
 		 "could not find %s in %s (consider using %<-B%>)",
 		 suffix + 1, compiler_path);
 
-  /* ??? We should probably use the TARGET name instead of "target"
-     here, so as to create different file names for different offload
-     targets.  */
-  dumpbase = concat (dumppfx, "target", NULL);
+  dumpbase = concat (dumppfx, "x", target, NULL);
 
   /* Generate temporary output file name.  */
   if (save_temps)
diff --git a/gcc/testsuite/lib/scanoffload.exp b/gcc/testsuite/lib/scanoffload.exp
new file mode 100644
index 00000000..cbf9fcb
--- /dev/null
+++ b/gcc/testsuite/lib/scanoffload.exp
@@ -0,0 +1,45 @@
+#   Copyright (C) 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Utility for scanning offloading dump output, used by libgomp.exp.
+
+# Format an offload dump suffix given the offload target name in
+# OFFTGT and any suffix, probably empty, in SUFFIX.
+proc scoff-format { offtgt suffix } {
+    return ".x$offtgt.mkoffload$suffix"
+}
+
+# Wrapper for scan procs.
+# Argument 0 is the index of the argument to replace when calling
+# argument 1 with the remaining arguments.  Use end-1 or end or so.
+proc scoff { args } {
+    set idx [lindex $args 0]
+    set prc [lindex $args 1]
+    set args [lreplace $args 0 1]
+
+    global offload_target
+    if [info set offload_target] {
+	set target $offload_target
+	if { "$target" != "disable" } {
+	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
+	}
+    } else {
+	global offload_targets
+	foreach target [split $offload_targets ","] {
+	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
+	}
+    }
+}
diff --git a/gcc/testsuite/lib/scanoffloadrtl.exp b/gcc/testsuite/lib/scanoffloadrtl.exp
index e792450..be457f7 100644
--- a/gcc/testsuite/lib/scanoffloadrtl.exp
+++ b/gcc/testsuite/lib/scanoffloadrtl.exp
@@ -18,6 +18,7 @@
 # libgomp.exp.
 
 load_lib scandump.exp
+load_lib scanoffload.exp
 
 # Utility for scanning compiler result, invoked via dg-final.
 # Call pass if pattern is present, otherwise fail.
@@ -36,12 +37,12 @@ proc scan-offload-rtl-dump { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump "offload-rtl" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	scoff end-1 scan-dump "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
 	    [lindex $args 2]
     } else {
-	scan-dump "offload-rtl" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
+	scoff end scan-dump "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
     }
 }
 
@@ -61,12 +62,12 @@ proc scan-offload-rtl-dump-times { args } {
 	return
     }
     if { [llength $args] >= 4 } {
-	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".target.mkoffload" \
+	scoff end-1 scan-dump-times "offload-rtl" [lindex $args 0] \
+	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" "" \
 			[lindex $args 3]
     } else {
-	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".target.mkoffload"
+	scoff end scan-dump-times "offload-rtl" [lindex $args 0] \
+	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ""
     }
 }
 
@@ -86,12 +87,12 @@ proc scan-offload-rtl-dump-not { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-not "offload-rtl" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	scoff end-1 scan-dump-not "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
 	    [lindex $args 2]
     } else {
-	scan-dump-not "offload-rtl" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
+	scoff end scan-dump-not "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
     }
 }
 
@@ -112,12 +113,12 @@ proc scan-offload-rtl-dump-dem { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-dem "offload-rtl" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	scoff end-1 scan-dump-dem "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
 	    [lindex $args 2]
     } else {
-	scan-dump-dem "offload-rtl" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
+	scoff end scan-dump-dem "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
     }
 }
 
@@ -137,11 +138,11 @@ proc scan-offload-rtl-dump-dem-not { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload" \
+	scoff end-1 scan-dump-dem-not "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
 	    [lindex $args 2]
     } else {
-	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".target.mkoffload"
+	scoff end scan-dump-dem-not "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
     }
 }
diff --git a/gcc/testsuite/lib/scanoffloadtree.exp b/gcc/testsuite/lib/scanoffloadtree.exp
index 3a3b64d2..e51085c 100644
--- a/gcc/testsuite/lib/scanoffloadtree.exp
+++ b/gcc/testsuite/lib/scanoffloadtree.exp
@@ -18,6 +18,7 @@
 # libgomp.exp.
 
 load_lib scandump.exp
+load_lib scanoffload.exp
 
 # Utility for scanning compiler result, invoked via dg-final.
 # Call pass if pattern is present, otherwise fail.
@@ -36,12 +37,12 @@ proc scan-offload-tree-dump { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump "offload-tree" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	scoff end-1 scan-dump "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
 	    [lindex $args 2]
     } else {
-	scan-dump "offload-tree" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
+	scoff end scan-dump "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
     }
 }
 
@@ -61,12 +62,12 @@ proc scan-offload-tree-dump-times { args } {
 	return
     }
     if { [llength $args] >= 4 } {
-	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".target.mkoffload" \
+	scoff end-1 scan-dump-times "offload-tree" [lindex $args 0] \
+	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" "" \
 	    [lindex $args 3]
     } else {
-	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".target.mkoffload"
+	scoff end scan-dump-times "offload-tree" [lindex $args 0] \
+	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ""
     }
 }
 
@@ -86,12 +87,12 @@ proc scan-offload-tree-dump-not { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-not "offload-tree" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	scoff end-1 scan-dump-not "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
 	    [lindex $args 2]
     } else {
-	scan-dump-not "offload-tree" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
+	scoff end scan-dump-not "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
     }
 }
 
@@ -112,12 +113,12 @@ proc scan-offload-tree-dump-dem { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-dem "offload-tree" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	scoff end-1 scan-dump-dem "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
 	    [lindex $args 2]
     } else {
-	scan-dump-dem "offload-tree" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
+	scoff end scan-dump-dem "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
     }
 }
 
@@ -137,11 +138,11 @@ proc scan-offload-tree-dump-dem-not { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-dem-not "offload-tree" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload" \
+	scoff end-1 scan-dump-dem-not "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
 	    [lindex $args 2]
     } else {
-	scan-dump-dem-not "offload-tree" [lindex $args 0] \
-	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".target.mkoffload"
+	scoff end scan-dump-dem-not "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
     }
 }
diff --git a/libgomp/testsuite/lib/libgomp-dg.exp b/libgomp/testsuite/lib/libgomp-dg.exp
index 726b924..ebf78e1 100644
--- a/libgomp/testsuite/lib/libgomp-dg.exp
+++ b/libgomp/testsuite/lib/libgomp-dg.exp
@@ -1,12 +1,4 @@
 proc libgomp-dg-test { prog do_what extra_tool_flags } {
-    # Force the dumpbase for test.c to test.o, such that scan-offload-*-dump
-    # will work.
-    foreach opt $extra_tool_flags {
-	if { [regexp ^-foffload=-fdump- $opt] } {
-	    lappend extra_tool_flags "-save-temps"
-	}
-    }
-
     return [gcc-dg-test-1 libgomp_target_compile $prog $do_what $extra_tool_flags]
 }
 
diff --git a/libgomp/testsuite/lib/libgomp.exp b/libgomp/testsuite/lib/libgomp.exp
index ee5f0e5..8ccb78f4 100644
--- a/libgomp/testsuite/lib/libgomp.exp
+++ b/libgomp/testsuite/lib/libgomp.exp
@@ -30,6 +30,7 @@ load_gcc_lib scanlang.exp
 load_gcc_lib scanrtl.exp
 load_gcc_lib scantree.exp
 load_gcc_lib scanltranstree.exp
+load_gcc_lib scanoffload.exp
 load_gcc_lib scanoffloadtree.exp
 load_gcc_lib scanoffloadrtl.exp
 load_gcc_lib scanipa.exp
Tobias Burnus June 19, 2020, 4:09 p.m. UTC | #81
On 6/19/20 11:53 AM, Alexandre Oliva wrote:

> Here's an incremental patch, on top of the one you kindly tested the
> other day (thanks!), that attempts to introduce per-offload-target dump
> name variation.
>
> Could you possibly give it a spin with the offloading targets you've
> got?

Done; nvptx compiled but for AMDGCN I got a compile error:
in one function 'argv_obstack' was lacking a 'cc_' prefix ('cc_argv_obstack'),
see attached patch (vs. mainline, not vs. either of your patches).

And there is an (unfixed) warning:
config/gcn/mkoffload.c:535:9: warning: unused variable 'dumpbase'

I additionally did run the test case manually → files.log for the
produced files.

Unfortunately, running the testsuite fails now with a tcl error:

ERROR: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2 : error executing dg-final: unknown or ambiguous subcommand "set": must be args, body, class, cmdcount, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars

Thanks,

Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Alexandre Oliva June 22, 2020, 6:08 a.m. UTC | #82
On Jun 19, 2020, Tobias Burnus <Tobias_Burnus@mentor.com> wrote:

> Done; nvptx compiled but for AMDGCN I got a compile error:
> in one function 'argv_obstack' was lacking a 'cc_' prefix ('cc_argv_obstack'),
> see attached patch (vs. mainline, not vs. either of your patches).

Ah, I see, cut&pasto, different obstacks.  Thanks for fixing it.

> And there is an (unfixed) warning:
> config/gcn/mkoffload.c:535:9: warning: unused variable 'dumpbase'

Thanks, I've removed that.

> I additionally did run the test case manually → files.log for the
> produced files.

This is with -save-temps, right?  I've arranged to drop the
no-longer-necessary -save-temps from the test runs, but you didn't get
to experience it because of:

> Unfortunately, running the testsuite fails now with a tcl error:

> : error executing dg-final: unknown or ambiguous subcommand "set":

Interesting, in my test run (native only) I didn't trigger that problem.

+++ b/gcc/testsuite/lib/scanoffload.exp

+    if [info set offload_target] {

The 'set' above should be 'exists'.
Tobias Burnus June 22, 2020, 7:07 a.m. UTC | #83
On 6/22/20 8:08 AM, Alexandre Oliva wrote:
>> I additionally did run the test case manually → files.log for the
>> produced files.
> This is with -save-temps, right?

Yes. Without, there are no files left under /tmp and only
   nvptx-merged-loop.xnvptx-none.mkoffload.309r.mach
   nvptx-merged-loop.exe
in the current directory.
(As in the testsuite, -foffload=-fdump-rtl-mach was used.)

> Interesting, in my test run (native only) I didn't trigger that problem.
> +++ b/gcc/testsuite/lib/scanoffload.exp
> +    if [info set offload_target] {
> The 'set' above should be 'exists'.

UNSUPPORTED: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0
PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  (test for excess errors)
PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  execution test
PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2   scan-offload-rtl-dump mach "Merging loop .* into "
UNSUPPORTED: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c -DACC_DEVICE_TYPE_host=1 -DACC_MEM_SHARED=1 -foffload=disable  -O2

Hence, it looks fine now – given:
/* { dg-do run { target openacc_nvidia_accel_selected } } */
/* { dg-options "-foffload=-fdump-rtl-mach" } */
/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */

Thanks a lot! The dump implementation looks much cleaner now :-)

Cheers,

Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Alexandre Oliva June 22, 2020, 2:32 p.m. UTC | #84
On Jun 22, 2020, Tobias Burnus <tobias@codesourcery.com> wrote:

> On 6/22/20 8:08 AM, Alexandre Oliva wrote:
>>> I additionally did run the test case manually → files.log for the
>>> produced files.
>> This is with -save-temps, right?

> Yes. Without, there are no files left under /tmp and only
>   nvptx-merged-loop.xnvptx-none.mkoffload.309r.mach
>   nvptx-merged-loop.exe
> in the current directory.
> (As in the testsuite, -foffload=-fdump-rtl-mach was used.)

>> Interesting, in my test run (native only) I didn't trigger that problem.
>> +++ b/gcc/testsuite/lib/scanoffload.exp
>> +    if [info set offload_target] {
>> The 'set' above should be 'exists'.

> UNSUPPORTED:
> libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none -O0
> PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none -O2
> (test for excess errors)
> PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none -O2
> execution test
> PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none -O2
> scan-offload-rtl-dump mach "Merging loop .* into "
> UNSUPPORTED:
> libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> -DACC_DEVICE_TYPE_host=1 -DACC_MEM_SHARED=1 -foffload=disable -O2

> Hence, it looks fine now – given:

Yay, thanks.

Here's a consolidated patch, that I've tested myself on x86_64-linux-gnu
(before consolidation, retesting now) with a toolchain build with all of
the offload targets built and enabled, but without cuda or ROCm runtimes
or hardware, only the intelmicemul runtime provided by liboffloadmic.

Ok to install?


handle dumpbase in offloading, adjust testsuite

From: Alexandre Oliva <oliva@adacore.com>

Pass dumpbase on to mkoffloads and their offload-target compiler runs,
using different suffixes for different offloading targets.
Obey -save-temps in naming temporary files while at that.

Adjust the testsuite offload dump scanning machinery to look for dump
files named under the new conventions, iterating internally over all
configured offload targets, or recognizing libgomp's testsuite's own
iteration.


for  gcc/ChangeLog

	* colllect-utils.h (dumppfx): New.
	* colllect-utils.c (dumppfx): Likewise.
	* lto-wrapper.c (run_gcc): Set global dumppfx.
	(compile_offload_image): Pass a -dumpbase on to mkoffload.
	* config/nvptx/mkoffload.c (ptx_dumpbase): New.
	(main): Handle incoming -dumpbase.  Set ptx_dumpbase.  Obey
	save_temps.
	(compile_native): Pass -dumpbase et al to compiler.
	* config/gcn/mkoffload.c (gcn_dumpbase): New.
	(main): Handle incoming -dumpbase.  Set gcn_dumpbase.  Obey
	save_temps.  Pass -dumpbase et al to offload target compiler.
	(compile_native): Pass -dumpbase et al to compiler.

for  gcc/testsuite/ChangeLog

	* lib/scanoffload.exp: New.
	* lib/scanoffloadrtl.exp: Load it.  Replace ".o" with ""
	globally, and use scanoffload's scoff wrapper to fill it in.
	* lib/scanoffloadtree.exp: Likewise.

for libgomp/testsuite/ChangeLog

	* lib/libgomp.exp: Load gcc lib scanoffload.exp.
	* lib/libgomp-dg.exp: Drop now-obsolete -save-temps.
---
 gcc/collect-utils.c                   |    1 +
 gcc/collect-utils.h                   |    1 +
 gcc/config/gcn/mkoffload.c            |   51 ++++++++++++++++++++++++++++++---
 gcc/config/nvptx/mkoffload.c          |   31 +++++++++++++++++++-
 gcc/lto-wrapper.c                     |   13 +++++++-
 gcc/testsuite/lib/scanoffload.exp     |   45 +++++++++++++++++++++++++++++
 gcc/testsuite/lib/scanoffloadrtl.exp  |   49 ++++++++++++++++----------------
 gcc/testsuite/lib/scanoffloadtree.exp |   51 +++++++++++++++++----------------
 libgomp/testsuite/lib/libgomp-dg.exp  |    8 -----
 libgomp/testsuite/lib/libgomp.exp     |    1 +
 10 files changed, 185 insertions(+), 66 deletions(-)
 create mode 100644 gcc/testsuite/lib/scanoffload.exp

diff --git a/gcc/collect-utils.c b/gcc/collect-utils.c
index e85843bc..d4fa2c3 100644
--- a/gcc/collect-utils.c
+++ b/gcc/collect-utils.c
@@ -34,6 +34,7 @@ static char *response_file;
 bool debug;
 bool verbose;
 bool save_temps;
+const char *dumppfx;
 
 
 /* Notify user of a non-error.  */
diff --git a/gcc/collect-utils.h b/gcc/collect-utils.h
index e7c955f..6ff7d9d9 100644
--- a/gcc/collect-utils.h
+++ b/gcc/collect-utils.h
@@ -37,6 +37,7 @@ extern void utils_cleanup (bool);
 extern bool debug;
 extern bool verbose;
 extern bool save_temps;
+extern const char *dumppfx;
 
 /* Provided by the tool itself.  */
 
diff --git a/gcc/config/gcn/mkoffload.c b/gcc/config/gcn/mkoffload.c
index 4a99d70..14f422e 100644
--- a/gcc/config/gcn/mkoffload.c
+++ b/gcc/config/gcn/mkoffload.c
@@ -41,6 +41,7 @@ static const char *gcn_s1_name;
 static const char *gcn_s2_name;
 static const char *gcn_o_name;
 static const char *gcn_cfile_name;
+static const char *gcn_dumpbase;
 
 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
 
@@ -496,6 +497,12 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, gcn_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   switch (offload_abi)
     {
     case OFFLOAD_ABI_LP64:
@@ -611,6 +618,9 @@ main (int argc, char **argv)
 	save_temps = true;
       else if (strcmp (argv[i], "-v") == 0)
 	verbose = true;
+      else if (strcmp (argv[i], "-dumpbase") == 0
+	       && i + 1 < argc)
+	dumppfx = argv[++i];
     }
   if (!(fopenacc ^ fopenmp))
     fatal_error (input_location, "either -fopenacc or -fopenmp must be set");
@@ -628,11 +638,6 @@ main (int argc, char **argv)
       gcc_unreachable ();
     }
 
-  gcn_s1_name = make_temp_file (".mkoffload.1.s");
-  gcn_s2_name = make_temp_file (".mkoffload.2.s");
-  gcn_o_name = make_temp_file (".mkoffload.hsaco");
-  gcn_cfile_name = make_temp_file (".c");
-
   /* Build arguments for compiler pass.  */
   struct obstack cc_argv_obstack;
   obstack_init (&cc_argv_obstack);
@@ -656,6 +661,35 @@ main (int argc, char **argv)
 	obstack_ptr_grow (&cc_argv_obstack, argv[ix]);
     }
 
+  if (!dumppfx)
+    dumppfx = outname;
+
+  const char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
+  const char *hsaco_dumpbase = concat (dumppfx, ".mkoffload.hsaco", NULL);
+  gcn_dumpbase = concat (dumppfx, ".c", NULL);
+
+  if (save_temps)
+    {
+      gcn_s1_name = concat (mko_dumpbase, ".1.s", NULL);
+      gcn_s2_name = concat (mko_dumpbase, ".2.s", NULL);
+      gcn_o_name = hsaco_dumpbase;
+      gcn_cfile_name = gcn_dumpbase;
+    }
+  else
+    {
+      gcn_s1_name = make_temp_file (".mkoffload.1.s");
+      gcn_s2_name = make_temp_file (".mkoffload.2.s");
+      gcn_o_name = make_temp_file (".mkoffload.hsaco");
+      gcn_cfile_name = make_temp_file (".c");
+    }
+
+  obstack_ptr_grow (&cc_argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&cc_argv_obstack, "");
+  obstack_ptr_grow (&cc_argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&cc_argv_obstack, mko_dumpbase);
+  obstack_ptr_grow (&cc_argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&cc_argv_obstack, "");
+
   obstack_ptr_grow (&cc_argv_obstack, "-o");
   obstack_ptr_grow (&cc_argv_obstack, gcn_s1_name);
   obstack_ptr_grow (&cc_argv_obstack, NULL);
@@ -674,6 +708,13 @@ main (int argc, char **argv)
 	|| strncmp (argv[i], "-march", 6) == 0)
       obstack_ptr_grow (&ld_argv_obstack, argv[i]);
 
+  obstack_ptr_grow (&cc_argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&cc_argv_obstack, "");
+  obstack_ptr_grow (&cc_argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&cc_argv_obstack, hsaco_dumpbase);
+  obstack_ptr_grow (&cc_argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&cc_argv_obstack, "");
+
   obstack_ptr_grow (&ld_argv_obstack, "-o");
   obstack_ptr_grow (&ld_argv_obstack, gcn_o_name);
   obstack_ptr_grow (&ld_argv_obstack, NULL);
diff --git a/gcc/config/nvptx/mkoffload.c b/gcc/config/nvptx/mkoffload.c
index 803b585..efdf9b9 100644
--- a/gcc/config/nvptx/mkoffload.c
+++ b/gcc/config/nvptx/mkoffload.c
@@ -55,6 +55,7 @@ static id_map *var_ids, **vars_tail = &var_ids;
 /* Files to unlink.  */
 static const char *ptx_name;
 static const char *ptx_cfile_name;
+static const char *ptx_dumpbase;
 
 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
 
@@ -369,6 +370,12 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, ptx_dumpbase);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   switch (offload_abi)
     {
     case OFFLOAD_ABI_LP64:
@@ -486,6 +493,9 @@ main (int argc, char **argv)
 	save_temps = true;
       else if (strcmp (argv[i], "-v") == 0)
 	verbose = true;
+      else if (strcmp (argv[i], "-dumpbase") == 0
+	       && i + 1 < argc)
+	dumppfx = argv[++i];
     }
   if (!(fopenacc ^ fopenmp))
     fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> "
@@ -521,7 +531,14 @@ main (int argc, char **argv)
 	obstack_ptr_grow (&argv_obstack, argv[ix]);
     }
 
-  ptx_cfile_name = make_temp_file (".c");
+  if (!dumppfx)
+    dumppfx = outname;
+
+  ptx_dumpbase = concat (dumppfx, ".c", NULL);
+  if (save_temps)
+    ptx_cfile_name = ptx_dumpbase;
+  else
+    ptx_cfile_name = make_temp_file (".c");
 
   out = fopen (ptx_cfile_name, "w");
   if (!out)
@@ -531,7 +548,17 @@ main (int argc, char **argv)
      configurations.  */
   if (offload_abi == OFFLOAD_ABI_LP64)
     {
-      ptx_name = make_temp_file (".mkoffload");
+      char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
+      if (save_temps)
+	ptx_name = mko_dumpbase;
+      else
+	ptx_name = make_temp_file (".mkoffload");
+      obstack_ptr_grow (&argv_obstack, "-dumpdir");
+      obstack_ptr_grow (&argv_obstack, "");
+      obstack_ptr_grow (&argv_obstack, "-dumpbase");
+      obstack_ptr_grow (&argv_obstack, mko_dumpbase);
+      obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+      obstack_ptr_grow (&argv_obstack, "");
       obstack_ptr_grow (&argv_obstack, "-o");
       obstack_ptr_grow (&argv_obstack, ptx_name);
       obstack_ptr_grow (&argv_obstack, NULL);
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index 8fbca7c..939a83a 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -830,6 +830,7 @@ compile_offload_image (const char *target, const char *compiler_path,
 		       unsigned int linker_opt_count)
 {
   char *filename = NULL;
+  char *dumpbase;
   char **argv;
   char *suffix
     = XALLOCAVEC (char, sizeof ("/accel//mkoffload") + strlen (target));
@@ -853,8 +854,13 @@ compile_offload_image (const char *target, const char *compiler_path,
 		 "could not find %s in %s (consider using %<-B%>)",
 		 suffix + 1, compiler_path);
 
+  dumpbase = concat (dumppfx, "x", target, NULL);
+
   /* Generate temporary output file name.  */
-  filename = make_temp_file (".target.o");
+  if (save_temps)
+    filename = concat (dumpbase, ".o", NULL);
+  else
+    filename = make_temp_file (".target.o");
 
   struct obstack argv_obstack;
   obstack_init (&argv_obstack);
@@ -875,6 +881,9 @@ compile_offload_image (const char *target, const char *compiler_path,
 			   compiler_opt_count);
   append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
 
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dumpbase);
+
   /* Append options specified by -foffload last.  In case of conflicting
      options we expect offload compiler to choose the latest.  */
   append_offload_options (&argv_obstack, target, compiler_opts,
@@ -1298,7 +1307,7 @@ run_gcc (unsigned argc, char *argv[])
   bool linker_output_rel = false;
   bool skip_debug = false;
   unsigned n_debugobj;
-  const char *dumppfx = NULL, *incoming_dumppfx = NULL;
+  const char *incoming_dumppfx = dumppfx = NULL;
   static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
 
   /* Get the driver and options.  */
diff --git a/gcc/testsuite/lib/scanoffload.exp b/gcc/testsuite/lib/scanoffload.exp
new file mode 100644
index 00000000..ec0d7a6
--- /dev/null
+++ b/gcc/testsuite/lib/scanoffload.exp
@@ -0,0 +1,45 @@
+#   Copyright (C) 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Utility for scanning offloading dump output, used by libgomp.exp.
+
+# Format an offload dump suffix given the offload target name in
+# OFFTGT and any suffix, probably empty, in SUFFIX.
+proc scoff-format { offtgt suffix } {
+    return ".x$offtgt.mkoffload$suffix"
+}
+
+# Wrapper for scan procs.
+# Argument 0 is the index of the argument to replace when calling
+# argument 1 with the remaining arguments.  Use end-1 or end or so.
+proc scoff { args } {
+    set idx [lindex $args 0]
+    set prc [lindex $args 1]
+    set args [lreplace $args 0 1]
+
+    global offload_target
+    if [info exists offload_target] {
+	set target $offload_target
+	if { "$target" != "disable" } {
+	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
+	}
+    } else {
+	global offload_targets
+	foreach target [split $offload_targets ","] {
+	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
+	}
+    }
+}
diff --git a/gcc/testsuite/lib/scanoffloadrtl.exp b/gcc/testsuite/lib/scanoffloadrtl.exp
index 69e4e7c8..be457f7 100644
--- a/gcc/testsuite/lib/scanoffloadrtl.exp
+++ b/gcc/testsuite/lib/scanoffloadrtl.exp
@@ -18,6 +18,7 @@
 # libgomp.exp.
 
 load_lib scandump.exp
+load_lib scanoffload.exp
 
 # Utility for scanning compiler result, invoked via dg-final.
 # Call pass if pattern is present, otherwise fail.
@@ -36,12 +37,12 @@ proc scan-offload-rtl-dump { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump "offload-rtl" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		  [lindex $args 2]
+	scoff end-1 scan-dump "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
+	    [lindex $args 2]
     } else {
-	scan-dump "offload-rtl" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	scoff end scan-dump "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
     }
 }
 
@@ -61,12 +62,12 @@ proc scan-offload-rtl-dump-times { args } {
 	return
     }
     if { [llength $args] >= 4 } {
-	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".o" \
+	scoff end-1 scan-dump-times "offload-rtl" [lindex $args 0] \
+	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" "" \
 			[lindex $args 3]
     } else {
-	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".o"
+	scoff end scan-dump-times "offload-rtl" [lindex $args 0] \
+	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ""
     }
 }
 
@@ -86,12 +87,12 @@ proc scan-offload-rtl-dump-not { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-not "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	scoff end-1 scan-dump-not "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
+	    [lindex $args 2]
     } else {
-	scan-dump-not "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	scoff end scan-dump-not "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
     }
 }
 
@@ -112,12 +113,12 @@ proc scan-offload-rtl-dump-dem { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-dem "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	scoff end-1 scan-dump-dem "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
+	    [lindex $args 2]
     } else {
-	scan-dump-dem "offload-rtl" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	scoff end scan-dump-dem "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
     }
 }
 
@@ -137,11 +138,11 @@ proc scan-offload-rtl-dump-dem-not { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
-			  [lindex $args 2]
+	scoff end-1 scan-dump-dem-not "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
+	    [lindex $args 2]
     } else {
-	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
+	scoff end scan-dump-dem-not "offload-rtl" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
     }
 }
diff --git a/gcc/testsuite/lib/scanoffloadtree.exp b/gcc/testsuite/lib/scanoffloadtree.exp
index 76a28d0..e51085c 100644
--- a/gcc/testsuite/lib/scanoffloadtree.exp
+++ b/gcc/testsuite/lib/scanoffloadtree.exp
@@ -18,6 +18,7 @@
 # libgomp.exp.
 
 load_lib scandump.exp
+load_lib scanoffload.exp
 
 # Utility for scanning compiler result, invoked via dg-final.
 # Call pass if pattern is present, otherwise fail.
@@ -36,12 +37,12 @@ proc scan-offload-tree-dump { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump "offload-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		  [lindex $args 2]
+	scoff end-1 scan-dump "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
+	    [lindex $args 2]
     } else {
-	scan-dump "offload-tree" [lindex $args 0] \
-		  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	scoff end scan-dump "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
     }
 }
 
@@ -61,12 +62,12 @@ proc scan-offload-tree-dump-times { args } {
 	return
     }
     if { [llength $args] >= 4 } {
-	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".o" \
-			[lindex $args 3]
+	scoff end-1 scan-dump-times "offload-tree" [lindex $args 0] \
+	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" "" \
+	    [lindex $args 3]
     } else {
-	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
-			"\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".o"
+	scoff end scan-dump-times "offload-tree" [lindex $args 0] \
+	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ""
     }
 }
 
@@ -86,12 +87,12 @@ proc scan-offload-tree-dump-not { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-not "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	scoff end-1 scan-dump-not "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
+	    [lindex $args 2]
     } else {
-	scan-dump-not "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	scoff end scan-dump-not "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
     }
 }
 
@@ -112,12 +113,12 @@ proc scan-offload-tree-dump-dem { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-dem "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-		      [lindex $args 2]
+	scoff end-1 scan-dump-dem "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
+	    [lindex $args 2]
     } else {
-	scan-dump-dem "offload-tree" [lindex $args 0] \
-		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	scoff end scan-dump-dem "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
     }
 }
 
@@ -137,11 +138,11 @@ proc scan-offload-tree-dump-dem-not { args } {
 	return
     }
     if { [llength $args] >= 3 } {
-	scan-dump-dem-not "offload-tree" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
-			  [lindex $args 2]
+	scoff end-1 scan-dump-dem-not "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
+	    [lindex $args 2]
     } else {
-	scan-dump-dem-not "offload-tree" [lindex $args 0] \
-			  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
+	scoff end scan-dump-dem-not "offload-tree" [lindex $args 0] \
+	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
     }
 }
diff --git a/libgomp/testsuite/lib/libgomp-dg.exp b/libgomp/testsuite/lib/libgomp-dg.exp
index 726b924..ebf78e1 100644
--- a/libgomp/testsuite/lib/libgomp-dg.exp
+++ b/libgomp/testsuite/lib/libgomp-dg.exp
@@ -1,12 +1,4 @@
 proc libgomp-dg-test { prog do_what extra_tool_flags } {
-    # Force the dumpbase for test.c to test.o, such that scan-offload-*-dump
-    # will work.
-    foreach opt $extra_tool_flags {
-	if { [regexp ^-foffload=-fdump- $opt] } {
-	    lappend extra_tool_flags "-save-temps"
-	}
-    }
-
     return [gcc-dg-test-1 libgomp_target_compile $prog $do_what $extra_tool_flags]
 }
 
diff --git a/libgomp/testsuite/lib/libgomp.exp b/libgomp/testsuite/lib/libgomp.exp
index ee5f0e5..8ccb78f4 100644
--- a/libgomp/testsuite/lib/libgomp.exp
+++ b/libgomp/testsuite/lib/libgomp.exp
@@ -30,6 +30,7 @@ load_gcc_lib scanlang.exp
 load_gcc_lib scanrtl.exp
 load_gcc_lib scantree.exp
 load_gcc_lib scanltranstree.exp
+load_gcc_lib scanoffload.exp
 load_gcc_lib scanoffloadtree.exp
 load_gcc_lib scanoffloadrtl.exp
 load_gcc_lib scanipa.exp
Richard Biener June 23, 2020, 8:17 a.m. UTC | #85
On Mon, 22 Jun 2020, Alexandre Oliva wrote:

> On Jun 22, 2020, Tobias Burnus <tobias@codesourcery.com> wrote:
> 
> > On 6/22/20 8:08 AM, Alexandre Oliva wrote:
> >>> I additionally did run the test case manually → files.log for the
> >>> produced files.
> >> This is with -save-temps, right?
> 
> > Yes. Without, there are no files left under /tmp and only
> >   nvptx-merged-loop.xnvptx-none.mkoffload.309r.mach
> >   nvptx-merged-loop.exe
> > in the current directory.
> > (As in the testsuite, -foffload=-fdump-rtl-mach was used.)
> 
> >> Interesting, in my test run (native only) I didn't trigger that problem.
> >> +++ b/gcc/testsuite/lib/scanoffload.exp
> >> +    if [info set offload_target] {
> >> The 'set' above should be 'exists'.
> 
> > UNSUPPORTED:
> > libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> > -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none -O0
> > PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> > -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none -O2
> > (test for excess errors)
> > PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> > -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none -O2
> > execution test
> > PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> > -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none -O2
> > scan-offload-rtl-dump mach "Merging loop .* into "
> > UNSUPPORTED:
> > libgomp.oacc-c/../libgomp.oacc-c-c++-common/nvptx-merged-loop.c
> > -DACC_DEVICE_TYPE_host=1 -DACC_MEM_SHARED=1 -foffload=disable -O2
> 
> > Hence, it looks fine now – given:
> 
> Yay, thanks.
> 
> Here's a consolidated patch, that I've tested myself on x86_64-linux-gnu
> (before consolidation, retesting now) with a toolchain build with all of
> the offload targets built and enabled, but without cuda or ROCm runtimes
> or hardware, only the intelmicemul runtime provided by liboffloadmic.
> 
> Ok to install?

OK.

Thanks,
Richard.

> 
> handle dumpbase in offloading, adjust testsuite
> 
> From: Alexandre Oliva <oliva@adacore.com>
> 
> Pass dumpbase on to mkoffloads and their offload-target compiler runs,
> using different suffixes for different offloading targets.
> Obey -save-temps in naming temporary files while at that.
> 
> Adjust the testsuite offload dump scanning machinery to look for dump
> files named under the new conventions, iterating internally over all
> configured offload targets, or recognizing libgomp's testsuite's own
> iteration.
> 
> 
> for  gcc/ChangeLog
> 
> 	* colllect-utils.h (dumppfx): New.
> 	* colllect-utils.c (dumppfx): Likewise.
> 	* lto-wrapper.c (run_gcc): Set global dumppfx.
> 	(compile_offload_image): Pass a -dumpbase on to mkoffload.
> 	* config/nvptx/mkoffload.c (ptx_dumpbase): New.
> 	(main): Handle incoming -dumpbase.  Set ptx_dumpbase.  Obey
> 	save_temps.
> 	(compile_native): Pass -dumpbase et al to compiler.
> 	* config/gcn/mkoffload.c (gcn_dumpbase): New.
> 	(main): Handle incoming -dumpbase.  Set gcn_dumpbase.  Obey
> 	save_temps.  Pass -dumpbase et al to offload target compiler.
> 	(compile_native): Pass -dumpbase et al to compiler.
> 
> for  gcc/testsuite/ChangeLog
> 
> 	* lib/scanoffload.exp: New.
> 	* lib/scanoffloadrtl.exp: Load it.  Replace ".o" with ""
> 	globally, and use scanoffload's scoff wrapper to fill it in.
> 	* lib/scanoffloadtree.exp: Likewise.
> 
> for libgomp/testsuite/ChangeLog
> 
> 	* lib/libgomp.exp: Load gcc lib scanoffload.exp.
> 	* lib/libgomp-dg.exp: Drop now-obsolete -save-temps.
> ---
>  gcc/collect-utils.c                   |    1 +
>  gcc/collect-utils.h                   |    1 +
>  gcc/config/gcn/mkoffload.c            |   51 ++++++++++++++++++++++++++++++---
>  gcc/config/nvptx/mkoffload.c          |   31 +++++++++++++++++++-
>  gcc/lto-wrapper.c                     |   13 +++++++-
>  gcc/testsuite/lib/scanoffload.exp     |   45 +++++++++++++++++++++++++++++
>  gcc/testsuite/lib/scanoffloadrtl.exp  |   49 ++++++++++++++++----------------
>  gcc/testsuite/lib/scanoffloadtree.exp |   51 +++++++++++++++++----------------
>  libgomp/testsuite/lib/libgomp-dg.exp  |    8 -----
>  libgomp/testsuite/lib/libgomp.exp     |    1 +
>  10 files changed, 185 insertions(+), 66 deletions(-)
>  create mode 100644 gcc/testsuite/lib/scanoffload.exp
> 
> diff --git a/gcc/collect-utils.c b/gcc/collect-utils.c
> index e85843bc..d4fa2c3 100644
> --- a/gcc/collect-utils.c
> +++ b/gcc/collect-utils.c
> @@ -34,6 +34,7 @@ static char *response_file;
>  bool debug;
>  bool verbose;
>  bool save_temps;
> +const char *dumppfx;
>  
>  
>  /* Notify user of a non-error.  */
> diff --git a/gcc/collect-utils.h b/gcc/collect-utils.h
> index e7c955f..6ff7d9d9 100644
> --- a/gcc/collect-utils.h
> +++ b/gcc/collect-utils.h
> @@ -37,6 +37,7 @@ extern void utils_cleanup (bool);
>  extern bool debug;
>  extern bool verbose;
>  extern bool save_temps;
> +extern const char *dumppfx;
>  
>  /* Provided by the tool itself.  */
>  
> diff --git a/gcc/config/gcn/mkoffload.c b/gcc/config/gcn/mkoffload.c
> index 4a99d70..14f422e 100644
> --- a/gcc/config/gcn/mkoffload.c
> +++ b/gcc/config/gcn/mkoffload.c
> @@ -41,6 +41,7 @@ static const char *gcn_s1_name;
>  static const char *gcn_s2_name;
>  static const char *gcn_o_name;
>  static const char *gcn_cfile_name;
> +static const char *gcn_dumpbase;
>  
>  enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
>  
> @@ -496,6 +497,12 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
>      obstack_ptr_grow (&argv_obstack, "-save-temps");
>    if (verbose)
>      obstack_ptr_grow (&argv_obstack, "-v");
> +  obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +  obstack_ptr_grow (&argv_obstack, "");
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&argv_obstack, gcn_dumpbase);
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +  obstack_ptr_grow (&argv_obstack, ".c");
>    switch (offload_abi)
>      {
>      case OFFLOAD_ABI_LP64:
> @@ -611,6 +618,9 @@ main (int argc, char **argv)
>  	save_temps = true;
>        else if (strcmp (argv[i], "-v") == 0)
>  	verbose = true;
> +      else if (strcmp (argv[i], "-dumpbase") == 0
> +	       && i + 1 < argc)
> +	dumppfx = argv[++i];
>      }
>    if (!(fopenacc ^ fopenmp))
>      fatal_error (input_location, "either -fopenacc or -fopenmp must be set");
> @@ -628,11 +638,6 @@ main (int argc, char **argv)
>        gcc_unreachable ();
>      }
>  
> -  gcn_s1_name = make_temp_file (".mkoffload.1.s");
> -  gcn_s2_name = make_temp_file (".mkoffload.2.s");
> -  gcn_o_name = make_temp_file (".mkoffload.hsaco");
> -  gcn_cfile_name = make_temp_file (".c");
> -
>    /* Build arguments for compiler pass.  */
>    struct obstack cc_argv_obstack;
>    obstack_init (&cc_argv_obstack);
> @@ -656,6 +661,35 @@ main (int argc, char **argv)
>  	obstack_ptr_grow (&cc_argv_obstack, argv[ix]);
>      }
>  
> +  if (!dumppfx)
> +    dumppfx = outname;
> +
> +  const char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
> +  const char *hsaco_dumpbase = concat (dumppfx, ".mkoffload.hsaco", NULL);
> +  gcn_dumpbase = concat (dumppfx, ".c", NULL);
> +
> +  if (save_temps)
> +    {
> +      gcn_s1_name = concat (mko_dumpbase, ".1.s", NULL);
> +      gcn_s2_name = concat (mko_dumpbase, ".2.s", NULL);
> +      gcn_o_name = hsaco_dumpbase;
> +      gcn_cfile_name = gcn_dumpbase;
> +    }
> +  else
> +    {
> +      gcn_s1_name = make_temp_file (".mkoffload.1.s");
> +      gcn_s2_name = make_temp_file (".mkoffload.2.s");
> +      gcn_o_name = make_temp_file (".mkoffload.hsaco");
> +      gcn_cfile_name = make_temp_file (".c");
> +    }
> +
> +  obstack_ptr_grow (&cc_argv_obstack, "-dumpdir");
> +  obstack_ptr_grow (&cc_argv_obstack, "");
> +  obstack_ptr_grow (&cc_argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&cc_argv_obstack, mko_dumpbase);
> +  obstack_ptr_grow (&cc_argv_obstack, "-dumpbase-ext");
> +  obstack_ptr_grow (&cc_argv_obstack, "");
> +
>    obstack_ptr_grow (&cc_argv_obstack, "-o");
>    obstack_ptr_grow (&cc_argv_obstack, gcn_s1_name);
>    obstack_ptr_grow (&cc_argv_obstack, NULL);
> @@ -674,6 +708,13 @@ main (int argc, char **argv)
>  	|| strncmp (argv[i], "-march", 6) == 0)
>        obstack_ptr_grow (&ld_argv_obstack, argv[i]);
>  
> +  obstack_ptr_grow (&cc_argv_obstack, "-dumpdir");
> +  obstack_ptr_grow (&cc_argv_obstack, "");
> +  obstack_ptr_grow (&cc_argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&cc_argv_obstack, hsaco_dumpbase);
> +  obstack_ptr_grow (&cc_argv_obstack, "-dumpbase-ext");
> +  obstack_ptr_grow (&cc_argv_obstack, "");
> +
>    obstack_ptr_grow (&ld_argv_obstack, "-o");
>    obstack_ptr_grow (&ld_argv_obstack, gcn_o_name);
>    obstack_ptr_grow (&ld_argv_obstack, NULL);
> diff --git a/gcc/config/nvptx/mkoffload.c b/gcc/config/nvptx/mkoffload.c
> index 803b585..efdf9b9 100644
> --- a/gcc/config/nvptx/mkoffload.c
> +++ b/gcc/config/nvptx/mkoffload.c
> @@ -55,6 +55,7 @@ static id_map *var_ids, **vars_tail = &var_ids;
>  /* Files to unlink.  */
>  static const char *ptx_name;
>  static const char *ptx_cfile_name;
> +static const char *ptx_dumpbase;
>  
>  enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
>  
> @@ -369,6 +370,12 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
>      obstack_ptr_grow (&argv_obstack, "-save-temps");
>    if (verbose)
>      obstack_ptr_grow (&argv_obstack, "-v");
> +  obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +  obstack_ptr_grow (&argv_obstack, "");
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&argv_obstack, ptx_dumpbase);
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +  obstack_ptr_grow (&argv_obstack, ".c");
>    switch (offload_abi)
>      {
>      case OFFLOAD_ABI_LP64:
> @@ -486,6 +493,9 @@ main (int argc, char **argv)
>  	save_temps = true;
>        else if (strcmp (argv[i], "-v") == 0)
>  	verbose = true;
> +      else if (strcmp (argv[i], "-dumpbase") == 0
> +	       && i + 1 < argc)
> +	dumppfx = argv[++i];
>      }
>    if (!(fopenacc ^ fopenmp))
>      fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> "
> @@ -521,7 +531,14 @@ main (int argc, char **argv)
>  	obstack_ptr_grow (&argv_obstack, argv[ix]);
>      }
>  
> -  ptx_cfile_name = make_temp_file (".c");
> +  if (!dumppfx)
> +    dumppfx = outname;
> +
> +  ptx_dumpbase = concat (dumppfx, ".c", NULL);
> +  if (save_temps)
> +    ptx_cfile_name = ptx_dumpbase;
> +  else
> +    ptx_cfile_name = make_temp_file (".c");
>  
>    out = fopen (ptx_cfile_name, "w");
>    if (!out)
> @@ -531,7 +548,17 @@ main (int argc, char **argv)
>       configurations.  */
>    if (offload_abi == OFFLOAD_ABI_LP64)
>      {
> -      ptx_name = make_temp_file (".mkoffload");
> +      char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
> +      if (save_temps)
> +	ptx_name = mko_dumpbase;
> +      else
> +	ptx_name = make_temp_file (".mkoffload");
> +      obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +      obstack_ptr_grow (&argv_obstack, "");
> +      obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +      obstack_ptr_grow (&argv_obstack, mko_dumpbase);
> +      obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +      obstack_ptr_grow (&argv_obstack, "");
>        obstack_ptr_grow (&argv_obstack, "-o");
>        obstack_ptr_grow (&argv_obstack, ptx_name);
>        obstack_ptr_grow (&argv_obstack, NULL);
> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> index 8fbca7c..939a83a 100644
> --- a/gcc/lto-wrapper.c
> +++ b/gcc/lto-wrapper.c
> @@ -830,6 +830,7 @@ compile_offload_image (const char *target, const char *compiler_path,
>  		       unsigned int linker_opt_count)
>  {
>    char *filename = NULL;
> +  char *dumpbase;
>    char **argv;
>    char *suffix
>      = XALLOCAVEC (char, sizeof ("/accel//mkoffload") + strlen (target));
> @@ -853,8 +854,13 @@ compile_offload_image (const char *target, const char *compiler_path,
>  		 "could not find %s in %s (consider using %<-B%>)",
>  		 suffix + 1, compiler_path);
>  
> +  dumpbase = concat (dumppfx, "x", target, NULL);
> +
>    /* Generate temporary output file name.  */
> -  filename = make_temp_file (".target.o");
> +  if (save_temps)
> +    filename = concat (dumpbase, ".o", NULL);
> +  else
> +    filename = make_temp_file (".target.o");
>  
>    struct obstack argv_obstack;
>    obstack_init (&argv_obstack);
> @@ -875,6 +881,9 @@ compile_offload_image (const char *target, const char *compiler_path,
>  			   compiler_opt_count);
>    append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
>  
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&argv_obstack, dumpbase);
> +
>    /* Append options specified by -foffload last.  In case of conflicting
>       options we expect offload compiler to choose the latest.  */
>    append_offload_options (&argv_obstack, target, compiler_opts,
> @@ -1298,7 +1307,7 @@ run_gcc (unsigned argc, char *argv[])
>    bool linker_output_rel = false;
>    bool skip_debug = false;
>    unsigned n_debugobj;
> -  const char *dumppfx = NULL, *incoming_dumppfx = NULL;
> +  const char *incoming_dumppfx = dumppfx = NULL;
>    static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
>  
>    /* Get the driver and options.  */
> diff --git a/gcc/testsuite/lib/scanoffload.exp b/gcc/testsuite/lib/scanoffload.exp
> new file mode 100644
> index 00000000..ec0d7a6
> --- /dev/null
> +++ b/gcc/testsuite/lib/scanoffload.exp
> @@ -0,0 +1,45 @@
> +#   Copyright (C) 2020 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +# 
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +# 
> +# You should have received a copy of the GNU General Public License
> +# along with GCC; see the file COPYING3.  If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +# Utility for scanning offloading dump output, used by libgomp.exp.
> +
> +# Format an offload dump suffix given the offload target name in
> +# OFFTGT and any suffix, probably empty, in SUFFIX.
> +proc scoff-format { offtgt suffix } {
> +    return ".x$offtgt.mkoffload$suffix"
> +}
> +
> +# Wrapper for scan procs.
> +# Argument 0 is the index of the argument to replace when calling
> +# argument 1 with the remaining arguments.  Use end-1 or end or so.
> +proc scoff { args } {
> +    set idx [lindex $args 0]
> +    set prc [lindex $args 1]
> +    set args [lreplace $args 0 1]
> +
> +    global offload_target
> +    if [info exists offload_target] {
> +	set target $offload_target
> +	if { "$target" != "disable" } {
> +	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
> +	}
> +    } else {
> +	global offload_targets
> +	foreach target [split $offload_targets ","] {
> +	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
> +	}
> +    }
> +}
> diff --git a/gcc/testsuite/lib/scanoffloadrtl.exp b/gcc/testsuite/lib/scanoffloadrtl.exp
> index 69e4e7c8..be457f7 100644
> --- a/gcc/testsuite/lib/scanoffloadrtl.exp
> +++ b/gcc/testsuite/lib/scanoffloadrtl.exp
> @@ -18,6 +18,7 @@
>  # libgomp.exp.
>  
>  load_lib scandump.exp
> +load_lib scanoffload.exp
>  
>  # Utility for scanning compiler result, invoked via dg-final.
>  # Call pass if pattern is present, otherwise fail.
> @@ -36,12 +37,12 @@ proc scan-offload-rtl-dump { args } {
>  	return
>      }
>      if { [llength $args] >= 3 } {
> -	scan-dump "offload-rtl" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
> -		  [lindex $args 2]
> +	scoff end-1 scan-dump "offload-rtl" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
> +	    [lindex $args 2]
>      } else {
> -	scan-dump "offload-rtl" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
> +	scoff end scan-dump "offload-rtl" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
>      }
>  }
>  
> @@ -61,12 +62,12 @@ proc scan-offload-rtl-dump-times { args } {
>  	return
>      }
>      if { [llength $args] >= 4 } {
> -	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".o" \
> +	scoff end-1 scan-dump-times "offload-rtl" [lindex $args 0] \
> +	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" "" \
>  			[lindex $args 3]
>      } else {
> -	scan-dump-times "offload-rtl" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ".o"
> +	scoff end scan-dump-times "offload-rtl" [lindex $args 0] \
> +	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 2]" ""
>      }
>  }
>  
> @@ -86,12 +87,12 @@ proc scan-offload-rtl-dump-not { args } {
>  	return
>      }
>      if { [llength $args] >= 3 } {
> -	scan-dump-not "offload-rtl" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
> -		      [lindex $args 2]
> +	scoff end-1 scan-dump-not "offload-rtl" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
> +	    [lindex $args 2]
>      } else {
> -	scan-dump-not "offload-rtl" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
> +	scoff end scan-dump-not "offload-rtl" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
>      }
>  }
>  
> @@ -112,12 +113,12 @@ proc scan-offload-rtl-dump-dem { args } {
>  	return
>      }
>      if { [llength $args] >= 3 } {
> -	scan-dump-dem "offload-rtl" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
> -		      [lindex $args 2]
> +	scoff end-1 scan-dump-dem "offload-rtl" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
> +	    [lindex $args 2]
>      } else {
> -	scan-dump-dem "offload-rtl" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
> +	scoff end scan-dump-dem "offload-rtl" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
>      }
>  }
>  
> @@ -137,11 +138,11 @@ proc scan-offload-rtl-dump-dem-not { args } {
>  	return
>      }
>      if { [llength $args] >= 3 } {
> -	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
> -			  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
> -			  [lindex $args 2]
> +	scoff end-1 scan-dump-dem-not "offload-rtl" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
> +	    [lindex $args 2]
>      } else {
> -	scan-dump-dem-not "offload-rtl" [lindex $args 0] \
> -			  "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
> +	scoff end scan-dump-dem-not "offload-rtl" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
>      }
>  }
> diff --git a/gcc/testsuite/lib/scanoffloadtree.exp b/gcc/testsuite/lib/scanoffloadtree.exp
> index 76a28d0..e51085c 100644
> --- a/gcc/testsuite/lib/scanoffloadtree.exp
> +++ b/gcc/testsuite/lib/scanoffloadtree.exp
> @@ -18,6 +18,7 @@
>  # libgomp.exp.
>  
>  load_lib scandump.exp
> +load_lib scanoffload.exp
>  
>  # Utility for scanning compiler result, invoked via dg-final.
>  # Call pass if pattern is present, otherwise fail.
> @@ -36,12 +37,12 @@ proc scan-offload-tree-dump { args } {
>  	return
>      }
>      if { [llength $args] >= 3 } {
> -	scan-dump "offload-tree" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
> -		  [lindex $args 2]
> +	scoff end-1 scan-dump "offload-tree" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
> +	    [lindex $args 2]
>      } else {
> -	scan-dump "offload-tree" [lindex $args 0] \
> -		  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
> +	scoff end scan-dump "offload-tree" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
>      }
>  }
>  
> @@ -61,12 +62,12 @@ proc scan-offload-tree-dump-times { args } {
>  	return
>      }
>      if { [llength $args] >= 4 } {
> -	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".o" \
> -			[lindex $args 3]
> +	scoff end-1 scan-dump-times "offload-tree" [lindex $args 0] \
> +	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" "" \
> +	    [lindex $args 3]
>      } else {
> -	scan-dump-times "offload-tree" [lindex $args 0] [lindex $args 1] \
> -			"\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ".o"
> +	scoff end scan-dump-times "offload-tree" [lindex $args 0] \
> +	    [lindex $args 1] "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 2]" ""
>      }
>  }
>  
> @@ -86,12 +87,12 @@ proc scan-offload-tree-dump-not { args } {
>  	return
>      }
>      if { [llength $args] >= 3 } {
> -	scan-dump-not "offload-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
> -		      [lindex $args 2]
> +	scoff end-1 scan-dump-not "offload-tree" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
> +	    [lindex $args 2]
>      } else {
> -	scan-dump-not "offload-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
> +	scoff end scan-dump-not "offload-tree" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
>      }
>  }
>  
> @@ -112,12 +113,12 @@ proc scan-offload-tree-dump-dem { args } {
>  	return
>      }
>      if { [llength $args] >= 3 } {
> -	scan-dump-dem "offload-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
> -		      [lindex $args 2]
> +	scoff end-1 scan-dump-dem "offload-tree" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
> +	    [lindex $args 2]
>      } else {
> -	scan-dump-dem "offload-tree" [lindex $args 0] \
> -		      "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
> +	scoff end scan-dump-dem "offload-tree" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
>      }
>  }
>  
> @@ -137,11 +138,11 @@ proc scan-offload-tree-dump-dem-not { args } {
>  	return
>      }
>      if { [llength $args] >= 3 } {
> -	scan-dump-dem-not "offload-tree" [lindex $args 0] \
> -			  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o" \
> -			  [lindex $args 2]
> +	scoff end-1 scan-dump-dem-not "offload-tree" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" "" \
> +	    [lindex $args 2]
>      } else {
> -	scan-dump-dem-not "offload-tree" [lindex $args 0] \
> -			  "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ".o"
> +	scoff end scan-dump-dem-not "offload-tree" [lindex $args 0] \
> +	    "\[0-9\]\[0-9\]\[0-9]t.[lindex $args 1]" ""
>      }
>  }
> diff --git a/libgomp/testsuite/lib/libgomp-dg.exp b/libgomp/testsuite/lib/libgomp-dg.exp
> index 726b924..ebf78e1 100644
> --- a/libgomp/testsuite/lib/libgomp-dg.exp
> +++ b/libgomp/testsuite/lib/libgomp-dg.exp
> @@ -1,12 +1,4 @@
>  proc libgomp-dg-test { prog do_what extra_tool_flags } {
> -    # Force the dumpbase for test.c to test.o, such that scan-offload-*-dump
> -    # will work.
> -    foreach opt $extra_tool_flags {
> -	if { [regexp ^-foffload=-fdump- $opt] } {
> -	    lappend extra_tool_flags "-save-temps"
> -	}
> -    }
> -
>      return [gcc-dg-test-1 libgomp_target_compile $prog $do_what $extra_tool_flags]
>  }
>  
> diff --git a/libgomp/testsuite/lib/libgomp.exp b/libgomp/testsuite/lib/libgomp.exp
> index ee5f0e5..8ccb78f4 100644
> --- a/libgomp/testsuite/lib/libgomp.exp
> +++ b/libgomp/testsuite/lib/libgomp.exp
> @@ -30,6 +30,7 @@ load_gcc_lib scanlang.exp
>  load_gcc_lib scanrtl.exp
>  load_gcc_lib scantree.exp
>  load_gcc_lib scanltranstree.exp
> +load_gcc_lib scanoffload.exp
>  load_gcc_lib scanoffloadtree.exp
>  load_gcc_lib scanoffloadrtl.exp
>  load_gcc_lib scanipa.exp
> 
> 
>
Alexandre Oliva June 23, 2020, 9:44 a.m. UTC | #86
Hello, Thomas,

On Jun  9, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:

> We're trying to scan 'variables.hsail.brig.*', but for input file name
> 'variables.hsail.brig', we're now creating:

I understand this was fixed by Martin Jambor's last week's patch for
brig.exp; can you please confirm whether the problem is fixed?
Alexandre Oliva June 23, 2020, 9:50 a.m. UTC | #87
On Jun  9, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:

> Previously, for '-foffload=nvptx-none -foffload=-fdump-rtl-mach
> -save-temps -o ./nvptx-merged-loop.exe', GCC produced the expected
> 'nvptx-merged-loop.o.307r.mach'.

I believe the patch I've just installed fixes the UNRESOLVED results
caused by not finding dump files.

> Consider 'libgomp.oacc-c-c++-common/pr85381-2.c':

>     /* { dg-additional-options "-save-temps" } */

>     /* { dg-final { scan-assembler-times "bar.sync" 2 } } */

> This expects to scan the PTX offloading compilation assembler code (not
> host code!), expecting that nvptx offloading code assembly is produced
> after the host code, and thus overwrites the latter file.  (Yes, that's
> certainly ugly/fragile...)

I'm afraid this will need further adjusting in the testsuite, as we'll
store the nvptx asm saved aux output in a separate file.
scan-assembler-times will no longer work for this purpose, we'll need
something that knows how to find the offloaded asm.
Martin Jambor June 23, 2020, 11:30 a.m. UTC | #88
Hi,

On Tue, Jun 23 2020, Alexandre Oliva wrote:
> Hello, Thomas,
>
> On Jun  9, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:
>
>> We're trying to scan 'variables.hsail.brig.*', but for input file name
>> 'variables.hsail.brig', we're now creating:
>
> I understand this was fixed by Martin Jambor's last week's patch for
> brig.exp; can you please confirm whether the problem is fixed?
>

I see all but one brig tests passing (I checked out yesterday's master
commit f4670347f10).  The one failure is PR 86948.

Martin
Thomas Schwinge June 30, 2020, 4:07 p.m. UTC | #89
Hi!

Many thanks, Alexandra and Tobias for working this out together!


On 2020-06-23T06:50:26-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> On Jun  9, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:
>
>> Previously, for '-foffload=nvptx-none -foffload=-fdump-rtl-mach
>> -save-temps -o ./nvptx-merged-loop.exe', GCC produced the expected
>> 'nvptx-merged-loop.o.307r.mach'.
>
> I believe the patch I've just installed fixes the UNRESOLVED results
> caused by not finding dump files.

Yes, confirmed, thanks!

A few small issues remain, for those I'll respond elsewhere in this
thread.


>> Consider 'libgomp.oacc-c-c++-common/pr85381-2.c':
>
>>     /* { dg-additional-options "-save-temps" } */
>
>>     /* { dg-final { scan-assembler-times "bar.sync" 2 } } */
>
>> This expects to scan the PTX offloading compilation assembler code (not
>> host code!), expecting that nvptx offloading code assembly is produced
>> after the host code, and thus overwrites the latter file.  (Yes, that's
>> certainly ugly/fragile...)
>
> I'm afraid this will need further adjusting in the testsuite, as we'll
> store the nvptx asm saved aux output in a separate file.
> scan-assembler-times will no longer work for this purpose, we'll need
> something that knows how to find the offloaded asm.

So, that's (now?) easy enough to repair.  I've pushed "[testsuite]
Replace fragile 'scan-assembler' with 'scan-offload-rtl' in
'libgomp.oacc-c-c++-common/pr85381*.c'", see attached.


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Thomas Schwinge June 30, 2020, 4:13 p.m. UTC | #90
Hi!

On 2020-06-18T14:06:10+0200, Tobias Burnus <tobias@codesourcery.com> wrote:
> On 6/18/20 12:39 PM, Alexandre Oliva wrote:
>>> and intelmic.
>> How does intelmic get into the picture?
>
> No idea – I just know that it counts as offloading platform,
> ENABLE_OFFLOAD is set for it (but not for has).
> I just wanted to mention it GCC supports it, in principle.
> (What I have heard is that it does not exist in silicon but
> only as simulator, which can be used for testing with GCC,
> but I did not follow this at all.)
>
>>    I looked for a mkoffload
>> program for it in the GCC source tree and couldn't find one.

See 'gcc/config/i386/intelmic-mkoffload.c'.  ;-)

>> This
>> suggests that the addition of -dumpbase to the mkoffload interface might
>> require changes elsewhere.
>
> Maybe.

:-) Yes, I quickly tested, and found that similar changes are required
there, too.

> I think Thomas is the only one who runs GCC with
> emulated intelmic once in a while – thus, he surely knows a bit more about it.
> But also Jakub should have an idea.

Can you easily adjust that file as you did for the GCN and nvptx
'mkoffload's?  Due to other workload, resolving it myself would be very
low priority for me, I'm afraid.  (But I can easily test anything anybody
else comes up with.)


Grüße
 Thomas
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Thomas Schwinge June 30, 2020, 4:35 p.m. UTC | #91
Hi!

On 2020-06-22T11:32:46-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> Here's a consolidated patch, [...]

Again, many thanks for working through this, with Tobias' help.

> --- /dev/null
> +++ b/gcc/testsuite/lib/scanoffload.exp

> +# Utility for scanning offloading dump output, used by libgomp.exp.

;-) Yeah, I was about to say that having this file in
'gcc/testsuite/lib/' seems to be a bit of an abstraction violation, given
that...

> +# Format an offload dump suffix given the offload target name in
> +# OFFTGT and any suffix, probably empty, in SUFFIX.
> +proc scoff-format { offtgt suffix } {
> +    return ".x$offtgt.mkoffload$suffix"
> +}
> +
> +# Wrapper for scan procs.
> +# Argument 0 is the index of the argument to replace when calling
> +# argument 1 with the remaining arguments.  Use end-1 or end or so.
> +proc scoff { args } {
> +    set idx [lindex $args 0]
> +    set prc [lindex $args 1]
> +    set args [lreplace $args 0 1]
> +
> +    global offload_target
> +    if [info exists offload_target] {
> +     set target $offload_target
> +     if { "$target" != "disable" } {
> +         eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
> +     }
> +    } else {
> +     global offload_targets
> +     foreach target [split $offload_targets ","] {
> +         eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
> +     }
> +    }
> +}

... only libgomp testing defines the 'offload_target', 'offload_targets'
variables.  But anyway, it works, and we've got worse things in GCC.  ;-)

Good idea to indirect this via 'scoff', 'scoff-format'!  This is very
explicit (good) instead of just using some wildcard file name matching --
which would especially be problematic if you've got offload code
generation configured for several offload targets.

> --- a/libgomp/testsuite/lib/libgomp-dg.exp
> +++ b/libgomp/testsuite/lib/libgomp-dg.exp
> @@ -1,12 +1,4 @@
>  proc libgomp-dg-test { prog do_what extra_tool_flags } {
> -    # Force the dumpbase for test.c to test.o, such that scan-offload-*-dump
> -    # will work.
> -    foreach opt $extra_tool_flags {
> -     if { [regexp ^-foffload=-fdump- $opt] } {
> -         lappend extra_tool_flags "-save-temps"
> -     }
> -    }
> -
>      return [gcc-dg-test-1 libgomp_target_compile $prog $do_what $extra_tool_flags]
>  }

Happy to see that hack go away.


I've pushed "[testsuite] Adjust 'scoff' for HSA offloading" to master
branch in commit 01dd58659faae3d6292c458cd9cf96dfd4cf7198, see attached.
"HSA offloading is doing things differently, doesn't use 'mkoffload'", so
we have to skip it in the loop over 'offload_targets'.


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Thomas Schwinge June 30, 2020, 6:52 p.m. UTC | #92
Hi Alexandre!

On 2020-06-22T11:32:46-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> Here's a consolidated patch, [...]

Another small issue here:

> --- /dev/null
> +++ b/gcc/testsuite/lib/scanoffload.exp

> +# Utility for scanning offloading dump output, used by libgomp.exp.
> +
> +# Format an offload dump suffix given the offload target name in
> +# OFFTGT and any suffix, probably empty, in SUFFIX.
> +proc scoff-format { offtgt suffix } {
> +    return ".x$offtgt.mkoffload$suffix"
> +}
> +
> +# Wrapper for scan procs.
> +# Argument 0 is the index of the argument to replace when calling
> +# argument 1 with the remaining arguments.  Use end-1 or end or so.
> +proc scoff { args } {
> +    set idx [lindex $args 0]
> +    set prc [lindex $args 1]
> +    set args [lreplace $args 0 1]
> +
> +    global offload_target
> +    if [info exists offload_target] {
> +     set target $offload_target
> +     if { "$target" != "disable" } {
> +         eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
> +     }
> +    } else {
> +     global offload_targets
> +     foreach target [split $offload_targets ","] {
> +         eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
> +     }
> +    }
> +}

> --- a/gcc/testsuite/lib/scanoffloadrtl.exp
> +++ b/gcc/testsuite/lib/scanoffloadrtl.exp

> @@ -36,12 +37,12 @@ proc scan-offload-rtl-dump { args } {
>       return
>      }
>      if { [llength $args] >= 3 } {
> -     scan-dump "offload-rtl" [lindex $args 0] \
> -               "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o" \
> -               [lindex $args 2]
> +     scoff end-1 scan-dump "offload-rtl" [lindex $args 0] \
> +         "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" "" \
> +         [lindex $args 2]
>      } else {
> -     scan-dump "offload-rtl" [lindex $args 0] \
> -               "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ".o"
> +     scoff end scan-dump "offload-rtl" [lindex $args 0] \
> +         "\[0-9\]\[0-9\]\[0-9]r.[lindex $args 1]" ""
>      }
>  }

> [...]

For example, if there are two 'offload_targets' configured, and you do a:

    { dg-final { scan-offload-tree-dump-times "(?n)^main\\\._omp_fn\\\.0 " 1 "optimized" } }

..., you'll get that reported as:

    PASS: libgomp.c++/scan-offload-1.C scan-offload-tree-dump-times optimized "(?n)^main\\._omp_fn\\.0 " 1
    PASS: libgomp.c++/scan-offload-1.C scan-offload-tree-dump-times optimized "(?n)^main\\._omp_fn\\.0 " 1

Can we easily get the respective offload target into that, or even full
'scoff-format' if that's easier?  I surely could hack up something, but
can you see an elegant way?


Grüße
 Thomas
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Alexandre Oliva July 14, 2020, 4:48 a.m. UTC | #93
Hello, Thomas,

Sorry it took me so long to get back to you.

Thanks for the patches you posted a couple of weeks ago, I'm merging
them into my aux-dump-revamp branch, where I'm accumulating the patches
related with this change.


On Jun 30, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:

> For example, if there are two 'offload_targets' configured, and you do a:

>     PASS: libgomp.c++/scan-offload-1.C scan-offload-tree-dump-times optimized "(?n)^main\\._omp_fn\\.0 " 1
>     PASS: libgomp.c++/scan-offload-1.C scan-offload-tree-dump-times optimized "(?n)^main\\._omp_fn\\.0 " 1

> Can we easily get the respective offload target into that, or even full
> 'scoff-format' if that's easier?  I surely could hack up something, but
> can you see an elegant way?

I'm not sure this is elegant, but...  does it work?
Ok to install if it does?  (I haven't tested it at all)


add offload target to testname for pass/fail message

From: Alexandre Oliva <oliva@adacore.com>

Offload tests that scan dump files may run multiple times, once per
offload target, but the test result messages do not mention the
offload target, so we may seem to have repeated results.  Fixed by
modifying the test name so that it contains the offload target name.


for  gcc/testsuite/ChangeLog

	* lib/scanoffload.exp (scoff-testname, scoff-adjust): New.
	(scoff): Call them.
---
 gcc/testsuite/lib/scanoffload.exp |   17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/lib/scanoffload.exp b/gcc/testsuite/lib/scanoffload.exp
index 1a26e44..397420a 100644
--- a/gcc/testsuite/lib/scanoffload.exp
+++ b/gcc/testsuite/lib/scanoffload.exp
@@ -22,6 +22,19 @@ proc scoff-format { offtgt suffix } {
     return ".x$offtgt.mkoffload$suffix"
 }
 
+# Adjust an offload dump TESTNAME for offload TARGET.
+proc scoff-testname { target testname } {
+    return "$target-$testname"
+}
+
+# Adjust the arglist ARGS, so that argument IDX gets scoff-formatted,
+# and argument 0 (the test name) gets scoff-testnamed.
+proc scoff-adjust { args idx target } {
+    set args [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]"]
+    set args [lreplace $args 0 0 "[scoff-testname $target [lindex $args 0]"]
+    return $args
+}
+
 # Wrapper for scan procs.
 # Argument 0 is the index of the argument to replace when calling
 # argument 1 with the remaining arguments.  Use end-1 or end or so.
@@ -34,7 +47,7 @@ proc scoff { args } {
     if [info exists offload_target] {
 	set target $offload_target
 	if { "$target" != "disable" } {
-	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
+	    eval $prc [scoff-adjust $args $idx $target]
 	}
     } else {
 	global offload_targets
@@ -42,7 +55,7 @@ proc scoff { args } {
 	    # HSA offloading is doing things differently, doesn't use 'mkoffload'.
 	    if { "$target" == "hsa" } continue
 
-	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
+	    eval $prc [scoff-adjust $args $idx $target]
 	}
     }
 }
Alexandre Oliva July 14, 2020, 5:46 a.m. UTC | #94
On Jun 30, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:

>>> I looked for a mkoffload
>>> program for it in the GCC source tree and couldn't find one.

> See 'gcc/config/i386/intelmic-mkoffload.c'.  ;-)

Thanks!

> :-) Yes, I quickly tested, and found that similar changes are required
> there, too.

> Can you easily adjust that file as you did for the GCN and nvptx
> 'mkoffload's?  Due to other workload, resolving it myself would be very
> low priority for me, I'm afraid.  (But I can easily test anything anybody
> else comes up with.)

Thanks for the offer.  Here's what I've been able to come up with,
totally untested.  Ok to install after you give it a spin?


revamp intelmic-mkoffload aux dump names

From: Alexandre Oliva <oliva@adacore.com>

Rework intelmic-mkoffload into the new aux and dump file naming
semantics.  Obey -save-temps.


for  gcc/ChangeLog

	* config/i386/intelmic-mkoffload.c
	(generate_target_descr_file): Use dumppfx for save_temps
	files.  Pass -dumpbase et al down to the compiler.
	(generate_target_offloadend_file): Likewise.
	(generate_host_descr_file): Likewise.
	(prepare_target_image): Likewise.  Move out_obj_filename
	setting...
	(main): ... here.  Detect -dumpbase, set dumppfx too.
---
 gcc/config/i386/intelmic-mkoffload.c |   72 +++++++++++++++++++++++++++++-----
 1 file changed, 62 insertions(+), 10 deletions(-)

diff --git a/gcc/config/i386/intelmic-mkoffload.c b/gcc/config/i386/intelmic-mkoffload.c
index e108bc0..52c06b9 100644
--- a/gcc/config/i386/intelmic-mkoffload.c
+++ b/gcc/config/i386/intelmic-mkoffload.c
@@ -245,8 +245,13 @@ compile_for_target (struct obstack *argv_obstack)
 static const char *
 generate_target_descr_file (const char *target_compiler)
 {
-  const char *src_filename = make_temp_file ("_target_descr.c");
-  const char *obj_filename = make_temp_file ("_target_descr.o");
+  char *dump_filename = concat (dumppfx, "_target_descr.c", NULL);
+  const char *src_filename = save_temps
+    ? dump_filename
+    : make_temp_file ("_target_descr.c");
+  const char *obj_filename = save_temps
+    ? concat (dumppfx, "_target_descr.o", NULL)
+    : make_temp_file ("_target_descr.o");
   temp_files[num_temps++] = src_filename;
   temp_files[num_temps++] = obj_filename;
   FILE *src_file = fopen (src_filename, "w");
@@ -293,6 +298,12 @@ generate_target_descr_file (const char *target_compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dump_filename);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   obstack_ptr_grow (&argv_obstack, "-c");
   obstack_ptr_grow (&argv_obstack, "-shared");
   obstack_ptr_grow (&argv_obstack, "-fPIC");
@@ -309,8 +320,13 @@ generate_target_descr_file (const char *target_compiler)
 static const char *
 generate_target_offloadend_file (const char *target_compiler)
 {
-  const char *src_filename = make_temp_file ("_target_offloadend.c");
-  const char *obj_filename = make_temp_file ("_target_offloadend.o");
+  char *dump_filename = concat (dumppfx, "_target_offloadend.c", NULL);
+  const char *src_filename = save_temps
+    ? dmp_filename
+    : make_temp_file ("_target_offloadend.c");
+  const char *obj_filename = save_temps
+    ? concat (dumppfx, "_target_offloadend.o", NULL)
+    : make_temp_file ("_target_offloadend.o");
   temp_files[num_temps++] = src_filename;
   temp_files[num_temps++] = obj_filename;
   FILE *src_file = fopen (src_filename, "w");
@@ -335,6 +351,12 @@ generate_target_offloadend_file (const char *target_compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dump_filename);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   obstack_ptr_grow (&argv_obstack, "-c");
   obstack_ptr_grow (&argv_obstack, "-shared");
   obstack_ptr_grow (&argv_obstack, "-fPIC");
@@ -350,8 +372,13 @@ generate_target_offloadend_file (const char *target_compiler)
 static const char *
 generate_host_descr_file (const char *host_compiler)
 {
-  const char *src_filename = make_temp_file ("_host_descr.c");
-  const char *obj_filename = make_temp_file ("_host_descr.o");
+  char *dump_filename = concat (dumppfx, "_host_descr.c", NULL);
+  const char *src_filename = save_temps
+    ? dmp_filename
+    : make_temp_file ("_host_descr.c");
+  const char *obj_filename = save_temps
+    ? concat (dumppfx, "_host_descr.o", NULL)
+    : make_temp_file ("_host_descr.o");
   temp_files[num_temps++] = src_filename;
   temp_files[num_temps++] = obj_filename;
   FILE *src_file = fopen (src_filename, "w");
@@ -402,6 +429,12 @@ generate_host_descr_file (const char *host_compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dump_filename);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   obstack_ptr_grow (&argv_obstack, "-c");
   obstack_ptr_grow (&argv_obstack, "-fPIC");
   obstack_ptr_grow (&argv_obstack, "-shared");
@@ -443,7 +476,10 @@ prepare_target_image (const char *target_compiler, int argc, char **argv)
   sprintf (opt1, "-Wl,%s", target_descr_filename);
   sprintf (opt2, "-Wl,%s", target_offloadend_filename);
 
-  const char *target_so_filename = make_temp_file ("_offload_intelmic.so");
+  char *dump_filename = concat (dumppfx, ".mkoffload", NULL);
+  const char *target_so_filename = save_temps
+    ? concat (dumppfx, "_offload_intelmic.so", NULL)
+    : make_temp_file ("_offload_intelmic.so");
   temp_files[num_temps++] = target_so_filename;
   struct obstack argv_obstack;
   obstack_init (&argv_obstack);
@@ -452,17 +488,21 @@ prepare_target_image (const char *target_compiler, int argc, char **argv)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dump_filename);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, "");
   obstack_ptr_grow (&argv_obstack, "-xlto");
   obstack_ptr_grow (&argv_obstack, opt1);
   for (int i = 1; i < argc; i++)
     {
       if (!strcmp (argv[i], "-o") && i + 1 != argc)
-	out_obj_filename = argv[++i];
+	++i;
       else
 	obstack_ptr_grow (&argv_obstack, argv[i]);
     }
-  if (!out_obj_filename)
-    fatal_error (input_location, "output file not specified");
   obstack_ptr_grow (&argv_obstack, opt2);
   /* NB: Put -fPIC and -shared the last to create shared library.  */
   obstack_ptr_grow (&argv_obstack, "-fPIC");
@@ -589,8 +629,20 @@ main (int argc, char **argv)
 	save_temps = true;
       else if (strcmp (argv[i], "-v") == 0)
 	verbose = true;
+      else if (strcmp (argv[i], "-dumpbase") == 0
+	       && i + 1 < argc)
+	dumppfx = argv[++i];
+      else if (strcmp (argv[i], "-o") == 0
+	       && i + 1 < argc)
+	out_obj_filename = argv[++i];
     }
 
+  if (!out_obj_filename)
+    fatal_error (input_location, "output file not specified");
+
+  if (!dumppfx)
+    dumppfx = out_obj_filename;
+
   const char *target_so_filename
     = prepare_target_image (target_compiler, argc, argv);
Alexandre Oliva July 14, 2020, 5:49 a.m. UTC | #95
FWIW, I spotted two bugs in the completely untested patch by running it
through the compiler.  s/dmp_filename/dump_filename/g will fix it.
Thomas Schwinge July 24, 2020, 6:01 a.m. UTC | #96
Hi Alexandre!

On 2020-07-14T01:48:41-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> Sorry it took me so long to get back to you.

Well, likewise.  :-|


> On Jun 30, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:
>
>> For example, if there are two 'offload_targets' configured, and you do a:
>
>>     PASS: libgomp.c++/scan-offload-1.C scan-offload-tree-dump-times optimized "(?n)^main\\._omp_fn\\.0 " 1
>>     PASS: libgomp.c++/scan-offload-1.C scan-offload-tree-dump-times optimized "(?n)^main\\._omp_fn\\.0 " 1
>
>> Can we easily get the respective offload target into that, or even full
>> 'scoff-format' if that's easier?  I surely could hack up something, but
>> can you see an elegant way?
>
> I'm not sure this is elegant, but...  does it work?
> Ok to install if it does?  (I haven't tested it at all)

Looks "good" ;-) to me -- best we can easily get, and certainly good
enough.  We then change as follows:

    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/pr85381.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2   [-scan-offload-rtl-dump-not-]{+scan-nvptx-none-offload-rtl-dump-not+} mach "nvptx_barsync"

..., that is, instead of 'scan-offload-rtl-dump-not' then display
'scan-nvptx-none-offload-rtl-dump-not'.  The latter is no longer the name
of the actual procedure called, but it's close enough.

Please merge in the attached incremental patch to resolve syntax errors.


Grüße
 Thomas


> add offload target to testname for pass/fail message
>
> From: Alexandre Oliva <oliva@adacore.com>
>
> Offload tests that scan dump files may run multiple times, once per
> offload target, but the test result messages do not mention the
> offload target, so we may seem to have repeated results.  Fixed by
> modifying the test name so that it contains the offload target name.
>
>
> for  gcc/testsuite/ChangeLog
>
>       * lib/scanoffload.exp (scoff-testname, scoff-adjust): New.
>       (scoff): Call them.
> ---
>  gcc/testsuite/lib/scanoffload.exp |   17 +++++++++++++++--
>  1 file changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/gcc/testsuite/lib/scanoffload.exp b/gcc/testsuite/lib/scanoffload.exp
> index 1a26e44..397420a 100644
> --- a/gcc/testsuite/lib/scanoffload.exp
> +++ b/gcc/testsuite/lib/scanoffload.exp
> @@ -22,6 +22,19 @@ proc scoff-format { offtgt suffix } {
>      return ".x$offtgt.mkoffload$suffix"
>  }
>
> +# Adjust an offload dump TESTNAME for offload TARGET.
> +proc scoff-testname { target testname } {
> +    return "$target-$testname"
> +}
> +
> +# Adjust the arglist ARGS, so that argument IDX gets scoff-formatted,
> +# and argument 0 (the test name) gets scoff-testnamed.
> +proc scoff-adjust { args idx target } {
> +    set args [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]"]
> +    set args [lreplace $args 0 0 "[scoff-testname $target [lindex $args 0]"]
> +    return $args
> +}
> +
>  # Wrapper for scan procs.
>  # Argument 0 is the index of the argument to replace when calling
>  # argument 1 with the remaining arguments.  Use end-1 or end or so.
> @@ -34,7 +47,7 @@ proc scoff { args } {
>      if [info exists offload_target] {
>       set target $offload_target
>       if { "$target" != "disable" } {
> -         eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
> +         eval $prc [scoff-adjust $args $idx $target]
>       }
>      } else {
>       global offload_targets
> @@ -42,7 +55,7 @@ proc scoff { args } {
>           # HSA offloading is doing things differently, doesn't use 'mkoffload'.
>           if { "$target" == "hsa" } continue
>
> -         eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
> +         eval $prc [scoff-adjust $args $idx $target]
>       }
>      }
>  }


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Thomas Schwinge July 24, 2020, 6:08 a.m. UTC | #97
Hi Alexandre!

On 2020-07-14T02:46:32-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> On Jun 30, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:
>> See 'gcc/config/i386/intelmic-mkoffload.c'.  ;-)

>> Can you easily adjust that file as you did for the GCN and nvptx
>> 'mkoffload's?  Due to other workload, resolving it myself would be very
>> low priority for me, I'm afraid.  (But I can easily test anything anybody
>> else comes up with.)
>
> Thanks for the offer.

Well, thanks for the patch!

> Here's what I've been able to come up with,
> totally untested.  Ok to install after you give it a spin?

Please merge in the attached patch: aside from the typo you've mentioned,
we also need to move the '-dump*' arguments later in one place, so that
they'll override those that appear via the loop over 'argv', which also
contains '-dump*' arguments.  With that changed, it appears to work fine.


Grüße
 Thomas


> revamp intelmic-mkoffload aux dump names
>
> From: Alexandre Oliva <oliva@adacore.com>
>
> Rework intelmic-mkoffload into the new aux and dump file naming
> semantics.  Obey -save-temps.
>
>
> for  gcc/ChangeLog
>
>       * config/i386/intelmic-mkoffload.c
>       (generate_target_descr_file): Use dumppfx for save_temps
>       files.  Pass -dumpbase et al down to the compiler.
>       (generate_target_offloadend_file): Likewise.
>       (generate_host_descr_file): Likewise.
>       (prepare_target_image): Likewise.  Move out_obj_filename
>       setting...
>       (main): ... here.  Detect -dumpbase, set dumppfx too.
> ---
>  gcc/config/i386/intelmic-mkoffload.c |   72 +++++++++++++++++++++++++++++-----
>  1 file changed, 62 insertions(+), 10 deletions(-)
>
> diff --git a/gcc/config/i386/intelmic-mkoffload.c b/gcc/config/i386/intelmic-mkoffload.c
> index e108bc0..52c06b9 100644
> --- a/gcc/config/i386/intelmic-mkoffload.c
> +++ b/gcc/config/i386/intelmic-mkoffload.c
> @@ -245,8 +245,13 @@ compile_for_target (struct obstack *argv_obstack)
>  static const char *
>  generate_target_descr_file (const char *target_compiler)
>  {
> -  const char *src_filename = make_temp_file ("_target_descr.c");
> -  const char *obj_filename = make_temp_file ("_target_descr.o");
> +  char *dump_filename = concat (dumppfx, "_target_descr.c", NULL);
> +  const char *src_filename = save_temps
> +    ? dump_filename
> +    : make_temp_file ("_target_descr.c");
> +  const char *obj_filename = save_temps
> +    ? concat (dumppfx, "_target_descr.o", NULL)
> +    : make_temp_file ("_target_descr.o");
>    temp_files[num_temps++] = src_filename;
>    temp_files[num_temps++] = obj_filename;
>    FILE *src_file = fopen (src_filename, "w");
> @@ -293,6 +298,12 @@ generate_target_descr_file (const char *target_compiler)
>      obstack_ptr_grow (&argv_obstack, "-save-temps");
>    if (verbose)
>      obstack_ptr_grow (&argv_obstack, "-v");
> +  obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +  obstack_ptr_grow (&argv_obstack, "");
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&argv_obstack, dump_filename);
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +  obstack_ptr_grow (&argv_obstack, ".c");
>    obstack_ptr_grow (&argv_obstack, "-c");
>    obstack_ptr_grow (&argv_obstack, "-shared");
>    obstack_ptr_grow (&argv_obstack, "-fPIC");
> @@ -309,8 +320,13 @@ generate_target_descr_file (const char *target_compiler)
>  static const char *
>  generate_target_offloadend_file (const char *target_compiler)
>  {
> -  const char *src_filename = make_temp_file ("_target_offloadend.c");
> -  const char *obj_filename = make_temp_file ("_target_offloadend.o");
> +  char *dump_filename = concat (dumppfx, "_target_offloadend.c", NULL);
> +  const char *src_filename = save_temps
> +    ? dmp_filename
> +    : make_temp_file ("_target_offloadend.c");
> +  const char *obj_filename = save_temps
> +    ? concat (dumppfx, "_target_offloadend.o", NULL)
> +    : make_temp_file ("_target_offloadend.o");
>    temp_files[num_temps++] = src_filename;
>    temp_files[num_temps++] = obj_filename;
>    FILE *src_file = fopen (src_filename, "w");
> @@ -335,6 +351,12 @@ generate_target_offloadend_file (const char *target_compiler)
>      obstack_ptr_grow (&argv_obstack, "-save-temps");
>    if (verbose)
>      obstack_ptr_grow (&argv_obstack, "-v");
> +  obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +  obstack_ptr_grow (&argv_obstack, "");
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&argv_obstack, dump_filename);
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +  obstack_ptr_grow (&argv_obstack, ".c");
>    obstack_ptr_grow (&argv_obstack, "-c");
>    obstack_ptr_grow (&argv_obstack, "-shared");
>    obstack_ptr_grow (&argv_obstack, "-fPIC");
> @@ -350,8 +372,13 @@ generate_target_offloadend_file (const char *target_compiler)
>  static const char *
>  generate_host_descr_file (const char *host_compiler)
>  {
> -  const char *src_filename = make_temp_file ("_host_descr.c");
> -  const char *obj_filename = make_temp_file ("_host_descr.o");
> +  char *dump_filename = concat (dumppfx, "_host_descr.c", NULL);
> +  const char *src_filename = save_temps
> +    ? dmp_filename
> +    : make_temp_file ("_host_descr.c");
> +  const char *obj_filename = save_temps
> +    ? concat (dumppfx, "_host_descr.o", NULL)
> +    : make_temp_file ("_host_descr.o");
>    temp_files[num_temps++] = src_filename;
>    temp_files[num_temps++] = obj_filename;
>    FILE *src_file = fopen (src_filename, "w");
> @@ -402,6 +429,12 @@ generate_host_descr_file (const char *host_compiler)
>      obstack_ptr_grow (&argv_obstack, "-save-temps");
>    if (verbose)
>      obstack_ptr_grow (&argv_obstack, "-v");
> +  obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +  obstack_ptr_grow (&argv_obstack, "");
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&argv_obstack, dump_filename);
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +  obstack_ptr_grow (&argv_obstack, ".c");
>    obstack_ptr_grow (&argv_obstack, "-c");
>    obstack_ptr_grow (&argv_obstack, "-fPIC");
>    obstack_ptr_grow (&argv_obstack, "-shared");
> @@ -443,7 +476,10 @@ prepare_target_image (const char *target_compiler, int argc, char **argv)
>    sprintf (opt1, "-Wl,%s", target_descr_filename);
>    sprintf (opt2, "-Wl,%s", target_offloadend_filename);
>
> -  const char *target_so_filename = make_temp_file ("_offload_intelmic.so");
> +  char *dump_filename = concat (dumppfx, ".mkoffload", NULL);
> +  const char *target_so_filename = save_temps
> +    ? concat (dumppfx, "_offload_intelmic.so", NULL)
> +    : make_temp_file ("_offload_intelmic.so");
>    temp_files[num_temps++] = target_so_filename;
>    struct obstack argv_obstack;
>    obstack_init (&argv_obstack);
> @@ -452,17 +488,21 @@ prepare_target_image (const char *target_compiler, int argc, char **argv)
>      obstack_ptr_grow (&argv_obstack, "-save-temps");
>    if (verbose)
>      obstack_ptr_grow (&argv_obstack, "-v");
> +  obstack_ptr_grow (&argv_obstack, "-dumpdir");
> +  obstack_ptr_grow (&argv_obstack, "");
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase");
> +  obstack_ptr_grow (&argv_obstack, dump_filename);
> +  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
> +  obstack_ptr_grow (&argv_obstack, "");
>    obstack_ptr_grow (&argv_obstack, "-xlto");
>    obstack_ptr_grow (&argv_obstack, opt1);
>    for (int i = 1; i < argc; i++)
>      {
>        if (!strcmp (argv[i], "-o") && i + 1 != argc)
> -     out_obj_filename = argv[++i];
> +     ++i;
>        else
>       obstack_ptr_grow (&argv_obstack, argv[i]);
>      }
> -  if (!out_obj_filename)
> -    fatal_error (input_location, "output file not specified");
>    obstack_ptr_grow (&argv_obstack, opt2);
>    /* NB: Put -fPIC and -shared the last to create shared library.  */
>    obstack_ptr_grow (&argv_obstack, "-fPIC");
> @@ -589,8 +629,20 @@ main (int argc, char **argv)
>       save_temps = true;
>        else if (strcmp (argv[i], "-v") == 0)
>       verbose = true;
> +      else if (strcmp (argv[i], "-dumpbase") == 0
> +            && i + 1 < argc)
> +     dumppfx = argv[++i];
> +      else if (strcmp (argv[i], "-o") == 0
> +            && i + 1 < argc)
> +     out_obj_filename = argv[++i];
>      }
>
> +  if (!out_obj_filename)
> +    fatal_error (input_location, "output file not specified");
> +
> +  if (!dumppfx)
> +    dumppfx = out_obj_filename;
> +
>    const char *target_so_filename
>      = prepare_target_image (target_compiler, argc, argv);
>


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Thomas Schwinge July 24, 2020, 12:06 p.m. UTC | #98
Hi!

On 2020-06-30T18:35:36+0200, I wrote:
> On 2020-06-22T11:32:46-0300, Alexandre Oliva <oliva@adacore.com> wrote:
>> --- /dev/null
>> +++ b/gcc/testsuite/lib/scanoffload.exp
>
>> +# Utility for scanning offloading dump output, used by libgomp.exp.
>
> ;-) Yeah, I was about to say that having this file in
> 'gcc/testsuite/lib/' seems to be a bit of an abstraction violation, given
> that...
>
>> +# Format an offload dump suffix given the offload target name in
>> +# OFFTGT and any suffix, probably empty, in SUFFIX.
>> +proc scoff-format { offtgt suffix } {
>> +    return ".x$offtgt.mkoffload$suffix"
>> +}
>> +
>> +# Wrapper for scan procs.
>> +# Argument 0 is the index of the argument to replace when calling
>> +# argument 1 with the remaining arguments.  Use end-1 or end or so.
>> +proc scoff { args } {
>> +    set idx [lindex $args 0]
>> +    set prc [lindex $args 1]
>> +    set args [lreplace $args 0 1]
>> +
>> +    global offload_target
>> +    if [info exists offload_target] {
>> +    set target $offload_target
>> +    if { "$target" != "disable" } {
>> +        eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
>> +    }
>> +    } else {
>> +    global offload_targets
>> +    foreach target [split $offload_targets ","] {
>> +        eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
>> +    }
>> +    }
>> +}
>
> ... only libgomp testing defines the 'offload_target', 'offload_targets'
> variables.  But anyway, it works, and we've got worse things in GCC.  ;-)

Actually, there is one problem.  To cure it, I've pushed commit
fdc9db25395e5a6e77069c04fe713f165a9c52a4 "[testsuite] Unset
'offload_target' after use" to master branch, see attached.


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Alexandre Oliva July 24, 2020, 5:54 p.m. UTC | #99
On Jul 24, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:

> we also need to move the '-dump*' arguments later in one place, so that
> they'll override those that appear via the loop over 'argv', which also
> contains '-dump*' arguments.  With that changed, it appears to work fine.

Aah, thanks.  Here's the combined patch for this subthread, that I'm
installing shortly.


revamp intelmic-mkoffload aux dump names

From: Alexandre Oliva <oliva@adacore.com>

Rework intelmic-mkoffload into the new aux and dump file naming
semantics.  Obey -save-temps.


Co-Authored-By: Thomas Schwinge <thomas@codesourcery.com>
for  gcc/ChangeLog

	* config/i386/intelmic-mkoffload.c
	(generate_target_descr_file): Use dumppfx for save_temps
	files.  Pass -dumpbase et al down to the compiler.
	(generate_target_offloadend_file): Likewise.
	(generate_host_descr_file): Likewise.
	(prepare_target_image): Likewise.  Move out_obj_filename
	setting...
	(main): ... here.  Detect -dumpbase, set dumppfx too.
---
 gcc/config/i386/intelmic-mkoffload.c |   72 +++++++++++++++++++++++++++++-----
 1 file changed, 62 insertions(+), 10 deletions(-)

diff --git a/gcc/config/i386/intelmic-mkoffload.c b/gcc/config/i386/intelmic-mkoffload.c
index e108bc0..15b5c3d 100644
--- a/gcc/config/i386/intelmic-mkoffload.c
+++ b/gcc/config/i386/intelmic-mkoffload.c
@@ -245,8 +245,13 @@ compile_for_target (struct obstack *argv_obstack)
 static const char *
 generate_target_descr_file (const char *target_compiler)
 {
-  const char *src_filename = make_temp_file ("_target_descr.c");
-  const char *obj_filename = make_temp_file ("_target_descr.o");
+  char *dump_filename = concat (dumppfx, "_target_descr.c", NULL);
+  const char *src_filename = save_temps
+    ? dump_filename
+    : make_temp_file ("_target_descr.c");
+  const char *obj_filename = save_temps
+    ? concat (dumppfx, "_target_descr.o", NULL)
+    : make_temp_file ("_target_descr.o");
   temp_files[num_temps++] = src_filename;
   temp_files[num_temps++] = obj_filename;
   FILE *src_file = fopen (src_filename, "w");
@@ -293,6 +298,12 @@ generate_target_descr_file (const char *target_compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dump_filename);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   obstack_ptr_grow (&argv_obstack, "-c");
   obstack_ptr_grow (&argv_obstack, "-shared");
   obstack_ptr_grow (&argv_obstack, "-fPIC");
@@ -309,8 +320,13 @@ generate_target_descr_file (const char *target_compiler)
 static const char *
 generate_target_offloadend_file (const char *target_compiler)
 {
-  const char *src_filename = make_temp_file ("_target_offloadend.c");
-  const char *obj_filename = make_temp_file ("_target_offloadend.o");
+  char *dump_filename = concat (dumppfx, "_target_offloadend.c", NULL);
+  const char *src_filename = save_temps
+    ? dump_filename
+    : make_temp_file ("_target_offloadend.c");
+  const char *obj_filename = save_temps
+    ? concat (dumppfx, "_target_offloadend.o", NULL)
+    : make_temp_file ("_target_offloadend.o");
   temp_files[num_temps++] = src_filename;
   temp_files[num_temps++] = obj_filename;
   FILE *src_file = fopen (src_filename, "w");
@@ -335,6 +351,12 @@ generate_target_offloadend_file (const char *target_compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dump_filename);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   obstack_ptr_grow (&argv_obstack, "-c");
   obstack_ptr_grow (&argv_obstack, "-shared");
   obstack_ptr_grow (&argv_obstack, "-fPIC");
@@ -350,8 +372,13 @@ generate_target_offloadend_file (const char *target_compiler)
 static const char *
 generate_host_descr_file (const char *host_compiler)
 {
-  const char *src_filename = make_temp_file ("_host_descr.c");
-  const char *obj_filename = make_temp_file ("_host_descr.o");
+  char *dump_filename = concat (dumppfx, "_host_descr.c", NULL);
+  const char *src_filename = save_temps
+    ? dump_filename
+    : make_temp_file ("_host_descr.c");
+  const char *obj_filename = save_temps
+    ? concat (dumppfx, "_host_descr.o", NULL)
+    : make_temp_file ("_host_descr.o");
   temp_files[num_temps++] = src_filename;
   temp_files[num_temps++] = obj_filename;
   FILE *src_file = fopen (src_filename, "w");
@@ -402,6 +429,12 @@ generate_host_descr_file (const char *host_compiler)
     obstack_ptr_grow (&argv_obstack, "-save-temps");
   if (verbose)
     obstack_ptr_grow (&argv_obstack, "-v");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dump_filename);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, ".c");
   obstack_ptr_grow (&argv_obstack, "-c");
   obstack_ptr_grow (&argv_obstack, "-fPIC");
   obstack_ptr_grow (&argv_obstack, "-shared");
@@ -443,7 +476,10 @@ prepare_target_image (const char *target_compiler, int argc, char **argv)
   sprintf (opt1, "-Wl,%s", target_descr_filename);
   sprintf (opt2, "-Wl,%s", target_offloadend_filename);
 
-  const char *target_so_filename = make_temp_file ("_offload_intelmic.so");
+  char *dump_filename = concat (dumppfx, ".mkoffload", NULL);
+  const char *target_so_filename = save_temps
+    ? concat (dumppfx, "_offload_intelmic.so", NULL)
+    : make_temp_file ("_offload_intelmic.so");
   temp_files[num_temps++] = target_so_filename;
   struct obstack argv_obstack;
   obstack_init (&argv_obstack);
@@ -457,16 +493,20 @@ prepare_target_image (const char *target_compiler, int argc, char **argv)
   for (int i = 1; i < argc; i++)
     {
       if (!strcmp (argv[i], "-o") && i + 1 != argc)
-	out_obj_filename = argv[++i];
+	++i;
       else
 	obstack_ptr_grow (&argv_obstack, argv[i]);
     }
-  if (!out_obj_filename)
-    fatal_error (input_location, "output file not specified");
   obstack_ptr_grow (&argv_obstack, opt2);
   /* NB: Put -fPIC and -shared the last to create shared library.  */
   obstack_ptr_grow (&argv_obstack, "-fPIC");
   obstack_ptr_grow (&argv_obstack, "-shared");
+  obstack_ptr_grow (&argv_obstack, "-dumpdir");
+  obstack_ptr_grow (&argv_obstack, "");
+  obstack_ptr_grow (&argv_obstack, "-dumpbase");
+  obstack_ptr_grow (&argv_obstack, dump_filename);
+  obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
+  obstack_ptr_grow (&argv_obstack, "");
   obstack_ptr_grow (&argv_obstack, "-o");
   obstack_ptr_grow (&argv_obstack, target_so_filename);
   compile_for_target (&argv_obstack);
@@ -589,8 +629,20 @@ main (int argc, char **argv)
 	save_temps = true;
       else if (strcmp (argv[i], "-v") == 0)
 	verbose = true;
+      else if (strcmp (argv[i], "-dumpbase") == 0
+	       && i + 1 < argc)
+	dumppfx = argv[++i];
+      else if (strcmp (argv[i], "-o") == 0
+	       && i + 1 < argc)
+	out_obj_filename = argv[++i];
     }
 
+  if (!out_obj_filename)
+    fatal_error (input_location, "output file not specified");
+
+  if (!dumppfx)
+    dumppfx = out_obj_filename;
+
   const char *target_so_filename
     = prepare_target_image (target_compiler, argc, argv);
Alexandre Oliva July 24, 2020, 6 p.m. UTC | #100
On Jul 24, 2020, Thomas Schwinge <thomas@codesourcery.com> wrote:

> Please merge in the attached incremental patch to resolve syntax errors.

Thanks, sorry about those.  I found out about lset after I posted the
proposed patch, and I switched to it over set from [lreplace] to avoid
further embarrassing myself ;-) That was no use: it was in the same
lines that were missing the closing brackets, and yet I didn't spot
them :-/

I gave this a round of testing with my attempt at a multi-offload-target
toolchain, but I'm not entirely sure any of the actual offloading tests
run far enough as to exercise this code, since I see complaints about
missing the actual hardware in the dejagnu logs.  So please let me know
if you run into any issues with this minor incremental change.

Here's what I'm installing shortly.  Thanks again,


add offload target to testname for pass/fail message

From: Alexandre Oliva <oliva@adacore.com>

Offload tests that scan dump files may run multiple times, once per
offload target, but the test result messages do not mention the
offload target, so we may seem to have repeated results.  Fixed by
modifying the test name so that it contains the offload target name.


Co-Authored-By: Thomas Schwinge <thomas@codesourcery.com>
for  gcc/testsuite/ChangeLog

	* lib/scanoffload.exp (scoff-testname, scoff-adjust): New.
	(scoff): Call them.
---
 gcc/testsuite/lib/scanoffload.exp |   17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/lib/scanoffload.exp b/gcc/testsuite/lib/scanoffload.exp
index 1a26e44..9071769 100644
--- a/gcc/testsuite/lib/scanoffload.exp
+++ b/gcc/testsuite/lib/scanoffload.exp
@@ -22,6 +22,19 @@ proc scoff-format { offtgt suffix } {
     return ".x$offtgt.mkoffload$suffix"
 }
 
+# Adjust an offload dump TESTNAME for offload TARGET.
+proc scoff-testname { target testname } {
+    return "$target-$testname"
+}
+
+# Adjust the arglist ARGS, so that argument IDX gets scoff-formatted,
+# and argument 0 (the test name) gets scoff-testnamed.
+proc scoff-adjust { args idx target } {
+    lset args $idx "[scoff-format $target [lindex $args $idx]]"
+    lset args 0 "[scoff-testname $target [lindex $args 0]]"
+    return $args
+}
+
 # Wrapper for scan procs.
 # Argument 0 is the index of the argument to replace when calling
 # argument 1 with the remaining arguments.  Use end-1 or end or so.
@@ -34,7 +47,7 @@ proc scoff { args } {
     if [info exists offload_target] {
 	set target $offload_target
 	if { "$target" != "disable" } {
-	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
+	    eval $prc [scoff-adjust $args $idx $target]
 	}
     } else {
 	global offload_targets
@@ -42,7 +55,7 @@ proc scoff { args } {
 	    # HSA offloading is doing things differently, doesn't use 'mkoffload'.
 	    if { "$target" == "hsa" } continue
 
-	    eval $prc [lreplace $args $idx $idx "[scoff-format $target [lindex $args $idx]]"]
+	    eval $prc [scoff-adjust $args $idx $target]
 	}
     }
 }
diff mbox series

Patch

diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 4abd4d5708a54..d68b37384ff7f 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -54,9 +54,6 @@ 
 #include "ada-tree.h"
 #include "gigi.h"
 
-/* This symbol needs to be defined for the front-end.  */
-void *callgraph_info_file = NULL;
-
 /* Command-line argc and argv.  These variables are global since they are
    imported in back_end.adb.  */
 unsigned int save_argc;
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5d811f113c907..bd302383377ba 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5406,6 +5406,10 @@  expand_builtin_alloca (tree exp)
     = allocate_dynamic_stack_space (op0, 0, align, max_size, alloca_for_var);
   result = convert_memory_address (ptr_mode, result);
 
+  /* Dynamic allocations for variables are recorded during gimplification.  */
+  if (!alloca_for_var && (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC))
+    record_dynamic_alloc (exp);
+
   return result;
 }
 
diff --git a/gcc/calls.c b/gcc/calls.c
index ae904473d0dc6..67c7c77598a3f 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -3759,6 +3759,9 @@  expand_call (tree exp, rtx target, int ignore)
 
   preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
 
+  if (flag_callgraph_info)
+    record_final_call (fndecl, EXPR_LOCATION (exp));
+
   /* We want to make two insn chains; one for a sibling call, the other
      for a normal call.  We will select one of the two chains after
      initial RTL generation is complete.  */
@@ -5343,6 +5346,9 @@  emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
   before_call = get_last_insn ();
 
+  if (flag_callgraph_info)
+    record_final_call (SYMBOL_REF_DECL (orgfun), UNKNOWN_LOCATION);
+
   /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
      will set inhibit_defer_pop to that value.  */
   /* The return type is needed to decide how many bytes the function pops.
diff --git a/gcc/common.opt b/gcc/common.opt
index cc279f411d796..63d646fba2b42 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1091,6 +1091,14 @@  fbtr-bb-exclusive
 Common Ignore
 Does nothing.  Preserved for backward compatibility.
 
+fcallgraph-info
+Common Report RejectNegative Var(flag_callgraph_info) Init(NO_CALLGRAPH_INFO);
+Output callgraph information on a per-file basis
+
+fcallgraph-info=
+Common Report RejectNegative Joined
+Output callgraph information on a per-file basis with decorations
+
 fcall-saved-
 Common Joined RejectNegative Var(common_deferred_options) Defer
 -fcall-saved-<register>	Mark <register> as being preserved across functions.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1407d019d1404..545b842eade71 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -583,8 +583,9 @@  Objective-C and Objective-C++ Dialects}.
 @item Developer Options
 @xref{Developer Options,,GCC Developer Options}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
--dumpfullversion  -fchecking  -fchecking=@var{n}  -fdbg-cnt-list @gol
--fdbg-cnt=@var{counter-value-list} @gol
+-dumpfullversion  -fcallgraph-info@r{[}=su,da@r{]}
+-fchecking  -fchecking=@var{n}
+-fdbg-cnt-list @gol  -fdbg-cnt=@var{counter-value-list} @gol
 -fdisable-ipa-@var{pass_name} @gol
 -fdisable-rtl-@var{pass_name} @gol
 -fdisable-rtl-@var{pass-name}=@var{range-list} @gol
@@ -14533,6 +14534,18 @@  The files are created in the directory of the output file.
 
 @table @gcctabopt
 
+@item -fcallgraph-info
+@itemx -fcallgraph-info=@var{MARKERS}
+@opindex fcallgraph-info
+Makes the compiler output callgraph information for the program, on a
+per-file basis.  The information is generated in the common VCG format.
+It can be decorated with additional, per-node and/or per-edge information,
+if a list of comma-separated markers is additionally specified.  When the
+@code{su} marker is specified, the callgraph is decorated with stack usage
+information; it is equivalent to @option{-fstack-usage}.  When the @code{da}
+marker is specified, the callgraph is decorated with information about
+dynamically allocated objects.
+
 @item -d@var{letters}
 @itemx -fdump-rtl-@var{pass}
 @itemx -fdump-rtl-@var{pass}=@var{filename}
diff --git a/gcc/explow.c b/gcc/explow.c
index 7eb854bca4a6d..83c786366c1aa 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -38,6 +38,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "dojump.h"
 #include "explow.h"
 #include "expr.h"
+#include "stringpool.h"
 #include "common/common-target.h"
 #include "output.h"
 #include "params.h"
@@ -1611,6 +1612,10 @@  set_stack_check_libfunc (const char *libfunc_name)
 {
   gcc_assert (stack_check_libfunc == NULL_RTX);
   stack_check_libfunc = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
+  tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+			  get_identifier (libfunc_name), void_type_node);
+  DECL_EXTERNAL (decl) = 1;
+  SET_SYMBOL_REF_DECL (stack_check_libfunc, decl);
 }
 
 /* Emit one stack probe at ADDRESS, an address within the stack.  */
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index a2103282d469d..b23d3a271f1ee 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -200,6 +200,22 @@  enum stack_check_type
   FULL_BUILTIN_STACK_CHECK
 };
 
+/* Type of callgraph information.  */
+enum callgraph_info_type
+{
+  /* No information.  */
+  NO_CALLGRAPH_INFO = 0,
+
+  /* Naked callgraph.  */
+  CALLGRAPH_INFO_NAKED = 1,
+
+  /* Callgraph decorated with stack usage information.  */
+  CALLGRAPH_INFO_STACK_USAGE = 2,
+
+  /* Callgraph decoration with dynamic allocation information.  */
+  CALLGRAPH_INFO_DYNAMIC_ALLOC = 4
+};
+
 /* Floating-point contraction mode.  */
 enum fp_contract_mode {
   FP_CONTRACT_OFF = 0,
diff --git a/gcc/function.c b/gcc/function.c
index a1c76a4dd7a84..152f927097c47 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4725,6 +4725,16 @@  get_last_funcdef_no (void)
   return funcdef_no;
 }
 
+/* Allocate and initialize the stack usage info data structure for the
+   current function.  */
+static void
+allocate_stack_usage_info (void)
+{
+  gcc_assert (!cfun->su);
+  cfun->su = ggc_cleared_alloc<stack_usage> ();
+  cfun->su->static_stack_size = -1;
+}
+
 /* Allocate a function structure for FNDECL and set its contents
    to the defaults.  Set cfun to the newly-allocated object.
    Some of the helper functions invoked during initialization assume
@@ -4802,6 +4812,9 @@  allocate_struct_function (tree fndecl, bool abstract_p)
 
       if (!profile_flag && !flag_instrument_function_entry_exit)
 	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
+
+      if (flag_callgraph_info)
+	allocate_stack_usage_info ();
     }
 
   /* Don't enable begin stmt markers if var-tracking at assignments is
@@ -4846,11 +4859,8 @@  prepare_function_start (void)
   init_expr ();
   default_rtl_profile ();
 
-  if (flag_stack_usage_info)
-    {
-      cfun->su = ggc_cleared_alloc<stack_usage> ();
-      cfun->su->static_stack_size = -1;
-    }
+  if (flag_stack_usage_info && !flag_callgraph_info)
+    allocate_stack_usage_info ();
 
   cse_not_expected = ! optimize;
 
@@ -6373,12 +6383,51 @@  rest_of_handle_thread_prologue_and_epilogue (void)
   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
 
   /* The stack usage info is finalized during prologue expansion.  */
-  if (flag_stack_usage_info)
-    output_stack_usage ();
+  if (flag_stack_usage_info || flag_callgraph_info)
+    {
+      output_stack_usage ();
+      vec_free (cfun->su->dallocs);
+      cfun->su->dallocs = NULL;
+      vec_free (cfun->su->callees);
+      cfun->su->callees = NULL;
+    }
 
   return 0;
 }
 
+/* Record a final call to CALLEE at LOCATION.  */
+
+void
+record_final_call (tree callee, location_t location)
+{
+  struct callee datum = { location, callee };
+  vec_safe_push (cfun->su->callees, datum);
+}
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+
+void
+record_dynamic_alloc (tree decl_or_exp)
+{
+  struct dalloc datum;
+
+  if (DECL_P (decl_or_exp))
+    {
+      datum.location = DECL_SOURCE_LOCATION (decl_or_exp);
+      const char *name = lang_hooks.decl_printable_name (decl_or_exp, 2);
+      const char *dot = strrchr (name, '.');
+      if (dot)
+	name = dot + 1;
+      datum.name = ggc_strdup (name);
+    }
+  else
+    {
+      datum.location = EXPR_LOCATION (decl_or_exp);
+      datum.name = NULL;
+    }
+  vec_safe_push (cfun->su->dallocs, datum);
+}
+
 namespace {
 
 const pass_data pass_data_thread_prologue_and_epilogue =
diff --git a/gcc/function.h b/gcc/function.h
index 43ac5dffd2457..ec523765d6eec 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -192,6 +192,18 @@  public:
   poly_int64 length;
 };
 
+struct GTY(()) callee
+{
+  location_t location;
+  tree decl;
+};
+
+struct GTY(()) dalloc
+{
+  location_t location;
+  char const *name;
+};
+
 class GTY(()) stack_usage
 {
 public:
@@ -210,6 +222,13 @@  public:
   /* Nonzero if the amount of stack space allocated dynamically cannot
      be bounded at compile-time.  */
   unsigned int has_unbounded_dynamic_stack_size : 1;
+
+  /* Functions called within the function, if callgraph is enabled.  */
+  vec<callee, va_gc> *callees;
+
+  /* Dynamic allocations enocuntered within the function, if callgraph
+     da is enabled.  */
+  vec<dalloc, va_gc> *dallocs;
 };
 
 #define current_function_static_stack_size (cfun->su->static_stack_size)
@@ -406,6 +425,12 @@  void add_local_decl (struct function *fun, tree d);
 #define FOR_EACH_LOCAL_DECL(FUN, I, D)		\
   FOR_EACH_VEC_SAFE_ELT_REVERSE ((FUN)->local_decls, I, D)
 
+/* Record a final call to CALLEE at LOCATION.  */
+void record_final_call (tree callee, location_t location);
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+void record_dynamic_alloc (tree decl_or_exp);
+
 /* If va_list_[gf]pr_size is set to this, it means we don't know how
    many units need to be saved.  */
 #define VA_LIST_MAX_GPR_SIZE	255
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 914bb8eb8d699..394f0fda9c98c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1697,6 +1697,10 @@  gimplify_vla_decl (tree decl, gimple_seq *seq_p)
   t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
 
   gimplify_and_add (t, seq_p);
+
+  /* Record the dynamic allocation associated with DECL if requested.  */
+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+    record_dynamic_alloc (decl);
 }
 
 /* A helper function to be called via walk_tree.  Mark all labels under *TP
diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c
index ef43dae12fb64..8916f7e4da0bb 100644
--- a/gcc/optabs-libfuncs.c
+++ b/gcc/optabs-libfuncs.c
@@ -735,10 +735,6 @@  build_libfunc_function_visibility (const char *name, symbol_visibility vis)
   DECL_VISIBILITY_SPECIFIED (decl) = 1;
   gcc_assert (DECL_ASSEMBLER_NAME (decl));
 
-  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
-     are the flags assigned by targetm.encode_section_info.  */
-  SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
-
   return decl;
 }
 
diff --git a/gcc/opts.c b/gcc/opts.c
index 10b9f108f8d06..f46b468a968e7 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2433,6 +2433,32 @@  common_handle_option (struct gcc_options *opts,
       /* Deferred.  */
       break;
 
+    case OPT_fcallgraph_info:
+      opts->x_flag_callgraph_info = CALLGRAPH_INFO_NAKED;
+      break;
+
+    case OPT_fcallgraph_info_:
+      {
+	char *my_arg, *p;
+	my_arg = xstrdup (arg);
+	p = strtok (my_arg, ",");
+	while (p)
+	  {
+	    if (strcmp (p, "su") == 0)
+	      {
+		opts->x_flag_callgraph_info |= CALLGRAPH_INFO_STACK_USAGE;
+		opts->x_flag_stack_usage_info = true;
+	      }
+	    else if (strcmp (p, "da") == 0)
+	      opts->x_flag_callgraph_info |= CALLGRAPH_INFO_DYNAMIC_ALLOC;
+	    else
+	      return 0;
+	    p = strtok (NULL, ",");
+	  }
+	free (my_arg);
+      }
+      break;
+
     case OPT_fdiagnostics_show_location_:
       diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value;
       break;
diff --git a/gcc/output.h b/gcc/output.h
index 835d63556e6a8..6cccada4aeb1d 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -604,7 +604,7 @@  extern int maybe_assemble_visibility (tree);
 
 extern int default_address_cost (rtx, machine_mode, addr_space_t, bool);
 
-/* Output stack usage information.  */
+/* Stack usage.  */
 extern void output_stack_usage (void);
 
 #endif /* ! GCC_OUTPUT_H */
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 6dcbb2dcb1369..bd09ec4d7a7af 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -1035,6 +1035,82 @@  print_node (FILE *file, const char *prefix, tree node, int indent,
   fprintf (file, ">");
 }
 
+/* Print the identifier for DECL according to FLAGS.  */
+
+void
+print_decl_identifier (FILE *file, tree decl, int flags)
+{
+  bool needs_colon = false;
+  const char *name;
+  char c;
+
+  if (flags & PRINT_DECL_ORIGIN)
+    {
+      if (DECL_IS_BUILTIN (decl))
+	fputs ("<built-in>", file);
+      else
+	{
+	  expanded_location loc
+	    = expand_location (DECL_SOURCE_LOCATION (decl));
+	  fprintf (file, "%s:%d:%d", loc.file, loc.line, loc.column);
+	}
+      needs_colon = true;
+    }
+
+  if (flags & PRINT_DECL_UNIQUE_NAME)
+    {
+      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+      if (!TREE_PUBLIC (decl)
+	  || (DECL_WEAK (decl) && !DECL_EXTERNAL (decl)))
+	/* The symbol has internal or weak linkage so its assembler name
+	   is not necessarily unique among the compilation units of the
+	   program.  We therefore have to further mangle it.  But we can't
+	   simply use DECL_SOURCE_FILE because it contains the name of the
+	   file the symbol originates from so, e.g. for function templates
+	   in C++ where the templates are defined in a header file, we can
+	   have symbols with the same assembler name and DECL_SOURCE_FILE.
+	   That's why we use the name of the top-level source file of the
+	   compilation unit.  ??? Unnecessary for Ada.  */
+	name = ACONCAT ((main_input_filename, ":", name, NULL));
+    }
+  else if (flags & PRINT_DECL_NAME)
+    {
+      /* We don't want to print the full qualified name because it can be long,
+	 so we strip the scope prefix, but we may need to deal with the suffix
+	 created by the compiler.  */
+      const char *suffix = strchr (IDENTIFIER_POINTER (DECL_NAME (decl)), '.');
+      name = lang_hooks.decl_printable_name (decl, 2);
+      if (suffix)
+	{
+	  const char *dot = strchr (name, '.');
+	  while (dot && strcasecmp (dot, suffix) != 0)
+	    {
+	      name = dot + 1;
+	      dot = strchr (name, '.');
+	    }
+	}
+      else
+	{
+	  const char *dot = strrchr (name, '.');
+	  if (dot)
+	    name = dot + 1;
+	}
+    }
+  else
+    return;
+
+  if (needs_colon)
+    fputc (':', file);
+
+  while ((c = *name++) != '\0')
+    {
+      /* Strip double-quotes because of VCG.  */
+      if (c == '"')
+	continue;
+      fputc (c, file);
+    }
+}
+
 
 /* Print the node NODE on standard error, for debugging.
    Most nodes referred to by this one are printed recursively
diff --git a/gcc/print-tree.h b/gcc/print-tree.h
index 1d4fe6e8950cc..cbea48c486e3c 100644
--- a/gcc/print-tree.h
+++ b/gcc/print-tree.h
@@ -42,5 +42,9 @@  extern void print_node (FILE *, const char *, tree, int,
 extern void print_node_brief (FILE *, const char *, const_tree, int);
 extern void indent_to (FILE *, int);
 #endif
+#define PRINT_DECL_ORIGIN       0x1
+#define PRINT_DECL_NAME         0x2
+#define PRINT_DECL_UNIQUE_NAME  0x4
+extern void print_decl_identifier (FILE *, tree, int flags);
 
 #endif  // GCC_PRINT_TREE_H
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 1c7002f5c37cd..016f6d688f324 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -84,6 +84,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "dumpfile.h"
 #include "ipa-fnsummary.h"
 #include "dump-context.h"
+#include "print-tree.h"
 #include "optinfo-emit-json.h"
 
 #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
@@ -174,6 +175,8 @@  const char *user_label_prefix;
 
 FILE *asm_out_file;
 FILE *aux_info_file;
+FILE *callgraph_info_file = NULL;
+static bool callgraph_info_indirect_emitted = false;
 FILE *stack_usage_file = NULL;
 
 /* The current working directory of a translation.  It's generally the
@@ -913,8 +916,8 @@  alloc_for_identifier_to_locale (size_t len)
 }
 
 /* Output stack usage information.  */
-void
-output_stack_usage (void)
+static void
+output_stack_usage_1 (FILE *cf)
 {
   static bool warning_issued = false;
   enum stack_usage_kind_type { STATIC = 0, DYNAMIC, DYNAMIC_BOUNDED };
@@ -970,41 +973,22 @@  output_stack_usage (void)
       stack_usage += current_function_dynamic_stack_size;
     }
 
-  if (stack_usage_file)
+  if (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE)
     {
-      expanded_location loc
-	= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
-      /* We don't want to print the full qualified name because it can be long,
-	 so we strip the scope prefix, but we may need to deal with the suffix
-	 created by the compiler.  */
-      const char *suffix
-	= strchr (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), '.');
-      const char *name
-	= lang_hooks.decl_printable_name (current_function_decl, 2);
-      if (suffix)
-	{
-	  const char *dot = strchr (name, '.');
-	  while (dot && strcasecmp (dot, suffix) != 0)
-	    {
-	      name = dot + 1;
-	      dot = strchr (name, '.');
-	    }
-	}
+      if (stack_usage)
+	fprintf (cf, "\\n" HOST_WIDE_INT_PRINT_DEC " bytes (%s)",
+		 stack_usage,
+		 stack_usage_kind_str[stack_usage_kind]);
       else
-	{
-	  const char *dot = strrchr (name, '.');
-	  if (dot)
-	    name = dot + 1;
-	}
+	fputs ("\\n0 bytes", cf);
+    }
 
-      fprintf (stack_usage_file,
-	       "%s:%d:%d:%s\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
-	       loc.file == NULL ? "(artificial)" : lbasename (loc.file),
-	       loc.line,
-	       loc.column,
-	       name,
-	       stack_usage,
-	       stack_usage_kind_str[stack_usage_kind]);
+  if (stack_usage_file)
+    {
+      print_decl_identifier (stack_usage_file, current_function_decl,
+			     PRINT_DECL_ORIGIN | PRINT_DECL_NAME);
+      fprintf (stack_usage_file, "\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
+	       stack_usage, stack_usage_kind_str[stack_usage_kind]);
     }
 
   if (warn_stack_usage >= 0 && warn_stack_usage < HOST_WIDE_INT_MAX)
@@ -1026,6 +1010,106 @@  output_stack_usage (void)
     }
 }
 
+/* Dump placeholder node for indirect calls in VCG format.  */
+
+#define INDIRECT_CALL_NAME  "__indirect_call"
+
+static void
+dump_final_indirect_call_node_vcg (FILE *f)
+{
+  if (callgraph_info_indirect_emitted)
+    return;
+
+  fputs ("node: { title: \"", f);
+  fputs (INDIRECT_CALL_NAME, f);
+  fputs ("\" label: \"", f);
+  fputs ("Indirect Call Placeholder", f);
+  fputs ("\" shape : ellipse }\n", f);
+  callgraph_info_indirect_emitted = true;
+}
+
+/* Dump final cgraph edge in VCG format.  */
+
+static void
+dump_final_callee_vcg (FILE *f, struct callee *callee)
+{
+  fputs ("edge: { sourcename: \"", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_UNIQUE_NAME);
+  fputs ("\" targetname: \"", f);
+  if (callee->decl)
+    print_decl_identifier (f, callee->decl, PRINT_DECL_UNIQUE_NAME);
+  else
+    fputs (INDIRECT_CALL_NAME, f);
+  if (LOCATION_LOCUS (callee->location) != UNKNOWN_LOCATION)
+    {
+      expanded_location loc;
+      fputs ("\" label: \"", f);
+      loc = expand_location (callee->location);
+      fprintf (f, "%s:%d:%d", loc.file, loc.line, loc.column);
+    }
+  fputs ("\" }\n", f);
+
+  if (!callee->decl)
+    dump_final_indirect_call_node_vcg (f);
+}
+
+/* Dump final cgraph node in VCG format.  */
+
+static void
+dump_final_node_vcg (FILE *f)
+{
+  fputs ("node: { title: \"", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_UNIQUE_NAME);
+  fputs ("\" label: \"", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_NAME);
+  fputs ("\\n", f);
+  print_decl_identifier (f, current_function_decl, PRINT_DECL_ORIGIN);
+
+  if (DECL_EXTERNAL (current_function_decl))
+    {
+      fputs ("\" shape : ellipse }\n", f);
+      return;
+    }
+
+  if (flag_stack_usage_info
+      || (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE))
+    output_stack_usage_1 (f);
+
+  if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+    {
+      fprintf (f, "\\n%u dynamic objects", vec_safe_length (cfun->su->dallocs));
+
+      unsigned i;
+      dalloc *cda;
+      FOR_EACH_VEC_SAFE_ELT (cfun->su->dallocs, i, cda)
+	{
+	  expanded_location loc = expand_location (cda->location);
+	  fprintf (f, "\\n %s", cda->name);
+	  fprintf (f, " %s:%d:%d", loc.file, loc.line, loc.column);
+	}
+    }
+
+  fputs ("\" }\n", f);
+
+  if (flag_callgraph_info)
+    {
+      unsigned i;
+      callee *c;
+      FOR_EACH_VEC_SAFE_ELT (cfun->su->callees, i, c)
+	dump_final_callee_vcg (f, c);
+    }
+}
+
+/* Output stack usage and callgraph info, as requested.  */
+void
+output_stack_usage (void)
+{
+  if (flag_callgraph_info)
+    dump_final_node_vcg (callgraph_info_file);
+  else
+    output_stack_usage_1 (NULL);
+}
+
 /* Open an auxiliary output file.  */
 static FILE *
 open_auxiliary_file (const char *ext)
@@ -1900,6 +1984,15 @@  lang_dependent_init (const char *name)
       /* If stack usage information is desired, open the output file.  */
       if (flag_stack_usage && !flag_generate_lto)
 	stack_usage_file = open_auxiliary_file ("su");
+
+      /* If call graph information is desired, open the output file.  */
+      if (flag_callgraph_info && !flag_generate_lto)
+	{
+	  callgraph_info_file = open_auxiliary_file ("ci");
+	  /* Write the file header.  */
+	  fprintf (callgraph_info_file,
+		   "graph: { title: \"%s\"\n", main_input_filename);
+	}
     }
 
   /* This creates various _DECL nodes, so needs to be called after the
@@ -2044,6 +2137,14 @@  finalize (bool no_backend)
       stack_usage_file = NULL;
     }
 
+  if (callgraph_info_file)
+    {
+      fputs ("}\n", callgraph_info_file);
+      fclose (callgraph_info_file);
+      callgraph_info_file = NULL;
+      callgraph_info_indirect_emitted = false;
+    }
+
   if (seen_error ())
     coverage_remove_note_file ();