[llvm-branch-commits] [llvm-mc] Add --show-source-loc option to emit source locations (PR #199298)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri May 22 16:20:36 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-mc

Author: Alexander Richardson (arichardson)

<details>
<summary>Changes</summary>

This adds a new --show-source-loc flag (and -asm-show-source-loc
MCTargetOption) to llvm-mc, which emits source location comments
(`# <SourceLoc: filename:line:col>`).
When instructions originate from macro expansions, llvm-mc unwinds the
instantiation stack, emitting intermediate expansion layers as
`# <MacroLoc: filename:line:col>` and reporting the top-level
macro invocation in `SourceLoc`. For .include directives, it also emits
`# <IncludeLoc: filename:line:col>` to report the include stack.

The main motivation for this feature is improving
update_mc_test_checks.py to cleanly map output instructions back to
input lines, enabling automated test updates for assembly files that
include directives like .ifdef or macros.

Assisted-By: Gemini


---
Full diff: https://github.com/llvm/llvm-project/pull/199298.diff


12 Files Affected:

- (modified) llvm/include/llvm/MC/MCTargetOptions.h (+1) 
- (modified) llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h (+1) 
- (modified) llvm/include/llvm/Support/SourceMgr.h (+1-1) 
- (modified) llvm/lib/MC/MCAsmStreamer.cpp (+38) 
- (modified) llvm/lib/MC/MCTargetOptions.cpp (+3-3) 
- (modified) llvm/lib/MC/MCTargetOptionsCommandFlags.cpp (+7) 
- (modified) llvm/lib/Support/SourceMgr.cpp (+1-1) 
- (added) llvm/test/tools/llvm-mc/Inputs/show-source-loc.inc (+5) 
- (added) llvm/test/tools/llvm-mc/disassemble-show-source-loc.s (+9) 
- (added) llvm/test/tools/llvm-mc/show-source-loc.s (+52) 
- (modified) llvm/tools/llvm-mc/Disassembler.cpp (+1) 
- (modified) llvm/tools/llvm-mc/llvm-mc.cpp (+6) 


``````````diff
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index 2f24608b5f6ba..52ae464a8b91d 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -52,6 +52,7 @@ class MCTargetOptions {
   bool FDPIC : 1;
   bool ShowMCEncoding : 1;
   bool ShowMCInst : 1;
+  bool ShowMCInstSourceLoc : 1;
   bool AsmVerbose : 1;
 
   /// Preserve Comments in Assembly.
diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
index ae80887900349..b9ddeeec4f537 100644
--- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
+++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
@@ -45,6 +45,7 @@ LLVM_ABI bool getEmitCompactUnwindNonCanonical();
 LLVM_ABI bool getEmitSFrameUnwind();
 
 LLVM_ABI bool getShowMCInst();
+LLVM_ABI bool getShowMCInstSourceLoc();
 
 LLVM_ABI bool getFatalWarnings();
 
diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index 83cb3de26453a..6157213c4b870 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -263,7 +263,7 @@ class SourceMgr {
   /// Given a line and column number in a mapped buffer, turn it into an SMLoc.
   /// This will return a null SMLoc if the line/column location is invalid.
   LLVM_ABI SMLoc FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,
-                                         unsigned ColNo);
+                                         unsigned ColNo) const;
 
   /// Emit a message about the specified location with the specified string.
   ///
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 05e3dc28a502b..c279dab35d0a5 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -37,6 +37,7 @@
 #include "llvm/Support/LEB128.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
 #include <algorithm>
 #include <optional>
 
@@ -60,6 +61,7 @@ class MCAsmStreamer final : public MCAsmBaseStreamer {
 
   bool IsVerboseAsm = false;
   bool ShowInst = false;
+  bool ShowInstSourceLoc = false;
   bool UseDwarfDirectory = false;
 
   void EmitRegisterName(int64_t Register);
@@ -107,6 +109,7 @@ class MCAsmStreamer final : public MCAsmBaseStreamer {
     if (IsVerboseAsm)
       InstPrinter->setCommentStream(CommentStream);
     ShowInst = TO.ShowMCInst;
+    ShowInstSourceLoc = TO.ShowMCInstSourceLoc;
     switch (TO.MCUseDwarfDirectory) {
     case MCTargetOptions::DisableDwarfDirectory:
       UseDwarfDirectory = false;
@@ -2624,6 +2627,41 @@ void MCAsmStreamer::emitInstruction(const MCInst &Inst,
     getCommentOS() << "\n";
 
   EmitEOL();
+
+  if (ShowInstSourceLoc && Inst.getLoc().isValid()) {
+    if (const SourceMgr *SM = getContext().getSourceManager()) {
+      SMLoc Loc = Inst.getLoc();
+      unsigned BufID = SM->FindBufferContainingLoc(Loc);
+      bool PrintedSourceLoc = false;
+
+      auto PrintLoc = [&](StringRef Type, SMLoc L, unsigned Buf) {
+        StringRef Filename = SM->getMemoryBuffer(Buf)->getBufferIdentifier();
+        std::pair<unsigned, unsigned> LineCol = SM->getLineAndColumn(L, Buf);
+        OS << MAI->getCommentString() << " <" << Type << ": " << Filename
+           << ":" << LineCol.first << ":" << LineCol.second << ">\n";
+      };
+
+      // Unwind the macro expansion and inclusion stacks.
+      while (BufID) {
+        SMLoc ParentLoc = SM->getParentIncludeLoc(BufID);
+        if (SMLoc DefLoc = SM->getMacroDefLoc(BufID); DefLoc.isValid()) {
+          PrintLoc("MacroLoc", DefLoc, SM->FindBufferContainingLoc(DefLoc));
+        } else {
+          // First location is the SourceLoc, all others are include stack
+          if (!PrintedSourceLoc) {
+            PrintLoc("SourceLoc", Loc, BufID);
+            PrintedSourceLoc = true;
+          } else {
+            PrintLoc("IncludeLoc", Loc, BufID);
+          }
+        }
+        // Move up to the parent context (the macro call site or the include site)
+        // for the next iteration of the stack unwinding.
+        Loc = ParentLoc;
+        BufID = Loc.isValid() ? SM->FindBufferContainingLoc(Loc) : 0;
+      }
+    }
+  }
 }
 
 void MCAsmStreamer::emitPseudoProbe(uint64_t Guid, uint64_t Index,
diff --git a/llvm/lib/MC/MCTargetOptions.cpp b/llvm/lib/MC/MCTargetOptions.cpp
index be6d19d111620..daf7ccece36c7 100644
--- a/llvm/lib/MC/MCTargetOptions.cpp
+++ b/llvm/lib/MC/MCTargetOptions.cpp
@@ -15,9 +15,9 @@ MCTargetOptions::MCTargetOptions()
     : MCRelaxAll(false), MCNoExecStack(false), MCFatalWarnings(false),
       MCNoWarn(false), MCNoDeprecatedWarn(false), MCNoTypeCheck(false),
       MCSaveTempLabels(false), MCIncrementalLinkerCompatible(false),
-      FDPIC(false), ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false),
-      PreserveAsmComments(true), Dwarf64(false),
-      EmitDwarfUnwind(EmitDwarfUnwindType::Default),
+      FDPIC(false), ShowMCEncoding(false), ShowMCInst(false),
+      ShowMCInstSourceLoc(false), AsmVerbose(false), PreserveAsmComments(true),
+      Dwarf64(false), EmitDwarfUnwind(EmitDwarfUnwindType::Default),
       MCUseDwarfDirectory(DefaultDwarfDirectory),
       EmitCompactUnwindNonCanonical(false), EmitSFrameUnwind(false),
       PPCUseFullRegisterNames(false) {}
diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
index 359c1bceb25b1..a80af06837b06 100644
--- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
+++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
@@ -50,6 +50,7 @@ MCOPT(EmitDwarfUnwindType, EmitDwarfUnwind)
 MCOPT(bool, EmitCompactUnwindNonCanonical)
 MCOPT(bool, EmitSFrameUnwind)
 MCOPT(bool, ShowMCInst)
+MCOPT(bool, ShowMCInstSourceLoc)
 MCOPT(bool, FatalWarnings)
 MCOPT(bool, NoWarn)
 MCOPT(bool, NoDeprecatedWarn)
@@ -124,6 +125,11 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() {
       cl::desc("Emit internal instruction representation to assembly file"));
   MCBINDOPT(ShowMCInst);
 
+  static cl::opt<bool> ShowMCInstSourceLoc(
+      "asm-show-source-loc",
+      cl::desc("Emit source locations of instructions to assembly file"));
+  MCBINDOPT(ShowMCInstSourceLoc);
+
   static cl::opt<bool> FatalWarnings("fatal-warnings",
                                      cl::desc("Treat warnings as errors"));
   MCBINDOPT(FatalWarnings);
@@ -203,6 +209,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() {
   Options.Dwarf64 = getDwarf64();
   Options.DwarfVersion = getDwarfVersion();
   Options.ShowMCInst = getShowMCInst();
+  Options.ShowMCInstSourceLoc = getShowMCInstSourceLoc();
   Options.ABIName = getABIName();
   Options.MCFatalWarnings = getFatalWarnings();
   Options.MCNoWarn = getNoWarn();
diff --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp
index 62fce28486d4a..66cee9ac28f03 100644
--- a/llvm/lib/Support/SourceMgr.cpp
+++ b/llvm/lib/Support/SourceMgr.cpp
@@ -259,7 +259,7 @@ std::string SourceMgr::getFormattedLocationNoOffset(SMLoc Loc,
 /// Given a line and column number in a mapped buffer, turn it into an SMLoc.
 /// This will return a null SMLoc if the line/column location is invalid.
 SMLoc SourceMgr::FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,
-                                         unsigned ColNo) {
+                                         unsigned ColNo) const {
   auto &SB = getBufferInfo(BufferID);
   const char *Ptr = SB.getPointerForLineNumber(LineNo);
   if (!Ptr)
diff --git a/llvm/test/tools/llvm-mc/Inputs/show-source-loc.inc b/llvm/test/tools/llvm-mc/Inputs/show-source-loc.inc
new file mode 100644
index 0000000000000..58e7a9628156d
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/Inputs/show-source-loc.inc
@@ -0,0 +1,5 @@
+xorl %ecx, %ecx
+
+.macro inc_macro reg
+  incl \reg
+.endm
diff --git a/llvm/test/tools/llvm-mc/disassemble-show-source-loc.s b/llvm/test/tools/llvm-mc/disassemble-show-source-loc.s
new file mode 100644
index 0000000000000..31c9fc8a5bd59
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/disassemble-show-source-loc.s
@@ -0,0 +1,9 @@
+# RUN: llvm-mc -triple=x86_64 -disassemble -show-source-loc %s | FileCheck %s
+
+# CHECK: nop
+# CHECK-NEXT: # <SourceLoc: {{.*}}disassemble-show-source-loc.s:5:1>
+0x90
+
+# CHECK: xorl %ecx, %ecx
+# CHECK-NEXT: # <SourceLoc: {{.*}}disassemble-show-source-loc.s:9:1>
+0x31 0xc9
diff --git a/llvm/test/tools/llvm-mc/show-source-loc.s b/llvm/test/tools/llvm-mc/show-source-loc.s
new file mode 100644
index 0000000000000..1fe06f2b87ed6
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/show-source-loc.s
@@ -0,0 +1,52 @@
+# RUN: llvm-mc -triple=x86_64 -show-source-loc %s -I %S/Inputs
+# RUN: llvm-mc -triple=x86_64 -show-source-loc %s -I %S/Inputs | FileCheck %s
+
+## Check that -show-source-loc emits <SourceLoc: ...> comments after instructions.
+
+.macro inner_macro reg1, reg2
+  addl \reg1, \reg2
+  subl \reg2, \reg1
+.endm
+
+.macro outer_macro r1, r2
+  inner_macro \r1, \r2
+.endm
+
+## Standard instructions report their exact line number.
+nop
+# CHECK: nop
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-2]]:1>
+
+## Nested macro expansion reports the full expansion stack.
+outer_macro %eax, %ebx
+# CHECK: addl %eax, %ebx
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:6:1>
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:11:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-4]]:1>
+# CHECK: subl %ebx, %eax
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:6:1>
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:11:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-8]]:1>
+
+## .include reports the include file location and the .include directive location.
+.include "show-source-loc.inc"
+# CHECK: xorl %ecx, %ecx
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.inc:1:1>
+# CHECK-NEXT: # <IncludeLoc: {{.*}}show-source-loc.s:[[#@LINE-3]]:31>
+
+## Macro defined in an include file.
+inc_macro %edx
+# CHECK: incl %edx
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.inc:3:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-3]]:1>
+
+## Indefinite repeat block (.irp).
+.irp reg, %esi, %edi
+  incl \reg
+.endr
+# CHECK: incl %esi
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:44:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-5]]:1>
+# CHECK: incl %edi
+# CHECK-NEXT: # <MacroLoc: {{.*}}show-source-loc.s:44:1>
+# CHECK-NEXT: # <SourceLoc: {{.*}}show-source-loc.s:[[#@LINE-8]]:1>
diff --git a/llvm/tools/llvm-mc/Disassembler.cpp b/llvm/tools/llvm-mc/Disassembler.cpp
index 9a61f68b12d31..55ab78ddefe42 100644
--- a/llvm/tools/llvm-mc/Disassembler.cpp
+++ b/llvm/tools/llvm-mc/Disassembler.cpp
@@ -77,6 +77,7 @@ static bool printInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
       [[fallthrough]];
 
     case MCDisassembler::Success:
+      Inst.setLoc(SMLoc::getFromPointer(Bytes.second[Index]));
       Streamer.emitInstruction(Inst, STI);
       break;
     }
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 903f82e6855ba..afbd861b91b81 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -86,6 +86,11 @@ static cl::opt<bool>
     ShowInst("show-inst", cl::desc("Show internal instruction representation"),
              cl::cat(MCCategory));
 
+static cl::opt<bool>
+    ShowSourceLoc("show-source-loc",
+                  cl::desc("Show source location of instructions"),
+                  cl::cat(MCCategory));
+
 static cl::opt<bool>
     ShowInstOperands("show-inst-operands",
                      cl::desc("Show instructions operands as parsed"),
@@ -409,6 +414,7 @@ int main(int argc, char **argv) {
   MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
   MCOptions.CompressDebugSections = CompressDebugSections.getValue();
   MCOptions.ShowMCInst = ShowInst;
+  MCOptions.ShowMCInstSourceLoc = ShowSourceLoc;
   MCOptions.AsmVerbose = true;
   MCOptions.MCNoExecStack = NoExecStack;
   MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory;

``````````

</details>


https://github.com/llvm/llvm-project/pull/199298


More information about the llvm-branch-commits mailing list