diff mbox

RFC: -fasm-show-source

Message ID 1470947688-31641-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Aug. 11, 2016, 8:34 p.m. UTC
I sometimes find myself scouring assembler output from the compiler
and trying to figure out which instructions correspond to which
lines of source code; I believe this is a common activity for some
end-users.

The following patch adds a new -fasm-show-source option, which
emits comments into the generated asm showing the pertinent
line of source code, whenever it changes.  It uses the same logic
as debug_hooks->source_line for tracking this (for handling
line-based breakpoints).

An example can be seen in the invoke.texi part of the patch.  As
noted there, it's aimed at end-users, rather than gcc developers.
The example shows a relatively short function; the option is
likely to be much more useful for longer functions.

I think it would further improve usability if this option were enabled
by default when the final output is .s (either via -S, or by "-o foo.s").
Ideas on how to implement that (in the driver) would be welcome - I
started looking at the spec-handling code, but thought I'd post the
idea here first, before diving in too deeply.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu; adds
2 PASS results to gcc.sum.

Thoughts?  OK for trunk as-is?

gcc/ChangeLog:
	* common.opt (fasm-show-source): New option.
	* doc/invoke.texi (Code Generation Options): Add
	-fasm-show-source.
	(-fasm-show-source): New item.
	* final.c (asm_show_source): New function.
	(final_scan_insn): Call asm_show_source.

gcc/testsuite/ChangeLog:
	* gcc.dg/fasm-show-source-1.c: New test case.
---
 gcc/common.opt                            |  5 +++
 gcc/doc/invoke.texi                       | 71 ++++++++++++++++++++++++++++++-
 gcc/final.c                               | 29 ++++++++++++-
 gcc/testsuite/gcc.dg/fasm-show-source-1.c | 15 +++++++
 4 files changed, 117 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/fasm-show-source-1.c

Comments

Sandra Loosemore Aug. 12, 2016, 2 a.m. UTC | #1
On 08/11/2016 02:34 PM, David Malcolm wrote:
> I sometimes find myself scouring assembler output from the compiler
> and trying to figure out which instructions correspond to which
> lines of source code; I believe this is a common activity for some
> end-users.
>
> The following patch adds a new -fasm-show-source option, which
> emits comments into the generated asm showing the pertinent
> line of source code, whenever it changes.  It uses the same logic
> as debug_hooks->source_line for tracking this (for handling
> line-based breakpoints).
>
> An example can be seen in the invoke.texi part of the patch.  As
> noted there, it's aimed at end-users, rather than gcc developers.
> The example shows a relatively short function; the option is
> likely to be much more useful for longer functions.
>
> I think it would further improve usability if this option were enabled
> by default when the final output is .s (either via -S, or by "-o foo.s").
> Ideas on how to implement that (in the driver) would be welcome - I
> started looking at the spec-handling code, but thought I'd post the
> idea here first, before diving in too deeply.
>
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu; adds
> 2 PASS results to gcc.sum.
>
> Thoughts?  OK for trunk as-is?

Why not extend the existing -fverbose-asm to do this?  E.g. 
-fverbose-asm=source, or something like that.  Otherwise you need to 
cross-reference the documentation for the two options and explain how 
they interact (or don't interact, as the case may be).

-Sandra
Prathamesh Kulkarni Aug. 12, 2016, 5:30 a.m. UTC | #2
On 12 August 2016 at 02:04, David Malcolm <dmalcolm@redhat.com> wrote:
> I sometimes find myself scouring assembler output from the compiler
> and trying to figure out which instructions correspond to which
> lines of source code; I believe this is a common activity for some
> end-users.
Hi David,
I usually use gcc -g -Wa,-adhln to trace C source from the assembly.
I tried your example and it gave more or less a similar output (attached).
However the source mapping with your patch looks better.

Thanks,
Prathamesh
>
> The following patch adds a new -fasm-show-source option, which
> emits comments into the generated asm showing the pertinent
> line of source code, whenever it changes.  It uses the same logic
> as debug_hooks->source_line for tracking this (for handling
> line-based breakpoints).
>
> An example can be seen in the invoke.texi part of the patch.  As
> noted there, it's aimed at end-users, rather than gcc developers.
> The example shows a relatively short function; the option is
> likely to be much more useful for longer functions.
>
> I think it would further improve usability if this option were enabled
> by default when the final output is .s (either via -S, or by "-o foo.s").
> Ideas on how to implement that (in the driver) would be welcome - I
> started looking at the spec-handling code, but thought I'd post the
> idea here first, before diving in too deeply.
>
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu; adds
> 2 PASS results to gcc.sum.
>
> Thoughts?  OK for trunk as-is?
>
> gcc/ChangeLog:
>         * common.opt (fasm-show-source): New option.
>         * doc/invoke.texi (Code Generation Options): Add
>         -fasm-show-source.
>         (-fasm-show-source): New item.
>         * final.c (asm_show_source): New function.
>         (final_scan_insn): Call asm_show_source.
>
> gcc/testsuite/ChangeLog:
>         * gcc.dg/fasm-show-source-1.c: New test case.
> ---
>  gcc/common.opt                            |  5 +++
>  gcc/doc/invoke.texi                       | 71 ++++++++++++++++++++++++++++++-
>  gcc/final.c                               | 29 ++++++++++++-
>  gcc/testsuite/gcc.dg/fasm-show-source-1.c | 15 +++++++
>  4 files changed, 117 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/fasm-show-source-1.c
>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 8a292ed..56ce513 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -939,6 +939,11 @@ fargument-noalias-anything
>  Common Ignore
>  Does nothing. Preserved for backward compatibility.
>
> +fasm-show-source
> +Common Var(flag_asm_show_source)
> +Emit comments in the generated assembly code to show the source code
> +lines associated with the assembly instructions.
> +
>  fsanitize=
>  Common Driver Report Joined
>  Select what to sanitize.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 22001f9..dc3d3ad 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -486,7 +486,8 @@ Objective-C and Objective-C++ Dialects}.
>
>  @item Code Generation Options
>  @xref{Code Gen Options,,Options for Code Generation Conventions}.
> -@gccoptlist{-fcall-saved-@var{reg}  -fcall-used-@var{reg} @gol
> +@gccoptlist{-fasm-show-source @gol
> +-fcall-saved-@var{reg}  -fcall-used-@var{reg} @gol
>  -ffixed-@var{reg}  -fexceptions @gol
>  -fnon-call-exceptions  -fdelete-dead-exceptions  -funwind-tables @gol
>  -fasynchronous-unwind-tables @gol
> @@ -11153,6 +11154,74 @@ can figure out the other form by either removing @samp{no-} or adding
>  it.
>
>  @table @gcctabopt
> +@item -fasm-show-source
> +@opindex fasm-show-source
> +Emit comments in the generated assembly code to show the source code
> +lines associated with the assembly instructions.  This option is
> +aimed at end-users who wish to better understand the relationship
> +between their source code and the generated machine code.
> +
> +The comments are of the form FILENAME:LINENUMBER:CONTENT OF LINE.
> +
> +For example, given this C source file:
> +
> +@smallexample
> +int test (int n)
> +@{
> +  int i;
> +  int total = 0;
> +
> +  for (i = 0; i < n; i++)
> +    total += i * i;
> +
> +  return total;
> +@}
> +@end smallexample
> +
> +compiling to (x86_64) assembly via @option{-S} and emitting the result
> +direct to stdout via @option{-o} @option{-}
> +
> +@smallexample
> +gcc -S test.c -fasm-show-source -Os -o -
> +@end smallexample
> +
> +gives output similar to this, highlighting which instructions correspond
> +to the various parts of the loop:
> +
> +@smallexample
> +       .file   "test.c"
> +       .text
> +       .globl  test
> +       .type   test, @@function
> +test:
> +.LFB0:
> +       .cfi_startproc
> +# test.c:4:   int total = 0;
> +       xorl    %eax, %eax
> +# test.c:6:   for (i = 0; i < n; i++)
> +       xorl    %edx, %edx
> +.L2:
> +# test.c:6:   for (i = 0; i < n; i++)
> +       cmpl    %edi, %edx
> +       jge     .L5
> +# test.c:7:     total += i * i;
> +       movl    %edx, %ecx
> +       imull   %edx, %ecx
> +# test.c:6:   for (i = 0; i < n; i++)
> +       incl    %edx
> +# test.c:7:     total += i * i;
> +       addl    %ecx, %eax
> +       jmp     .L2
> +.L5:
> +# test.c:10: @}
> +       ret
> +       .cfi_endproc
> +.LFE0:
> +       .size   test, .-test
> +       .ident  "GCC: (GNU) 7.0.0 20160809 (experimental)"
> +       .section        .note.GNU-stack,"",@@progbits
> +@end smallexample
> +
>  @item -fstack-reuse=@var{reuse-level}
>  @opindex fstack_reuse
>  This option controls stack space reuse for user declared local/auto variables
> diff --git a/gcc/final.c b/gcc/final.c
> index 5b04311..09bf0b7 100644
> --- a/gcc/final.c
> +++ b/gcc/final.c
> @@ -2140,6 +2140,27 @@ call_from_call_insn (rtx_call_insn *insn)
>    return x;
>  }
>
> +/* Implementation of -fasm-show-source.
> +   Print a comment into the asm showing FILENAME, LINENUM, and the
> +   corresponding source line, if available.  */
> +
> +static void
> +asm_show_source (const char *filename, int linenum)
> +{
> +  if (!filename)
> +    return;
> +
> +  int line_size;
> +  const char *line = location_get_source_line (filename, linenum, &line_size);
> +  if (!line)
> +    return;
> +
> +  fprintf (asm_out_file, "%s %s:%i: ", ASM_COMMENT_START, filename, linenum);
> +  /* "line" is not 0-terminated, so we must use line_size.  */
> +  fwrite (line, 1, line_size, asm_out_file);
> +  fputc ('\n', asm_out_file);
> +}
> +
>  /* The final scan for one insn, INSN.
>     Args are same as in `final', except that INSN
>     is the insn being scanned.
> @@ -2563,8 +2584,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
>            note in a row.  */
>         if (!DECL_IGNORED_P (current_function_decl)
>             && notice_source_line (insn, &is_stmt))
> -         (*debug_hooks->source_line) (last_linenum, last_filename,
> -                                      last_discriminator, is_stmt);
> +         {
> +           if (flag_asm_show_source)
> +             asm_show_source (last_filename, last_linenum);
> +           (*debug_hooks->source_line) (last_linenum, last_filename,
> +                                        last_discriminator, is_stmt);
> +         }
>
>         if (GET_CODE (body) == PARALLEL
>             && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
> diff --git a/gcc/testsuite/gcc.dg/fasm-show-source-1.c b/gcc/testsuite/gcc.dg/fasm-show-source-1.c
> new file mode 100644
> index 0000000..3dd49e0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/fasm-show-source-1.c
> @@ -0,0 +1,15 @@
> +/* Ensure that the generated asm contains FIXME  */
> +/* { dg-options "-fasm-show-source" } */
> +
> +int test (int n)
> +{
> +  int i;
> +  int total = 0;
> +
> +  for (i = 0; i < n; i++)
> +    total += i * i;
> +
> +  return total;
> +}
> +
> +/* { dg-final { scan-assembler "total = 0" } } */
> --
> 1.8.5.3
>
1              		.file	"foo.c"
   2              		.text
   3              	.Ltext0:
   4              		.section	.text.unlikely,"ax",@progbits
   5              	.LCOLDB0:
   6              		.text
   7              	.LHOTB0:
   8              		.section	.text.unlikely
   9              	.Ltext_cold0:
  10              		.text
  11              		.globl	f
  13              	f:
  14              	.LFB0:
  15              		.file 1 "foo.c"
   1:foo.c         **** int f(int n)
   2:foo.c         **** {
  16              		.loc 1 2 0
  17              		.cfi_startproc
  18              	.LVL0:
  19              	.LBB2:
   3:foo.c         ****   int total = 0;
   4:foo.c         ****   for (int i = 0; i < n; i++)
  20              		.loc 1 4 0
  21 0000 31D2     		xorl	%edx, %edx
  22              	.LBE2:
   3:foo.c         ****   int total = 0;
  23              		.loc 1 3 0
  24 0002 31C0     		xorl	%eax, %eax
  25              	.LVL1:
  26              	.L2:
  27              	.LBB3:
  28              		.loc 1 4 0 discriminator 1
  29 0004 39FA     		cmpl	%edi, %edx
  30 0006 7D0B     		jge	.L5
   5:foo.c         ****     total += i * i;
  31              		.loc 1 5 0 discriminator 3
  32 0008 89D1     		movl	%edx, %ecx
  33 000a 0FAFCA   		imull	%edx, %ecx
   4:foo.c         ****   return total;
  34              		.loc 1 4 0 discriminator 3
  35 000d FFC2     		incl	%edx
  36              	.LVL2:
  37              		.loc 1 5 0 discriminator 3
  38 000f 01C8     		addl	%ecx, %eax
  39              	.LVL3:
  40 0011 EBF1     		jmp	.L2
  41              	.L5:
  42              	.LBE3:
   6:foo.c         ****   return total;
   7:foo.c         **** }
  43              		.loc 1 7 0
  44 0013 C3       		ret
  45              		.cfi_endproc
  46              	.LFE0:
  48              		.section	.text.unlikely
  49              	.LCOLDE0:
  50              		.text
  51              	.LHOTE0:
  52              	.Letext0:
  53              		.section	.text.unlikely
  54              	.Letext_cold0:
David Malcolm Aug. 12, 2016, 6:55 p.m. UTC | #3
On Fri, 2016-08-12 at 11:00 +0530, Prathamesh Kulkarni wrote:
> On 12 August 2016 at 02:04, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > I sometimes find myself scouring assembler output from the compiler
> > and trying to figure out which instructions correspond to which
> > lines of source code; I believe this is a common activity for some
> > end-users.
> Hi David,
> I usually use gcc -g -Wa,-adhln to trace C source from the assembly.

If I'm reading that right, you're using the GNU assembler to emit a
listing file ("-a"), parsing the debuginfo with:
  "d": omit debugging directives
  "h": include high-level source
  "l": include assembly
  "n": omit forms processing

> I tried your example and it gave more or less a similar output
> (attached).

Thanks.

> However the source mapping with your patch looks better.

One specific goal of the patch is that the source information is in a
format that can be parsed by Emacs, and it can jump to the
corresponding location in the source file.

The do-it-in-gcc approach also doesn't rely on any smarts in the
assembler.

As Sandra noted, we already have -fverbose-asm, so I've posted an
updated patch to add the source-printing to that option, rather than as
a standalone option.

Dave

> Thanks,
> Prathamesh
> > 
> > The following patch adds a new -fasm-show-source option, which
> > emits comments into the generated asm showing the pertinent
> > line of source code, whenever it changes.  It uses the same logic
> > as debug_hooks->source_line for tracking this (for handling
> > line-based breakpoints).
> > 
> > An example can be seen in the invoke.texi part of the patch.  As
> > noted there, it's aimed at end-users, rather than gcc developers.
> > The example shows a relatively short function; the option is
> > likely to be much more useful for longer functions.
> > 
> > I think it would further improve usability if this option were
> > enabled
> > by default when the final output is .s (either via -S, or by "-o
> > foo.s").
> > Ideas on how to implement that (in the driver) would be welcome - I
> > started looking at the spec-handling code, but thought I'd post the
> > idea here first, before diving in too deeply.
> > 
> > Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu; adds
> > 2 PASS results to gcc.sum.
> > 
> > Thoughts?  OK for trunk as-is?
> > 
> > gcc/ChangeLog:
> >         * common.opt (fasm-show-source): New option.
> >         * doc/invoke.texi (Code Generation Options): Add
> >         -fasm-show-source.
> >         (-fasm-show-source): New item.
> >         * final.c (asm_show_source): New function.
> >         (final_scan_insn): Call asm_show_source.
> > 
> > gcc/testsuite/ChangeLog:
> >         * gcc.dg/fasm-show-source-1.c: New test case.
> > ---
> >  gcc/common.opt                            |  5 +++
> >  gcc/doc/invoke.texi                       | 71
> > ++++++++++++++++++++++++++++++-
> >  gcc/final.c                               | 29 ++++++++++++-
> >  gcc/testsuite/gcc.dg/fasm-show-source-1.c | 15 +++++++
> >  4 files changed, 117 insertions(+), 3 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.dg/fasm-show-source-1.c
> > 
> > diff --git a/gcc/common.opt b/gcc/common.opt
> > index 8a292ed..56ce513 100644
> > --- a/gcc/common.opt
> > +++ b/gcc/common.opt
> > @@ -939,6 +939,11 @@ fargument-noalias-anything
> >  Common Ignore
> >  Does nothing. Preserved for backward compatibility.
> > 
> > +fasm-show-source
> > +Common Var(flag_asm_show_source)
> > +Emit comments in the generated assembly code to show the source
> > code
> > +lines associated with the assembly instructions.
> > +
> >  fsanitize=
> >  Common Driver Report Joined
> >  Select what to sanitize.
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index 22001f9..dc3d3ad 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -486,7 +486,8 @@ Objective-C and Objective-C++ Dialects}.
> > 
> >  @item Code Generation Options
> >  @xref{Code Gen Options,,Options for Code Generation Conventions}.
> > -@gccoptlist{-fcall-saved-@var{reg}  -fcall-used-@var{reg} @gol
> > +@gccoptlist{-fasm-show-source @gol
> > +-fcall-saved-@var{reg}  -fcall-used-@var{reg} @gol
> >  -ffixed-@var{reg}  -fexceptions @gol
> >  -fnon-call-exceptions  -fdelete-dead-exceptions  -funwind-tables
> > @gol
> >  -fasynchronous-unwind-tables @gol
> > @@ -11153,6 +11154,74 @@ can figure out the other form by either
> > removing @samp{no-} or adding
> >  it.
> > 
> >  @table @gcctabopt
> > +@item -fasm-show-source
> > +@opindex fasm-show-source
> > +Emit comments in the generated assembly code to show the source
> > code
> > +lines associated with the assembly instructions.  This option is
> > +aimed at end-users who wish to better understand the relationship
> > +between their source code and the generated machine code.
> > +
> > +The comments are of the form FILENAME:LINENUMBER:CONTENT OF LINE.
> > +
> > +For example, given this C source file:
> > +
> > +@smallexample
> > +int test (int n)
> > +@{
> > +  int i;
> > +  int total = 0;
> > +
> > +  for (i = 0; i < n; i++)
> > +    total += i * i;
> > +
> > +  return total;
> > +@}
> > +@end smallexample
> > +
> > +compiling to (x86_64) assembly via @option{-S} and emitting the
> > result
> > +direct to stdout via @option{-o} @option{-}
> > +
> > +@smallexample
> > +gcc -S test.c -fasm-show-source -Os -o -
> > +@end smallexample
> > +
> > +gives output similar to this, highlighting which instructions
> > correspond
> > +to the various parts of the loop:
> > +
> > +@smallexample
> > +       .file   "test.c"
> > +       .text
> > +       .globl  test
> > +       .type   test, @@function
> > +test:
> > +.LFB0:
> > +       .cfi_startproc
> > +# test.c:4:   int total = 0;
> > +       xorl    %eax, %eax
> > +# test.c:6:   for (i = 0; i < n; i++)
> > +       xorl    %edx, %edx
> > +.L2:
> > +# test.c:6:   for (i = 0; i < n; i++)
> > +       cmpl    %edi, %edx
> > +       jge     .L5
> > +# test.c:7:     total += i * i;
> > +       movl    %edx, %ecx
> > +       imull   %edx, %ecx
> > +# test.c:6:   for (i = 0; i < n; i++)
> > +       incl    %edx
> > +# test.c:7:     total += i * i;
> > +       addl    %ecx, %eax
> > +       jmp     .L2
> > +.L5:
> > +# test.c:10: @}
> > +       ret
> > +       .cfi_endproc
> > +.LFE0:
> > +       .size   test, .-test
> > +       .ident  "GCC: (GNU) 7.0.0 20160809 (experimental)"
> > +       .section        .note.GNU-stack,"",@@progbits
> > +@end smallexample
> > +
> >  @item -fstack-reuse=@var{reuse-level}
> >  @opindex fstack_reuse
> >  This option controls stack space reuse for user declared
> > local/auto variables
> > diff --git a/gcc/final.c b/gcc/final.c
> > index 5b04311..09bf0b7 100644
> > --- a/gcc/final.c
> > +++ b/gcc/final.c
> > @@ -2140,6 +2140,27 @@ call_from_call_insn (rtx_call_insn *insn)
> >    return x;
> >  }
> > 
> > +/* Implementation of -fasm-show-source.
> > +   Print a comment into the asm showing FILENAME, LINENUM, and the
> > +   corresponding source line, if available.  */
> > +
> > +static void
> > +asm_show_source (const char *filename, int linenum)
> > +{
> > +  if (!filename)
> > +    return;
> > +
> > +  int line_size;
> > +  const char *line = location_get_source_line (filename, linenum,
> > &line_size);
> > +  if (!line)
> > +    return;
> > +
> > +  fprintf (asm_out_file, "%s %s:%i: ", ASM_COMMENT_START,
> > filename, linenum);
> > +  /* "line" is not 0-terminated, so we must use line_size.  */
> > +  fwrite (line, 1, line_size, asm_out_file);
> > +  fputc ('\n', asm_out_file);
> > +}
> > +
> >  /* The final scan for one insn, INSN.
> >     Args are same as in `final', except that INSN
> >     is the insn being scanned.
> > @@ -2563,8 +2584,12 @@ final_scan_insn (rtx_insn *insn, FILE *file,
> > int optimize_p ATTRIBUTE_UNUSED,
> >            note in a row.  */
> >         if (!DECL_IGNORED_P (current_function_decl)
> >             && notice_source_line (insn, &is_stmt))
> > -         (*debug_hooks->source_line) (last_linenum, last_filename,
> > -                                      last_discriminator,
> > is_stmt);
> > +         {
> > +           if (flag_asm_show_source)
> > +             asm_show_source (last_filename, last_linenum);
> > +           (*debug_hooks->source_line) (last_linenum,
> > last_filename,
> > +                                        last_discriminator,
> > is_stmt);
> > +         }
> > 
> >         if (GET_CODE (body) == PARALLEL
> >             && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
> > diff --git a/gcc/testsuite/gcc.dg/fasm-show-source-1.c
> > b/gcc/testsuite/gcc.dg/fasm-show-source-1.c
> > new file mode 100644
> > index 0000000..3dd49e0
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/fasm-show-source-1.c
> > @@ -0,0 +1,15 @@
> > +/* Ensure that the generated asm contains FIXME  */
> > +/* { dg-options "-fasm-show-source" } */
> > +
> > +int test (int n)
> > +{
> > +  int i;
> > +  int total = 0;
> > +
> > +  for (i = 0; i < n; i++)
> > +    total += i * i;
> > +
> > +  return total;
> > +}
> > +
> > +/* { dg-final { scan-assembler "total = 0" } } */
> > --
> > 1.8.5.3
> >
diff mbox

Patch

diff --git a/gcc/common.opt b/gcc/common.opt
index 8a292ed..56ce513 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -939,6 +939,11 @@  fargument-noalias-anything
 Common Ignore
 Does nothing. Preserved for backward compatibility.
 
+fasm-show-source
+Common Var(flag_asm_show_source)
+Emit comments in the generated assembly code to show the source code
+lines associated with the assembly instructions.
+
 fsanitize=
 Common Driver Report Joined
 Select what to sanitize.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 22001f9..dc3d3ad 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -486,7 +486,8 @@  Objective-C and Objective-C++ Dialects}.
 
 @item Code Generation Options
 @xref{Code Gen Options,,Options for Code Generation Conventions}.
-@gccoptlist{-fcall-saved-@var{reg}  -fcall-used-@var{reg} @gol
+@gccoptlist{-fasm-show-source @gol
+-fcall-saved-@var{reg}  -fcall-used-@var{reg} @gol
 -ffixed-@var{reg}  -fexceptions @gol
 -fnon-call-exceptions  -fdelete-dead-exceptions  -funwind-tables @gol
 -fasynchronous-unwind-tables @gol
@@ -11153,6 +11154,74 @@  can figure out the other form by either removing @samp{no-} or adding
 it.
 
 @table @gcctabopt
+@item -fasm-show-source
+@opindex fasm-show-source
+Emit comments in the generated assembly code to show the source code
+lines associated with the assembly instructions.  This option is
+aimed at end-users who wish to better understand the relationship
+between their source code and the generated machine code.
+
+The comments are of the form FILENAME:LINENUMBER:CONTENT OF LINE.
+
+For example, given this C source file:
+
+@smallexample
+int test (int n)
+@{
+  int i;
+  int total = 0;
+
+  for (i = 0; i < n; i++)
+    total += i * i;
+
+  return total;
+@}
+@end smallexample
+
+compiling to (x86_64) assembly via @option{-S} and emitting the result
+direct to stdout via @option{-o} @option{-}
+
+@smallexample
+gcc -S test.c -fasm-show-source -Os -o -
+@end smallexample
+
+gives output similar to this, highlighting which instructions correspond
+to the various parts of the loop:
+
+@smallexample
+	.file	"test.c"
+	.text
+	.globl	test
+	.type	test, @@function
+test:
+.LFB0:
+	.cfi_startproc
+# test.c:4:   int total = 0;
+	xorl	%eax, %eax
+# test.c:6:   for (i = 0; i < n; i++)
+	xorl	%edx, %edx
+.L2:
+# test.c:6:   for (i = 0; i < n; i++)
+	cmpl	%edi, %edx
+	jge	.L5
+# test.c:7:     total += i * i;
+	movl	%edx, %ecx
+	imull	%edx, %ecx
+# test.c:6:   for (i = 0; i < n; i++)
+	incl	%edx
+# test.c:7:     total += i * i;
+	addl	%ecx, %eax
+	jmp	.L2
+.L5:
+# test.c:10: @}
+	ret
+	.cfi_endproc
+.LFE0:
+	.size	test, .-test
+	.ident	"GCC: (GNU) 7.0.0 20160809 (experimental)"
+	.section	.note.GNU-stack,"",@@progbits
+@end smallexample
+
 @item -fstack-reuse=@var{reuse-level}
 @opindex fstack_reuse
 This option controls stack space reuse for user declared local/auto variables
diff --git a/gcc/final.c b/gcc/final.c
index 5b04311..09bf0b7 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -2140,6 +2140,27 @@  call_from_call_insn (rtx_call_insn *insn)
   return x;
 }
 
+/* Implementation of -fasm-show-source.
+   Print a comment into the asm showing FILENAME, LINENUM, and the
+   corresponding source line, if available.  */
+
+static void
+asm_show_source (const char *filename, int linenum)
+{
+  if (!filename)
+    return;
+
+  int line_size;
+  const char *line = location_get_source_line (filename, linenum, &line_size);
+  if (!line)
+    return;
+
+  fprintf (asm_out_file, "%s %s:%i: ", ASM_COMMENT_START, filename, linenum);
+  /* "line" is not 0-terminated, so we must use line_size.  */
+  fwrite (line, 1, line_size, asm_out_file);
+  fputc ('\n', asm_out_file);
+}
+
 /* The final scan for one insn, INSN.
    Args are same as in `final', except that INSN
    is the insn being scanned.
@@ -2563,8 +2584,12 @@  final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	   note in a row.  */
 	if (!DECL_IGNORED_P (current_function_decl)
 	    && notice_source_line (insn, &is_stmt))
-	  (*debug_hooks->source_line) (last_linenum, last_filename,
-				       last_discriminator, is_stmt);
+	  {
+	    if (flag_asm_show_source)
+	      asm_show_source (last_filename, last_linenum);
+	    (*debug_hooks->source_line) (last_linenum, last_filename,
+					 last_discriminator, is_stmt);
+	  }
 
 	if (GET_CODE (body) == PARALLEL
 	    && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
diff --git a/gcc/testsuite/gcc.dg/fasm-show-source-1.c b/gcc/testsuite/gcc.dg/fasm-show-source-1.c
new file mode 100644
index 0000000..3dd49e0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fasm-show-source-1.c
@@ -0,0 +1,15 @@ 
+/* Ensure that the generated asm contains FIXME  */
+/* { dg-options "-fasm-show-source" } */
+
+int test (int n)
+{
+  int i;
+  int total = 0;
+
+  for (i = 0; i < n; i++)
+    total += i * i;
+
+  return total;
+}
+
+/* { dg-final { scan-assembler "total = 0" } } */