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

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

Reply via email to